//Written by Zichqec https://zichqec.github.io/s-the-skeleton/index.html //If this all looks scary to you, no worries! All you need to do is set a few options in OnStartWordSearch, set up dialogue in WordSearchDialogue, and then add your own pool of words for it to choose from in WordSearchWords. If it gives you any trouble, let me know! //Use this to start a new word search game: "\![*]\q[Word Search,OnStartWordSearch]" OnStartWordSearch { _rightadjust = 0 //Don't touch these ones _highlightcolor = "" //---Options. Feel free to set these however you like.--- //_defaultballoon: Set this to the name of your balloon, as seen in the right click menu. This lets you adjust the color and positioning specifically to your balloon, without breaking it completely for other balloons! //_debug: Hides all letters that are not a part of words, so you can test and see how well your words are being distributed //_gridsize: The dimensions of your word search. I created this based on a 10x10 grid, but you can play around with it if you like. //_fontsize: Font size of the grid. Adjust to your liking. The bigger the better, this game can be hard on the eyes. //_maxwords: How many words it will attempt to add to the grid. Note: Sometimes adding a word fails, so you may end up with less words! //_attempts_to_place: How many times it will attempt to add a single word to the grid. If you put this higher you'll probably end up with the max amount of words in the puzzle more often, but it may impact performance. //_rightadjust: You can use this to center the word search in your balloon (this is in pixels). Since people can use whatever balloon they want, though, I put a check to check if they're in your default balloon. Make sure to put your balloon's name there. Note: Only works in YAYA, you might need a different setup using OnBalloonChange if you're using AYA. //_backwardsallowed: 1 if you want words to be able to appear backwards, 0 if you don't. //_highlightinverted: Words that are found are highlighted using your balloon's anchor color. If you would prefer for everything to be the anchor color, and for found words to be the color of menu choices, you can set that here. //_highlightcolor: Color you want for highlighting, as an R,G,B value. If you want the default color used by your balloon, put "default.anchor" instead //Note: If you want to change the anchor color that's used in the grid, you can do so by adding a \f[anchorcolor,(R),(G),(B)] tag in the part of the Word Search code that displays the grid. You can also use similar tags to change the color of \__q tags, I believe. Ukadoc will have more info. _defaultballoon = "Your Balloon's Name here" _debug = 0 _gridsize = 10 _fontsize = 16 _maxwords = 10 _attempts_to_place = 15 if SHIORI3FW.BalloonName == _defaultballoon; _rightadjust = 0 _backwardsallowed = 0 _highlightinverted = 1 if SHIORI3FW.BalloonName == _defaultballoon; _highlightcolor = "255,255,255" else; _highlightcolor = "default.anchor" //Don't touch these WSOpts = (_fontsize,_rightadjust,_highlightinverted,_highlightcolor) CreateWordSearch(_debug,_gridsize,_maxwords,_attempts_to_place,_backwardsallowed) WordsLeft = WordList OnWordSearch } //All your dialogue goes here. Don't add \e to the end of any of these. WordSearchDialogue { if _argv[0] == "Menu During Play" //Menu option at the bottom while the game is being played, such as a button to give up/quit { "\n\![*]\q[Give up,OnWordSearchQuit]\e" } elseif _argv[0] == "Invalid Word" //If the user puts in a word that isn't on the word list or was already guessed - _argv[1] is the word the user guessed { "%(_argv[1]) is not valid." } elseif _argv[0] == "Invalid Move" //If the user tried an illegal diagonal move { "You can't move like that.\w8\w8 Moves have to be straight lines;\w4 up,\w4 down,\w4 left,\w4 right,\w4 or diagonal." } elseif _argv[0] == "Found Word" //If the user found a word - _argv[1] is the word that was found { "You found the word %(_argv[1])." } elseif _argv[0] == "Finished Puzzle" //If the user completed the puzzle - _argv[1] is the last word the user found. Might be a good idea to add menu buttons here. { "%(_argv[1]) was the last word,\w4 good job!" -- "\_q\n\![*]\q[Play again,OnStartWordSearch] \![*]\q[Play something else,OnGamesMenu]\n\![*]\q[I'm done,cancelnodialogue]\e" ERASEVAR("WordSearch") ERASEVAR("WordList") ERASEVAR("WordsLeft") ERASEVAR("SearchHighlight") ERASEVAR("WSOpts") } } //Words you want to be placed in the puzzle go here. Be mindful of how long your words are! Make sure they're not too long to fit the grid. Probably don't make them too short, either. I'd recommend at least 4 letters. And have plenty of words available, the more the better! This has to be an array, so if you're using my other games, you won't be able to share a word pool between them. (Unless you get clever and have those word pools read from here using something like ANY(WordSearchWords) WordSearchWords : array { "Example" "Test" "Many" "Words" "Hellyeah" "Dreams" "Hopes" "Monsters" "Humans" "Skeletons" "Elementals" "Lorem" "Ipsum" "Lulo" "Dusty" "Obsidian" "Nyctophobia" "Neophyte" } OnWordSearch { _highlightarray = SearchHighlight _endRow = "" _endCol = "" _startRow = "" _startCol = "" _RowDist = "" _ColDist = "" //Sets up some variables for the X and Y values, and also sets up variables to check that the user doesn't make an illegal diagonal move if reference0 == "StartLetter" { _startRow = TOINT(reference1) _startCol = TOINT(reference2) } elseif reference0 == "EndLetter" { _endRow = TOINT(reference1) _endCol = TOINT(reference2) _startRow = TOINT(reference3) _startCol = TOINT(reference4) //These bits change the numbers to not be negatives, so they can be compared properly _RowDist = _startRow - _endRow if _RowDist < 0; _RowDist = -_RowDist _ColDist = _startCol - _endCol if _ColDist < 0; _ColDist = -_ColDist } _valid = 0 _direction = "" _guessedword = "" _start = "" _end = "" //If the user attempted a guess if reference0 == "EndLetter" { if _startRow == _endRow //If this is a valid move (Horizontal) { _valid = 1 if _startCol > _endCol; {_direction = "Left"; _start = _endCol; _end = _startCol} else; {_direction = "Right"; _start = _startCol; _end = _endCol} for _i = _start; _i <= _end; _i++ { _guessedword += WordSearch[_startRow][_i] } if _direction == "Left" { _guessedword = WSReverse(_guessedword) } //Highlighting for _i = 0; _i < STRLEN(_guessedword); _i++ { _row = _highlightarray[_startRow] _row[_start + _i] = "1" _highlightarray[_startRow] = _row } } elseif _startCol == _endCol //Vertical { _valid = 1 if _startRow > _endRow; {_direction = "Up"; _start = _endRow; _end = _startRow} else; {_direction = "Down"; _start = _startRow; _end = _endRow} for _i = _start; _i <= _end; _i++ { _guessedword += WordSearch[_i][_startCol] } if _direction == "Up" { _guessedword = WSReverse(_guessedword) } //Highlighting for _i = 0; _i < STRLEN(_guessedword); _i++ { _row = _highlightarray[_start + _i] _row[_startCol] = "1" _highlightarray[_start + _i] = _row } } elseif _RowDist == _ColDist //Diagonal, if it's valid { _valid = 1 if _startCol > _endCol && _startRow > _endRow //Going left and up { _direction = "Left Up" _ii = _startCol for _i = _startRow; _i >= _endRow; _i-- { _guessedword += WordSearch[_i][_ii] //Highlighting _row = _highlightarray[_i] _row[_ii] = "1" _highlightarray[_i] = _row _ii-- } } elseif _startCol > _endCol && _startRow < _endRow //going left and down { _direction = "Left Down" _ii = _startCol for _i = _startRow; _i <= _endRow; _i++ { _guessedword += WordSearch[_i][_ii] //Highlighting _row = _highlightarray[_i] _row[_ii] = "1" _highlightarray[_i] = _row _ii-- } } elseif _startCol < _endCol && _startRow > _endRow //going right and up { _direction = "Right Up" _ii = _startRow for _i = _startCol; _i <= _endCol; _i++ { _guessedword += WordSearch[_ii][_i] //Highlighting _row = _highlightarray[_ii] _row[_i] = "1" _highlightarray[_ii] = _row _ii-- } } else //going right and down { _direction = "Right Down" _ii = _startCol for _i = _startRow; _i <= _endRow; _i++ { _guessedword += WordSearch[_i][_ii] //Highlighting _row = _highlightarray[_i] _row[_ii] = "1" _highlightarray[_i] = _row _ii++ } } } else //If it's an invalid move { _valid = 0 } } //If the word is in the list of words to find, mark it, and also remove the word from the list of words that still need to be found _find = ASEARCH(_guessedword,WordsLeft) if _find != -1 { _valid = 2 WordsLeft[_find] = IARRAY } if _valid == 2; SearchHighlight = _highlightarray else; _highlightarray = SearchHighlight //Set up the display of the grid _fheight = 10 if WSOpts[0] > 0; _fheight = WSOpts[0] _rightadjust = 0 if WSOpts[1] > 0; _rightadjust = WSOpts[1] _inverthighlight = 0 if WSOpts[2] == 1; _inverthighlight = WSOpts[2] _display = "\f[anchorfontcolor,%(WSOpts[3])]\f[height,%(_fheight)]\f[bold,1]" if reference0 == "Win"; _display += "\f[anchorstyle,none]\f[cursorstyle,none]" for _i = 0; _i < ARRAYSIZE(WordSearch); _i++ { _display += "\_l[%(_rightadjust)]" _row = WordSearch[_i] for _ii = 0; _ii < ARRAYSIZE(_row); _ii++ { _col = _row[_ii] if reference0 == "Win" //If the user already won, don't display with clickable buttons { _tag1 = "" _tag2 = "" if _highlightarray[_i][_ii] == "1"; { if _inverthighlight == 1 { _tag1 = "\__q[OnBlank]" _tag2 = "\__q" } else { _tag1 = "\_a[OnBlank]" _tag2 = "\_a" } } elseif _inverthighlight == 1 //if this is a random letter but inverted highlighting is on { _tag1 = "\_a[OnBlank]" _tag2 = "\_a" } _display += "%(_tag1)%(_col)%(_tag2) " } else { //IF the user has selected a letter, give it a unique link and highlight it if reference0 == "StartLetter" && _i == _startRow && _ii == _startCol { _tag = "\_a"; if _inverthighlight == 1; _tag = "\__q" _display += "%(_tag)[OnWordSearch,CancelStart,%(_i),%(_ii),%(_startRow),%(_startCol)]%(_col)%(_tag) " } else //Normal display with clickable buttons { _ref = "" if reference0 == "StartLetter"; _ref = "EndLetter" else; _ref = "StartLetter" _tag = "" if _inverthighlight == 1 { _tag = "\_a" if _highlightarray[_i][_ii] == "1"; _tag = "\__q" } else { _tag = "\__q" if _highlightarray[_i][_ii] == "1"; _tag = "\_a" } _display += "%(_tag)[OnWordSearch,%(_ref),%(_i),%(_ii),%(_startRow),%(_startCol)]%(_col)%(_tag) " } } } _display += "\n" } //Display word list _display += "\n[half]\f[height,default]\f[cursorstyle,default]" foreach WordList; _word { _exist = ASEARCH(_word,WordsLeft) if _exist == -1; _display += "\f[strike,1]" //Strike it out if it's been found already _display += "%(_word)" if _exist == -1; _display += "\f[strike,0]" _display += " " } if ARRAYSIZE(WordsLeft) == 0 && reference0 != "Win"; "\![raise,OnWordSearch,Win,%(_guessedword)]\e" //If the user won, restart this function so that it can remake the board -- //Dialogues for when you've made a turn. I ended up making a separate function for this because wow this function got long if reference0 == "EndLetter" { _display += "\n\_q\f[default]" if _valid == 2 //If the user found a word { _display += "%(WordSearchDialogue('Found Word',_guessedword))" } elseif _valid == 1 //If the user found a word, but it's not in the word list or has already been guessed { _display += "%(WordSearchDialogue('Invalid Word',_guessedword))" } else //If the user made an invalid move { _display += "%(WordSearchDialogue('Invalid Move'))" } } elseif reference0 == "Win" //If the user won { _display += "\n\_q\f[default]%(WordSearchDialogue('Finished Puzzle',reference1))" } if reference0 != "Win"; _display += "\n\f[default]%(WordSearchDialogue('Menu During Play'))" "\b2\f[name,Courier New]\![set,autoscroll,disable]\_q%(_display)\*\e" //Actual display } WSReverse //Reverses the string it's given, for the purposes of placing some words backwards { _output = "" for _i = 0; _i < STRLEN(_argv[0]); _i++ { _output = SUBSTR(_argv[0],_i,1) + _output } _output } CreateWordSearch //:deargodhelpme: { _dimensions = 10 //Width and height of the grid if _argv[1] > 0; _dimensions = _argv[1] _totalwords = 10 //How many words to attempt to add, total (each word will be tried multiple times if it does not fit) if _argv[2] > 0; _totalwords = _argv[2] _wordtries = 15 //How many times it will attempt to place a word before giving up if _argv[3] > 0; _wordtries = _argv[3] _allowreverse = 1 if _argv[4] == 0; _allowreverse = 0 WordList = IARRAY //Create a grid of .s WordSearch = IARRAY //Setting up the base grid, and the array for highlighting words SearchHighlight = IARRAY for _i = 0; _i < _dimensions; _i++ //Rows { _highlight = "" _columns = "" for _ii = 0; _ii < _dimensions; _ii++ //Columns { if _ii != 0; {_columns += ","; _highlight += ","} _columns += "." _highlight += "0" } WordSearch ,= _columns SearchHighlight ,= _highlight } //Get words and add them to the grid _availwords = WordSearchWords _toadd = "" _orig = "" _placed = 0 for _i = 0; _i < _totalwords; _i++ { //Check to make sure there's a word to add. If there is, pick a random one, then erase it from the array. If the word is too long, skip it and start again. if ARRAYSIZE(_availwords) == 0; {LOGGING("Ran out of words to add");break} _toadd = TOUPPER(ANY(_availwords)) LOGGING("Entered loop 1 - Start new word (%(_toadd))") _availwords[LSO] = IARRAY if STRLEN(_toadd) > _dimensions; {LOGGING("%(_toadd) too long for current grid size");continue} //This loop attempts to place the word several times, depending on how you have it set _placed = 0 _orig = _toadd for _ii = 0; _ii < _wordtries && _placed == 0; _ii++ { //Sets an orientation, decides if it should be reversed _orient = ANY("Horizontal,Vertical,Diagonal \,Diagonal /") if _allowreverse == 1 && RAND(2) == 1 { _toadd = WSReverse(_toadd) } _len = STRLEN(_toadd) _x = RAND(_dimensions) _y = RAND(_dimensions) LOGGING("Entered loop 2 - Try to find a place for new word (%(_x),%(_y) orient: %(_orient), len: %(_len)") //Each of these attempts to place it based on the orientation if _orient == "Horizontal" //---Left to Right--- { if (_x + _len) > _dimensions //If it's too long { LOGGING("Couldn't place %(_toadd), X: %(_x), orient: %(_orient), len: %(_len), tries so far: %(_ii)") continue } else //If it has enough space { _skip = 0 _rowtochange = WordSearch[_y] for _iii = 0; _iii < STRLEN(_toadd); _iii++ //Check to see if any other words are in the way { LOGGING("Entered loop 3 - Attempt to add new word, see if other words block it") if _rowtochange[_x + _iii] == "." || _rowtochange[_x + _iii] == SUBSTR(_toadd,_iii,1) //If it's an empty space or a space that matches the current letter { _rowtochange[_x + _iii] = SUBSTR(_toadd,_iii,1) } else //If it's a taken space { _skip = 1 LOGGING("Can't place %(_toadd), %(_rowtochange[_x + _iii]) in the way.") break } } if _skip == 1 //If it got blocked, skip and try placing in another place { _skip = 0 continue } else //If it wasn't blocked, go ahead and add it { WordSearch[_y] = _rowtochange _placed = 1 } } } elseif _orient == "Vertical" //---Top to Bottom--- { if (_y + _len) > _dimensions //If it's too long { LOGGING("Couldn't place %(_toadd), Y: %(_y), orient: %(_orient), len: %(_len), tries so far: %(_ii)") continue } else //If it has enough space { _skip = 0 //Make a temp array of this column _coltochange = IARRAY for _iii = 0; _iii < ARRAYSIZE(WordSearch[_x]); _iii++ { _coltochange ,= WordSearch[_iii][_x] } for _iii = 0; _iii < STRLEN(_toadd); _iii++ //Check to see if any other words are in the way { LOGGING("Entered loop 3 - Attempt to add new word, see if other words block it") if _coltochange[_y + _iii] == "." || _coltochange[_y + _iii] == SUBSTR(_toadd,_iii,1) //If it's an empty space or a space that matches the current letter { LOGGING("placed %(SUBSTR(_toadd,_iii,1))") _coltochange[_y + _iii] = SUBSTR(_toadd,_iii,1) } else //If it's a taken space { _skip = 1 LOGGING("Can't place %(_toadd), %(_coltochange[_y + _iii]) in the way.") break } } if _skip == 1 //If it got blocked, skip and try placing in another place { _skip = 0 continue } else //If it wasn't blocked, go ahead and add it { //_x should be the column that needs changed... have to extract it out of every row though and then put it back. for _iii = 0; _iii < ARRAYSIZE(_coltochange); _iii++ { _row = WordSearch[_iii] _row[_x] = _coltochange[_iii] WordSearch[_iii] = _row } //WordSearch[_x] = _coltochange _placed = 1 } } } elseif _orient == "Diagonal \" //Diagonal top left to bottom right { if (_y + _len) > _dimensions || (_x + _len) > _dimensions //If it's too long { LOGGING("Couldn't place %(_toadd), Y: %(_y), orient: %(_orient), len: %(_len), tries so far: %(_ii)") continue } else //If it has enough space { _skip = 0 //Make a temp array of this column _diagtochange = IARRAY for _iii = 0; _iii < _len; _iii++ { _diagtochange ,= WordSearch[_y + _iii][_x + _iii] } for _iii = 0; _iii < STRLEN(_toadd); _iii++ //Check to see if any other words are in the way { LOGGING("Entered loop 3 - Attempt to add new word, see if other words block it") if _diagtochange[_iii] == "." || _diagtochange[_iii] == SUBSTR(_toadd,_iii,1) //If it's an empty space or a space that matches the current letter { LOGGING("placed %(SUBSTR(_toadd,_iii,1))") _diagtochange[_iii] = SUBSTR(_toadd,_iii,1) } else //If it's a taken space { _skip = 1 LOGGING("Can't place %(_toadd), %(_diagtochange[_iii]) in the way.") break } } if _skip == 1 //If it got blocked, skip and try placing in another place { _skip = 0 continue } else //If it wasn't blocked, go ahead and add it { //_x should be the column that needs changed... have to extract it out of every row though and then put it back. for _iii = 0; _iii < ARRAYSIZE(_diagtochange); _iii++ { _row = WordSearch[_iii + _y] _row[_x + _iii] = _diagtochange[_iii] WordSearch[_iii + _y] = _row } _placed = 1 } } } elseif _orient == "Diagonal /" //diagonal bottom left to top right { if (_y - _len) < 0 || (_x + _len) > _dimensions //If it's too long { LOGGING("Couldn't place %(_toadd), Y: %(_y), orient: %(_orient), len: %(_len), tries so far: %(_ii)") continue } else //If it has enough space { _skip = 0 //Make a temp array of this column _diagtochange = IARRAY for _iii = 0; _iii < _len; _iii++ { LOGGING("Diagpath %(_iii): '%(WordSearch[_y - _iii][_x + _iii])'") _diagtochange ,= WordSearch[_y - _iii][_x + _iii] } for _iii = 0; _iii < STRLEN(_toadd); _iii++ //Check to see if any other words are in the way { LOGGING("Entered loop 3 - Attempt to add new word, see if other words block it") if _diagtochange[_iii] == "." || _diagtochange[_iii] == SUBSTR(_toadd,_iii,1) //If it's an empty space or a space that matches the current letter { LOGGING("placed %(SUBSTR(_toadd,_iii,1))") _diagtochange[_iii] = SUBSTR(_toadd,_iii,1) } else //If it's a taken space { _skip = 1 LOGGING("Can't place %(_toadd), %(_diagtochange[_iii]) in the way.") break } } if _skip == 1 //If it got blocked, skip and try placing in another place { _skip = 0 continue } else //If it wasn't blocked, go ahead and add it { //_x should be the column that needs changed... have to extract it out of every row though and then put it back. //_c = 0 LOGGING("To place: %(_diagtochange)") for _iii = 0; _iii < ARRAYSIZE(_diagtochange); _iii++ { _row = WordSearch[_y - _iii] _row[_x + _iii] = _diagtochange[_iii] WordSearch[_y - _iii] = _row //_c++ } //WordSearch[_x] = _diagtochange _placed = 1 } } } } if _placed == 1; WordList ,= _orig } //Fill empty spaces on the grid for _i = 0; _i < ARRAYSIZE(WordSearch); _i++ { _row = WordSearch[_i] for _ii = 0; _ii < ARRAYSIZE(_row); _ii++ { //Comment this out if you want just .s so you can see the words it placed if _row[_ii] == "." && _argv[0] != 1; _row[_ii] = ANY("A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z") } WordSearch[_i] = _row } }