# Vocabulary Mosaic -- (C)Copyright 2015 James Paige #----------------------------------------------------------------------- include, plotscr.hsd include, scancode.hsi #----------------------------------------------------------------------- define constant(2, current save version) global variable(1, save version) global variable(500, board) global variable(501, tile size) global variable(502, mouse cursor) global variable(503, left clicking) global variable(504, right clicking) global variable(505, carry) global variable(506, panning) global variable(507, tray) global variable(508, table) global variable(509, decollider) global variable(510, need recheck) global variable(511, play mode) global variable(512, tray set) global variable(513, turn button) global variable(514, total tiles placed) global variable(515, good tiles placed) global variable(516, bad tiles placed) global variable(517, flasher) global variable(518, modal) global variable(519, hider) global variable(520, score meters) global variable(521, points this turn) global variable(522, tray enabled) global variable(523, winning score) global variable(524, win mark passed) global variable(525, click anim) #Globals 600-603 used for player's score define constant(12, tiles per turn) define constant(300, default winning score) define constant(10, first box) define constant(18790, last box) define constant( 0,c:blue 1,c:green 2,c:red 3,c:yellow 4,c:brown 5,c:purple 6,c:cyan 7,c:grey 8,c:black 9,c:white 10,c:silver ) define constant( 0,str:debug 1,str:search 2,str:searchtemp 3,str:unfrozen 4,str:score 5,str:vic 6,str:rand ) #----------------------------------------------------------------------- # Init plotscript, prepare game, begin if(save slot used(1)) then( if(import globals(1, @save version) <> current save version) then( delete save(1) )else( load from slot(1) ) ) suspend player play song(0) prepare mouse prepare global stuff setup multiplayer main loop end script, prepare global stuff, begin winning score := default winning score tile size := 20 table := create table board := create board decollider := create decollider create trays turn button := create turn button create score meters mouse cursor := create mouse cursor create first word end script, prepare mouse, begin init mouse mouse region (-1, -1, -1, -1) # unrestricted mouse movement end script, show game board, begin set slice visible(table, true) set slice visible(turn button, true) end #----------------------------------------------------------------------- # Core script, main loop, begin while(true) do( update mouse update decollider update recheck update tray update turn button update modal handle input wait(1) ) end #----------------------------------------------------------------------- # Input handling script, left mouse down event, begin try to click turn button try to pick up a tile try to start panning try to advance modal end script, left mouse up event, begin drop a tile stop panning end script, right mouse down event, begin #create random letter(board) end script, right mouse up event, begin end script, handle input, begin if(mouse button(left button)) then( if(left clicking == false) then( left mouse down event ) left clicking := true )else( if(left clicking) then( left mouse up event ) left clicking := false ) if(mouse button(right button)) then( if(right clicking == false) then( right mouse down event ) right clicking := true )else( if(right clicking) then( right mouse up event ) right clicking := false ) if(keyval(key:ESC) >> 1 && not(modal)) then( modal := create quit confirmer ) end #----------------------------------------------------------------------- # Letters script, letter value, code, begin variable(v) switch(code) do( case(65) do(v:=1) #A case(66) do(v:=3) #B case(67) do(v:=3) #C case(68) do(v:=2) #D case(69) do(v:=1) #E case(70) do(v:=4) #F case(71) do(v:=2) #G case(72) do(v:=4) #H case(73) do(v:=1) #I case(74) do(v:=8) #J case(75) do(v:=5) #K case(76) do(v:=1) #L case(77) do(v:=3) #M case(78) do(v:=1) #N case(79) do(v:=1) #O case(80) do(v:=3) #P case(81) do(v:=10) #Q case(82) do(v:=1) #R case(83) do(v:=1) #S case(84) do(v:=1) #T case(85) do(v:=1) #U case(86) do(v:=4) #V case(87) do(v:=4) #W case(88) do(v:=8) #X case(89) do(v:=4) #Y case(90) do(v:=10) #Z ) exit returning(v) end script, create random letter, where, begin # Create a random letter with a distribution that matches what appears in the words file variable(n, letter) n := random(0, 9985) while(true) do( if(n >= 0 && n << 850) then(letter := 65, break) if(n >= 850 && n << 1048) then(letter := 66, break) if(n >= 1048 && n << 1451) then(letter := 67, break) if(n >= 1451 && n << 1798) then(letter := 68, break) if(n >= 1798 && n << 2923) then(letter := 69, break) if(n >= 2923 && n << 3049) then(letter := 70, break) if(n >= 3049 && n << 3318) then(letter := 71, break) if(n >= 3318 && n << 3571) then(letter := 72, break) if(n >= 3571 && n << 4437) then(letter := 73, break) if(n >= 4437 && n << 4460) then(letter := 74, break) if(n >= 4460 && n << 4562) then(letter := 75, break) if(n >= 4562 && n << 5116) then(letter := 76, break) if(n >= 5116 && n << 5406) then(letter := 77, break) if(n >= 5406 && n << 6115) then(letter := 78, break) if(n >= 6115 && n << 6746) then(letter := 79, break) if(n >= 6746 && n << 7016) then(letter := 80, break) if(n >= 7016 && n << 7033) then(letter := 81, break) if(n >= 7033 && n << 7764) then(letter := 82, break) if(n >= 7764 && n << 8585) then(letter := 83, break) if(n >= 8585 && n << 9232) then(letter := 84, break) if(n >= 9232 && n << 9559) then(letter := 85, break) if(n >= 9559 && n << 9660) then(letter := 86, break) if(n >= 9660 && n << 9742) then(letter := 87, break) if(n >= 9742 && n << 9768) then(letter := 88, break) if(n >= 9768 && n << 9939) then(letter := 89, break) if(n >= 9939 && n << 9986) then(letter := 90, break) n := 63 #? break ) exit returning(create letter(letter, where)) end script, create letter, ascii, where, begin variable(sl, txt, clip, spr, cn) sl := create rect(tile size, tile size, c:grey) set slice extra(sl, extra 0, ascii) set parent(sl, where) clip := create container(20, 20) set slice clipping(clip, true) set parent(clip, sl) center slice(clip) spr := load backdrop sprite(1) set parent(spr, clip) cn := ascii -- 65 set slice x(spr, (cn ,mod, 16) * -20) set slice y(spr, (cn / 16) * -25 -- 2) txt := create text set slice y(txt, 1) set outline(txt, true) $0="" append ascii(0, ascii) set slice text(txt, 0) set parent(txt, sl) center slice(txt) set slice visible(txt, false) if(where == board) then( set slice edge x(sl, edge:center, mouse board x) set slice edge y(sl, edge:center, mouse board y) align with grid(sl) ) if(parent slice(where) == tray set) then( set slice edge x(sl, edge:center, slice edge x(where, edge:center)) ) exit returning(sl) end script, align with grid, sl, begin variable(x, y, ox, oy) x := slice edge x(sl, edge:center) if(x << 0) then(ox := -1) set slice x(sl, (x / tile size + ox) * tile size) y := slice edge y(sl, edge:center) if(y << 0) then(oy := -1) set slice y(sl, (y / tile size + oy) * tile size) prevent stacking(sl) need recheck := true end script, prevent stacking, sl, begin variable(col) col := find colliding slice(board, sl, 0, false) if(col) then( put in decollider(sl) ) end script, try to pick up a tile, begin variable(tile) if(modal) then(exit script) if(carry) then(exit script) # can only carry one tile at a time if(slice collide(turn button, mouse cursor)) then( exit script ) if(slice collide(tray, mouse cursor)) then( tile := first child(tray) )else( tile := first child(board) ) while(tile) do( if(slice collide(tile, mouse cursor)) then( if(get frozen(tile) == false) then( pick up a tile(tile) exit script ) ) tile := next sibling(tile) ) end script, pick up a tile, tile, begin if(carry) then(drop a tile) carry := tile set parent to mouse(tile) set rect style(tile, c:grey) need recheck := true play sound(0) end script, drop a tile, begin if(carry == 0) then(exit script) if(slice collide(tray, carry)) then( set parent preserve pos(carry, tray) )else( set parent preserve pos(carry, board) align with grid(carry) ) carry := 0 play sound(1) save game end script, find leftmost tile, sl, begin variable(find, next) find := sl while(find) do( next := tile by offset(find, -1, 0) if(next == 0) then(break) find := next ) exit returning(find) end script, find upmost tile, sl, begin variable(find, next) find := sl while(find) do( next := tile by offset(find, 0, -1) if(next == 0) then(break) find := next ) exit returning(find) end script, tile by offset, tile, xoff, yoff, begin exit returning(slice at pos(board, slice edge x(tile, edge:center) + xoff * tile size, slice edge y(tile, edge:center) + yoff * tile size)) end #----------------------------------------------------------------------- # First Word script, create first word, begin variable(i, ch, len, tile) while(true) do( load random word(str:rand) len := string length(str:rand) if(len >= 3 && len <= 6) then( break ) ) #$str:rand="VOCABULARY" len := string length(str:rand) for(i, 0, len -- 1) do( ch := ascii from string(str:rand, i + 1) tile := create letter(ch, board) set slice x(tile, (i -- len / 2) * tile size) set slice y(tile, tile size / 2 * -1) align with grid(tile) set frozen(tile, true) set slice extra(tile, extra 2, c:black) ) evaluate all words end #----------------------------------------------------------------------- # Word tile searching script, update recheck, begin if(need recheck) then( #recheck all words # disabled because it is too slow for every click need recheck := false ) end script, recheck all words, begin variable(tile) reset all tiles tile := slice at pos(board, 0, 0) if(tile) then( check for words(tile) ) evaluate all words end script, reset all tiles, begin variable(tile) tile := first child(board) while(tile) do( # reset all tiles set horiz checked(tile, false) set vert checked(tile, false) set horiz found(tile, false) set vert found(tile, false) tile := next sibling(tile) ) end script, evaluate all words, begin variable(tile, style, h, v, good, bad, total) tile := first child(board) while(tile) do( style := c:grey h := get horiz found(tile) v := get vert found(tile) if(h && v) then( style := c:silver good += 1 )else( bad += 1 ) if(get frozen(tile)) then( style := get slice extra(tile, extra 2) )else( total += 1 ) set rect style(tile, style) tile := next sibling(tile) ) total tiles placed := total good tiles placed := good bad tiles placed := bad end script, check for words, sl, begin check for horiz word(sl) check for vert word(sl) end script, check for horiz word, sl, begin variable(start, code) if(get horiz checked(sl)) then(exit script) sl := find leftmost tile(sl) start := sl $1="" $3="" while(sl) do( code := get slice extra(sl, extra 0) append ascii(1, code) if(get frozen(sl) == false) then( append ascii(3, code) ) set horiz checked(sl, true) sl := tile by offset(sl, 1, 0) ) if(string length(1) >> 1) then( if(check for a word) then( score word(1, 3) mark word horiz(start, true) ) )else( # single-char strings count as words even though they aren't # (although they will never count for points) mark word horiz(start, true) ) end script, check for vert word, sl, begin variable(start, code) if(get vert checked(sl)) then(exit script) sl := find upmost tile(sl) start := sl $1="" $3="" while(sl) do( code := get slice extra(sl, extra 0) append ascii(1, code) if(get frozen(sl) == false) then( append ascii(3, code) ) set vert checked(sl, true) sl := tile by offset(sl, 0, 1) ) if(string length(1) >> 1) then( if(check for a word) then( score word(1, 3) mark word vert(start, true) ) )else( # single-char strings count as words even though they aren't # (although they will never count for points) mark word vert(start, true) ) end script, mark word horiz, sl, value, begin mark word in dir(sl, -1, 0, value) mark word in dir(sl, 1, 0, value) end script, mark word vert, sl, value, begin mark word in dir(sl, 0, -1, value) mark word in dir(sl, 0, 1, value) end script, mark word in dir, sl, xoff, yoff, value, begin while(sl) do( if(xoff) then( set horiz found(sl, value) check for vert word(sl) ) if(yoff) then( set vert found(sl, value) check for horiz word(sl) ) sl := tile by offset(sl, xoff, yoff) ) end script, freeze words, pl num, begin variable(sl, h, v, fr) sl := first child(board) while(sl) do( h := get horiz found(sl) v := get vert found(sl) fr := get frozen(sl) if(h && v && not(fr)) then( set frozen(sl, true) set slice extra(sl, extra 2, pl num) ) sl := next sibling(sl) ) evaluate all words end #----------------------------------------------------------------------- # Modal modes script, try to advance modal, begin variable(callback) if(not(modal)) then(exit script) callback := get slice extra(modal, extra 0) if(callback) then( run script by id(callback, modal) ) ) script, update modal, begin variable(callback) if(not(modal)) then(exit script) callback := get slice extra(modal, extra 1) if(callback) then( run script by id(callback, modal) ) end script, free modal, begin free slice(modal) modal := 0 end #----------------------------------------------------------------------- # Turn confirmer script, create turn confirmer, begin variable(sl, txt, button) sl := create rect(slice width(sprite layer) / 4 * 3, slice height(sprite layer) / 2, 12) realign slice(sl, edge:center, edge:top, edge:center, edge:top) move slice below(sl, mouse cursor) set padding(sl, 20) set rect trans(sl, trans:fuzzy) txt := create text set parent(txt, sl) realign slice(txt, edge:center, edge:top, edge:center, edge:right) if(total tiles placed) then( $0="Play these words?" )else( $0="Skip your turn?" ) set slice text(txt, 0) set outline(txt, true) $0="YES" button := create button(sl, 0) realign slice(button, edge:left, edge:bottom, edge:left, edge:bottom) set slice extra(button, extra 0, 1) $0="NO" button := create button(sl, 0) realign slice(button, edge:right, edge:bottom, edge:right, edge:bottom) set slice extra(button, extra 0, 2) set slice extra(sl, extra 0, @try to advance turn confirmer) set slice extra(sl, extra 1, @update turn confirmer) set slice edge y(sl, edge:bottom, -10) exit returning(sl) end script, try to advance turn confirmer, sl, begin if(slice edge y(sl, edge:top) << 20) then(exit script) variable(ch, extra) ch := first child(sl) while(ch) do( if(slice collide(ch, mouse cursor)) then( extra := get slice extra(ch, extra 0) if(extra == 1) then( free modal play sound(2) score words freeze words(current player) save game exit script ) if(extra == 2) then( play sound(2) ) ) ch := next sibling(ch) ) free modal end script, update turn confirmer, sl, begin variable(ch) if(slice edge y(sl, edge:top) << 20) then( nudge slice y(sl, 12) ) ch := first child(sl) while(ch) do( if(slice is rect(ch)) then(mouse over button(ch)) ch := next sibling(ch) ) end script, mouse over button, sl, begin variable(col) col := 237 if(slice collide(sl, mouse cursor)) then( col := 255 if(mouse button(left button)) then(col := 234) ) set rect bg col(sl, col) ) script, create button, parent, str, begin variable(sl, txt) sl := create rect(50, 20, 11) set parent(sl, parent) txt := create text set parent(txt, sl) center slice(txt) set outline(txt, true) set slice text(txt, str) set slice width(sl, slice width(txt) + 10) exit returning(sl) end #----------------------------------------------------------------------- # Quit confirmer script, create quit confirmer, begin variable(sl, txt, button) sl := create rect(slice width(sprite layer) / 4 * 3, slice height(sprite layer) / 2, 12) realign slice(sl, edge:center, edge:top, edge:center, edge:top) move slice below(sl, mouse cursor) set padding(sl, 20) set rect trans(sl, trans:fuzzy) txt := create text set parent(txt, sl) realign slice(txt, edge:center, edge:top, edge:center, edge:right) $0="Quit the game?" set slice text(txt, 0) set outline(txt, true) $0="YES" button := create button(sl, 0) realign slice(button, edge:left, edge:bottom, edge:left, edge:bottom) set slice extra(button, extra 0, 1) $0="NO" button := create button(sl, 0) realign slice(button, edge:right, edge:bottom, edge:right, edge:bottom) set slice extra(button, extra 0, 2) set slice extra(sl, extra 0, @try to advance quit confirmer) set slice extra(sl, extra 1, @update quit confirmer) set slice edge y(sl, edge:bottom, -10) save game exit returning(sl) end script, try to advance quit confirmer, sl, begin if(slice edge y(sl, edge:top) << 20) then(exit script) variable(ch, extra) ch := first child(sl) while(ch) do( if(slice collide(ch, mouse cursor)) then( extra := get slice extra(ch, extra 0) if(extra == 1) then( play sound(2) delete save(1) reset game exit script ) if(extra == 2) then( play sound(2) ) ) ch := next sibling(ch) ) free modal end script, update quit confirmer, sl, begin variable(ch) if(slice edge y(sl, edge:top) << 20) then( nudge slice y(sl, 12) ) ch := first child(sl) while(ch) do( if(slice is rect(ch)) then(mouse over button(ch)) ch := next sibling(ch) ) end #----------------------------------------------------------------------- # Word scoring script, try to advance score text, sl, begin if(slice edge y(sl, edge:bottom) <= slice height(sprite layer) -- 15) then( free modal play sound(2) modal := show score meters ) end script, update score text, sl, begin if(slice edge y(sl, edge:bottom) >> slice height(sprite layer) -- 15) then( nudge slice y(sl, -8) ) end script, create score box, begin variable(box, txt) box := create rect(slice width(sprite layer) -- 40, 0, current player) set slice y(box, slice height(sprite layer) + 20) move slice below(box, mouse cursor) set rect border(box, 12) realign slice(box, edge:center, edge:top, edge:center, edge:top) set padding(box, 10) txt := create text set parent(txt, box) set wrap(txt, true) set outline(txt, true) set slice width(txt, slice width(box) -- 20) create hider(box) set slice extra(box, extra 0, @try to advance score text) set slice extra(box, extra 1, @update score text) play sound(3) exit returning(box) end script, copy score string, box, str, begin variable(txt) txt := first child(box) if(ascii from string(str, string length(str)) == 10) then(delete char(str, string length(str))) set slice text(txt, str) set slice height(box, slice height(txt) + 20) end script, score words, begin variable(box) points this turn := 0 modal := create score box $str:score="*** " get player name(0, current player) str:score $+ 0 $str:score+" ***" append ascii(str:score, 10) recheck all words $str:score+"*** TOTAL=" append number(str:score, points this turn) $str:score+" ***" set score(current player, get score(current player) + points this turn) copy score string(modal, str:score) end script, score word, str, unfrozen, begin variable(points) if(modal) then( if(string length(unfrozen) == 0) then(exit script) $0="" 0 $+ str $0+" [" 0 $+ unfrozen $0+"] +" points := count word points(unfrozen) points := points * (string length(str) -- 1) / 2 append number(0, points) points this turn += points str:score $+ 0 append ascii(str:score, 10) ) end script, count word points, str, begin variable(i, code, p) p := 0 for(i, 1, string length(str)) do( code := ascii from string(str, i) p += letter value(code) ) exit returning(p) end #----------------------------------------------------------------------- # Score meters script, create score meters, begin variable(sl, i, txt) sl := create rect(slice width(sprite layer) -- 20, slice height(sprite layer) -- 20, 12) center slice(sl) set padding(sl, 20) set rect trans(sl, trans:fuzzy) set slice extra(sl, extra 0, @try to advance score meters) set slice extra(sl, extra 1, @update score meters) for(i, 0, 3) do( create score meter(sl, i) ) txt := create text set parent(txt, sl) realign slice(txt, edge:center, edge:top, edge:center, edge:bottom) set slice y(txt, -8) set outline(txt, true) score meters := sl hide score meters end script, create score meter, parent, index, begin variable(sl, holder, parent w, parent h, txt) holder := create rect(32, parent h, c:black) parent h := slice height(parent) -- get top padding(parent) -- get bottom padding(parent) set slice height(holder, parent h + 20) set slice y(holder, -6) parent w := slice width(parent) -- get left padding(parent) -- get right padding(parent) set slice x(holder, parent w / 4 * index + parent w / 8 -- 16) set parent(holder, parent) set padding(holder, 6) sl := create rect(16, 0, index) set parent(sl, holder) realign slice(sl, edge:center, edge:bottom, edge:center, edge:bottom) set rect fg col(sl, 15) txt := create text set parent(txt, sl) realign slice(txt, edge:center, edge:top, edge:center, edge:bottom) set slice extra(holder, extra 0, 0) end script, show score meters, begin set slice visible(score meters, true) if(hider) then( move slice above(score meters, hider) ) play sound(5) exit returning(score meters) end script, hide score meters, begin set slice visible(score meters, false) end script, try to advance score meters, sl, begin if(get score(current player) >= winning score) then(win mark passed := true) hide score meters modal := 0 free slice(hider) hider := 0 play sound(2) next turn end script, update score meters, meterbox, begin variable(sl, txt, n, parent h) sl := first child(slice child(meterbox, current player)) txt := first child(sl) n := get slice extra(sl, extra 0) if(n << get score(current player)) then( n += 1 parent h := slice height(meterbox) -- get top padding(meterbox) -- get bottom padding(meterbox) set slice height(sl, parent h * 1000 / winning score * n / 1000) set slice extra(sl, extra 0, n) $0="" append number(0, n) set slice text(txt, 0) if(n >= winning score) then(win mark passed := true) if(n >= get score(current player)) then(stop sound(5)) ) txt := last child(meterbox) if(win mark passed) then( $0="" append number(0, winning score) $0+" passed, FINAL ROUND!" )else( $0="First to " append number(0, winning score) $0+" wins." ) set slice text(txt, 0) end #----------------------------------------------------------------------- # Hider script, create hider, under, trans=trans:fuzzy, begin hider := create rect(0, 0, c:black) fill parent(hider, true) set rect trans(hider, trans) move slice below(hider, under) end #----------------------------------------------------------------------- # Word list searching script, check for a word, begin # assumes that the word to search for is loaded into string #1 if(search for word(first box, last box)) then( concatenate strings(0, 1) return(true) )else( concatenate strings(0, 1) return(false) ) end script, search for word, first, last, begin if(last -- first <= 1) then( exit returning(brute force search(first, last)) )else( exit returning(split search area(first, last)) ) end script, split search area, first, last, begin variable(mid) mid := first + (last -- first) / 2 if(alpha compare box(mid, 0) << 0) then( exit returning(search for word(first, mid)) )else( exit returning(search for word(mid, last)) ) end script, alpha compare box, box, line, begin # assumes that the search word is already stored in string 1 string from text box(2, box, line, false) exit returning(alpha compare(1, 2)) end script, alpha compare, s1, s2, begin # returns -1 if string s1 is alphabetically less than string s2. # returns 1 if string s1 is alphabetically more than string s2. variable(i, ch1, ch2) for(i, 1, string length(s1)) do( ch1 := ascii from string(s1, i) if(string length(s2) << i) then(exit returning(1)) ch2 := ascii from string(s2, i) if(ch1 == ch2) then(continue) exit returning(sign(ch1 -- ch2)) ) if(string length(s2) >> string length(s1)) then(exit returning(-1)) exit returning(0) end script, brute force search, first, last, begin variable(box, line) for(box, first, last) do( for(line, 0, 7) do( if(alpha compare box(box, line) == 0) then( exit returning(true) ) ) ) exit returning(false) end script, load random word, str, begin variable(box, line) box := random(first box, last box) line := random(0, 7) string from text box(str, box, line) end #----------------------------------------------------------------------- # Mouse script, update mouse, begin set slice x(mouse cursor, mouse pixel x) set slice y(mouse cursor, mouse pixel y) if(panning) then( set slice x(table, slice x(panning) + mouse pixel x -- slice width(panning)) set slice y(table, slice y(panning) + mouse pixel y -- slice height(panning)) ) if(left clicking) then( set slice visible(click anim, true) set sprite frame(click anim, small(get sprite frame(click anim) + 1, 7)) )else( set slice visible(click anim, false) set sprite frame(click anim, 0) ) end script, mouse board x, begin exit returning(mouse pixel x -- slice x(table)) end script, mouse board y, begin exit returning(mouse pixel y -- slice y(table)) end script, create mouse cursor, begin variable(sl, spr) sl := create container(1, 1) spr := load weapon sprite(1) if(running on mobile) then(set slice visible(spr, false)) set parent(spr, sl) click anim := load hero sprite(1) set parent(click anim, sl) center slice(click anim) set slice visible(click anim, false) exit returning(sl) end script, set parent to mouse, sl, begin set parent preserve pos(sl, mouse cursor) slice to back(sl) end script, try to start panning, begin if(modal) then(exit script) if(carry) then(exit script) if(slice collide(turn button, mouse cursor)) then(exit script) if(slice collide(tray, mouse cursor)) then(exit script) start panning end script, start panning, begin panning := create container(0, 0) set slice x(panning, slice x(table)) set slice y(panning, slice y(table)) set slice width(panning, mouse pixel x) set slice height(panning, mouse pixel y) end script, stop panning, begin if(panning) then( free slice(panning) panning := false ) end #----------------------------------------------------------------------- # Tile tray script, create trays, begin variable(i) tray set := create container(slice width(sprite layer), tile size + tile size / 10) set vert anchor(tray set, edge:bottom) set vert align(tray set, edge:bottom) for(i, 0, 3) do( create tray(i) ) tray := first child(tray set) end script, create tray, index, begin variable(sl) sl := create rect(0, 0, index) set slice extra(sl, extra 0, index) set rect border(sl, 14) set parent(sl, tray set) set slice width(sl, slice width(tray set)) set slice height(sl, slice height(tray set)) set slice y(sl, slice height(tray set)) fill tray(sl) end script, find tray, index, begin variable(sl) sl := first child(tray set) while(sl) do( if(get slice extra(sl, extra 0) == index) then(exit returning(sl)) sl := next sibling(sl) ) exit returning(-1) end script, fill tray, sl, begin while(child count(sl) << tiles per turn) do( create random letter(sl) ) end script, empty tray, sl, begin while(child count(sl) >> 0) do( free slice(first child(sl)) ) end script, update tray, begin variable(tile, col, dir) if(tray enabled == false) then(exit script) tile := first child(tray) while(tile) do( # keep centered vertically nudge slice y(tile, towards y(tile, tray)) # discourage overlapping col := find colliding slice(tray, tile, 0, false) if(col) then( dir := away from x(tile, col) if(dir == 0) then(dir := random(0, 1) * 2 -- 1) nudge slice x(tile, dir * 2) ) # don't go over the left/right edges if(slice edge x(tile, edge:left) << slice edge x(tray, edge:left)) then(nudge slice x(tile, 2)) if(slice edge x(tile, edge:right) >> slice edge x(tray, edge:right)) then(nudge slice x(tile, -2)) tile := next sibling(tile) ) scroll trays end script, scroll trays, begin variable(sl) sl := first child(tray set) while(sl) do( if(sl == tray) then( if(slice y(sl) >> 0) then(nudge slice y(sl, -1 * tray dist diff(sl))) )else( if(slice y(sl) << 20) then(nudge slice y(sl, 1 * tray dist diff(sl))) ) sl := next sibling(sl) ) end script, tray dist diff, sl, begin exit returning(large(1, abs(slice y(tray) / 5))) end #----------------------------------------------------------------------- # Board script, create table, begin variable(sl) sl := create rect(tile size, tile size, 13) set slice edge x(sl, edge:center, slice edge x(sprite layer, edge:center)) set slice edge y(sl, edge:center, slice edge y(sprite layer, edge:center)) set slice visible(sl, false) variable(decor) decor := create container(0, 0) set parent(decor, sl) center slice(decor) variable(bg) bg := load backdrop sprite(2) set parent(bg, decor) set slice x(bg, -320) set slice y(bg, -200) bg := load backdrop sprite(3) set parent(bg, decor) set slice x(bg, 0) set slice y(bg, -200) bg := load backdrop sprite(4) set parent(bg, decor) set slice x(bg, -320) set slice y(bg, 0) bg := load backdrop sprite(5) set parent(bg, decor) set slice x(bg, 0) set slice y(bg, 0) exit returning(sl) end script, create board, begin variable(sl) sl := create rect(tile size, tile size, 13) set parent(sl, table) exit returning(sl) end #----------------------------------------------------------------------- # Flashing script, flash invalid tiles, begin flasher := 6 update flash invalid tiles end script, update flash invalid tiles, begin variable(tile, style, h, v, fr) tile := first child(board) while(tile) do( style := get rect style(tile) h := get horiz found(tile) v := get vert found(tile) fr := get frozen(tile) if(not(h) || not(v)) then( if(flasher, mod, 2 == 0) then( style := c:black )else( style := c:white ) ) set rect style(tile, style) tile := next sibling(tile) ) flasher -= 1 if(flasher >> 0) then( set timer(1, 0, 2, @update flash invalid tiles) )else( set timer(1, 0, 2, @evaluate all words) ) end #----------------------------------------------------------------------- # Decollider script, create decollider, begin variable(sl) sl := create container(0, 0) set parent(sl, table) exit returning(sl) end script, update decollider, begin variable(tile, next, col) tile := first child(decollider) while(tile) do( next := next sibling(tile) col := find colliding slice(board, tile, 0, false) if(col) then( decollide tile(tile) )else( remove from decollider(tile) ) tile := next ) end script, decollide tile, tile, begin variable(dir) dir := best direction to decollide(tile) switch(dir) do( case(up) do(nudge slice y(tile, tile size * -1)) case(down) do(nudge slice y(tile, tile size)) case(left) do(nudge slice x(tile, tile size * -1)) case(right) do(nudge slice x(tile, tile size)) ) end script, best direction to decollide, tile, begin # don't bother to actually figure out the best yet, just randomize it exit returning(random(up, left)) end script, put in decollider, tile, begin set parent preserve pos(tile, decollider) set rect style(tile, c:purple) end script, remove from decollider, tile, begin set parent preserve pos(tile, board) set rect style(tile, c:grey) need recheck := true end #----------------------------------------------------------------------- # Turn button script, create turn button, begin variable(sl, txt, hint) sl := create rect(50, 20, 11) txt := create text set outline(txt, true) set parent(txt, sl) center slice(txt) $0="Turn Button" set slice text(txt, 0) hint := create text set outline(hint, true) set text color(hint, 2) set parent(hint, sl) realign slice(hint, edge:right, edge:bottom, edge:left, edge:top) $0="Turn Button Hint" set slice text(hint, 0) set slice visible(hint, true) set slice visible(sl, false) exit returning(sl) end script, update turn button, begin variable(sl, txt, hint, col) sl := turn button txt := first child(sl) hint := slice child(sl, 1) #if(total tiles placed == 0) then( # $0="SKIP" # set slice text(txt, 0) # $0="Skip your turn." # set slice text(hint, 0) #)else( $0="DONE" set slice text(txt, 0) $0="Confirm your word placement." set slice text(hint, 0) #) set slice width(sl, slice width(txt) + 10) col := 237 if(slice collide(sl, mouse cursor) && not(modal)) then( col := 255 if(mouse button(left button)) then(col := 234) set slice visible(hint, true) )else( set slice visible(hint, false) ) set rect bg col(sl, col) end script, try to click turn button, begin if(modal) then(exit script) if(slice collide(turn button, mouse cursor)) then( play sound(2) recheck all words if(bad tiles placed == 0) then( modal := create turn confirmer )else( flash invalid tiles play sound(4) ) ) end script, next turn, begin variable(i) i := get slice extra(tray, extra 0) i += 1 if(i >> play mode) then( if(win mark passed) then( modal := create victory screen exit script ) i := 0 if(play mode == 0) then( empty tray(tray) set slice y(tray, 20) ) ) tray := find tray(i) fill tray(tray) save game end #----------------------------------------------------------------------- # Player handling script, setup multiplayer, begin choose play mode choose target score end script, choose play mode, begin variable(holder, done) holder := create choice holder while(not(done)) do( done := update play mode mouse(holder) wait(1) ) play mode := get slice extra(get slice extra(holder, extra 0), extra 0) free slice(holder) end script, update play mode mouse, holder, begin variable(sl) if(keyval(key:ESC) > 1) then( game over ) update mouse set slice extra(holder, extra 0, -1) sl := first child(holder) while(sl) do( set rect style(sl, 12) if(slice collide(sl, mouse cursor)) then( set rect bg col(sl, 230) set slice extra(holder, extra 0, sl) ) sl := next sibling(sl) ) if(mouse button(left button)) then( if(get slice extra(holder, extra 0) >= 0) then( play sound(2) exit returning(true) ) ) exit returning(false) end script, create choice holder, begin variable(sl, i) sl := create container(0, 0) slice to back(sl) fill parent(sl, true) set padding(sl, 10) for(i, 0, 3) do( create play mode button(sl, i) ) exit returning(sl) end script, create play mode button, parent, index, begin variable(sl, txt) sl := create rect((slice width(sprite layer) -- 30) / 2, (slice height(sprite layer) -- 30) / 2, 12) set parent(sl, parent) if(index == 1 || index == 3) then( set horiz align(sl, edge:right) set horiz anchor(sl, edge:right) ) if(index == 2 || index == 3) then( set vert align(sl, edge:bottom) set vert anchor(sl, edge:bottom) ) set slice clipping(sl, true) variable(bg) bg := load backdrop sprite(6) set parent(bg, sl) set slice x(bg, (index ,mod, 2) * -160) set slice y(bg, (index / 2) * -100) txt := create text set outline(txt, true) set parent(txt, sl) get play mode name(0, index) set slice text(txt, 0) set horiz anchor(txt, edge:center) set horiz align(txt, edge:center) set slice y(txt, 10) set slice extra(sl, extra 0, index) exit returning(sl) end script, get player name, str, index, begin switch(index) do( case(0) do($str="Blue Player") case(1) do($str="Green Player") case(2) do($str="Red Player") case(3) do($str="Yellow Player") ) end script, get play mode name, str, index, begin switch(index) do( case(0) do($str="1 PLAYER PRACTICE") case(1) do($str="2 PLAYER GAME") case(2) do($str="3 PLAYER GAME") case(3) do($str="4 PLAYER GAME") ) end script, current player, begin exit returning(get slice extra(tray, extra 0)) end script, set score, player, value, begin if(player >= 0 && player <= 3) then( write global(600 + player, value) ) end script, get score, player, begin if(player >= 0 && player <= 3) then( exit returning(read global(600 + player)) ) exit returning(-1) end #----------------------------------------------------------------------- # Target score screen script, choose target score, begin modal := create target score chooser end script, create target score chooser, begin variable(sl, txt, btn) sl := create rect(slice width(sprite layer) / 3 * 2, slice height(sprite layer) / 5 * 3, 12) move slice below(sl, mouse cursor) center slice(sl) set slice edge x(sl, edge:right, -10) set slice extra(sl, extra 0, @try to advance target score chooser) set slice extra(sl, extra 1, @update target score chooser) set padding(sl, 10) txt := create text set parent(txt, sl) $0="PLAY TO SCORE:" set slice text(txt, 0) set outline(txt, true) realign slice(txt, edge:center, edge:top, edge:center, edge:top) $0="START GAME" btn := create button(sl, 0) realign slice(btn, edge:center, edge:bottom, edge:center, edge:bottom) txt := create text set parent(txt, sl) center slice(txt) set outline(txt, true) create spinner buttons(sl) exit returning(sl) end script, create spinner buttons, sl, begin variable(dir, power, holder, btn) for(dir, -1, 1, 2) do( for(power, 0, 2) do( holder := create rect(16, 16) set parent(holder, sl) center slice(holder) set rect bg col(holder, 2) btn := create text set parent(btn, holder) center slice(btn) $0="" append ascii(0, 175 + dir) set slice text(btn, 0) set slice x(holder, 20 + power * 20 * -1) set slice y(holder, dir * 12 * -1) set slice extra(holder, extra 0, 10 ^ power * dir) ) ) end script, try to advance target score chooser, sl, begin variable(btn, find, n) if(slice x(sl) << 0) then(exit script) find := first child(sl) while(find) do( if(slice collide(mouse cursor, find)) then( n := get slice extra(find, extra 0) if(n <> 0) then( winning score += n winning score := large(100, small(999, winning score)) play sound(0) ) ) find := next sibling(find) ) btn := slice child(sl, 1) if(slice collide(mouse cursor, btn)) then( play sound(2) free modal show game board tray enabled := true save game ) end script, update target score chooser, sl, begin variable(btn, col, txt, find, n) if(slice x(sl) << 0) then( nudge slice x(sl, 15) if(slice x(sl) >> 0) then(set slice x(sl, 0)) ) find := first child(sl) while(find) do( n := get slice extra(find, extra 0) if(n <> 0) then( if(slice collide(mouse cursor, find)) then( set rect bg col(find, 9) )else( set rect bg col(find, 2) ) ) find := next sibling(find) ) btn := slice child(sl, 1) mouse over button(btn) txt := slice child(sl, 2) set text color(txt, 14 + (milliseconds / 250, mod, 2)) $0="" append number(0, winning score) set slice text(txt, 0) end #----------------------------------------------------------------------- # Victory screen script, create victory screen, begin variable(sl, txt, win, tie, i) sl := create rect(slice width(sprite layer) / 4 * 3, 76, 12) move slice below(sl, mouse cursor) set rect trans(sl, trans:solid) center slice(sl) set padding(sl, 10) txt := create text set parent(txt, sl) center slice(txt) set wrap(txt, true) set outline(txt, true) fill parent(txt) win := find winner tie := detect tie if(tie) then( create tie string(str:vic) )else( $str:vic="" get player name(0, win) str:vic $+ 0 $str:vic+" wins! " append number(str:vic, get score(win)) set rect style(sl, win) set rect border(sl, 12) ) create runner up string(str:vic) set slice text(txt, str:vic) variable(button) $0="PLAY AGAIN?" button := create button(sl, 0) realign slice(button, edge:center, edge:bottom, edge:center, edge:top) set slice extra(button, extra 0, 1) set slice extra(sl, extra 0, @try to advance victory screen) set slice extra(sl, extra 1, @update victory screen) set slice edge y(sl, edge:bottom, -10) create hider(sl, trans:solid) for(i, 0, 300) do( if(i, mod, 4 == 0) then( create word floater ) update victory screen background ) play song(1) delete save(1) exit returning(sl) end script, try to advance victory screen, sl, begin if(slice edge y(sl, edge:center) << 20) then(exit script) variable(ch, extra) ch := first child(sl) while(ch) do( if(slice collide(ch, mouse cursor)) then( extra := get slice extra(ch, extra 0) if(extra == 1) then( play sound(2) delete save(1) reset game exit script ) if(extra == 2) then( play sound(2) ) ) ch := next sibling(ch) ) end script, update victory screen, sl, begin variable(ch) if(slice edge y(sl, edge:center) << 20) then( nudge slice y(sl, 12) ) ch := first child(sl) while(ch) do( if(slice is rect(ch)) then(mouse over button(ch)) ch := next sibling(ch) ) if(seconds of play, mod, 4 == 0) then( create word floater ) update victory screen background end script, update victory screen background, begin variable(ch, next) ch := first child(hider) while(ch) do( nudge slice x(ch, get slice extra(ch, extra 0)) nudge slice y(ch, get slice extra(ch, extra 1)) next := next sibling(ch) if(not(slice collide(ch, sprite layer))) then(set slice extra(ch, extra 1, get slice extra(ch, extra 1) * -1)) if(slice edge x(ch, edge:right) << 0) then(free slice(ch)) ch := next ) end script, find winner, begin variable(i, s, win) s := 0 win := -1 for(i, 0, play mode) do( if(get score(i) >> s) then( s := get score(i) if(s >= winning score) then( win := i ) ) ) exit returning(win) end script, detect tie, begin variable(i, count, winner, winscore) winner := find winner winscore := get score(winner) for(i, 0, play mode) do( if(get score(i) >= winscore) then( count += 1 ) ) exit returning(count >> 1) end script, create tie string, str, begin variable(i, winner, winscore, plus) winner := find winner winscore := get score(winner) $str="TIE! " for(i, 0, play mode) do( if(get score(i) >= winscore) then( if(plus) then( $str+"+" ) get player name(0, i) str $+ 0 plus := true ) ) $str+" " append number(str, winscore) end script, create runner up string, str, begin variable(i, winner, winscore, found) winner := find winner winscore := get score(winner) for(i, 0, play mode) do( if(get score(i) >= winscore) then(continue) if(get score(i) >= winning score) then( if(not(found)) then( append ascii(str, 10) append ascii(str, 10) found := true ) $str+"Runner up: " get player name(0, i) str $+ 0 $str+" " append number(str, get score(i)) append ascii(str, 10) ) ) end script, create word floater, begin variable(txt) txt := create text set parent(txt, hider) load random word(0) set slice text(txt, 0) set text color(txt, random(0, 255)) set slice x(txt, slice width(sprite layer)) set slice y(txt, random(-10, slice height(sprite layer))) set slice extra(txt, extra 0, random(-3, -1)) if(random(0, 100) << 50) then( set slice extra(txt, extra 1, random(-1, 1)) ) end #----------------------------------------------------------------------- # Extra data as bits script, get exbit, sl, bit, begin variable(n) n := get slice extra(sl, extra 1) if(n,and,2^bit) then(exit returning(true)) exit returning(false) end script, set exbit, sl, bit, value=1, begin variable(n) n := get slice extra(sl, extra 1) if(value) then(n := n, or, 2^bit) else(n := n, and, (-1, xor, 2^bit)) set slice extra(sl, extra 1, n) end script, get horiz checked, sl, begin exit returning(get exbit(sl, 0)) end script, set horiz checked, sl, value, begin set exbit(sl, 0, value) end script, get vert checked, sl, begin exit returning(get exbit(sl, 1)) end script, set vert checked, sl, value, begin set exbit(sl, 1, value) end script, get horiz found, sl, begin exit returning(get exbit(sl, 2)) end script, set horiz found, sl, value, begin set exbit(sl, 2, value) end script, get vert found, sl, begin exit returning(get exbit(sl, 3)) end script, set vert found, sl, value, begin set exbit(sl, 3, value) end script, get frozen, sl, begin exit returning(get exbit(sl, 4)) end script, set frozen, sl, value, begin set exbit(sl, 4, value) end #----------------------------------------------------------------------- # Utility scripts script, nudge slice x, sl, change, begin if(change) then( set slice x(sl, slice x(sl) + change) ) end script, nudge slice y, sl, change, begin if(change) then( set slice y(sl, slice y(sl) + change) ) end script, towards x, sl, dest, edge=edge:center, edgedest=edge:center, begin exit returning(sign(slice edge x(dest, edgedest) -- slice edge x(sl, edge))) end script, towards y, sl, dest, edge=edge:center, edgedest=edge:center, begin exit returning(sign(slice edge y(dest, edgedest) -- slice edge y(sl, edge))) end script, away from x, sl, dest, edge=edge:center, edgedest=edge:center, begin exit returning(sign(slice edge x(sl, edge) -- slice edge x(dest, edgedest))) end script, away from y, sl, dest, edge=edge:center, edgedest=edge:center, begin exit returning(sign(slice edge y(sl, edge) -- slice edge y(dest, edgedest))) end script, slice at pos, parent, x, y, begin variable(pos, find, result) pos := create container(1,1) set parent(pos, parent) put slice(pos, x, y) result := false find := first child(parent) while(find) do( if(find <> pos) then( if(slice collide(pos, find)) then( result := find break ) ) find := next sibling(find) ) free slice(pos) exit returning(result) end #----------------------------------------------------------------------- # Utility scripts that dang well need to be in plotscr.hsd already dangnabit! script, set parent preserve pos, sl, new parent, begin variable(x, y) x := slice screen x(sl) y := slice screen y(sl) set parent(sl, new parent) put slice screen(sl, x, y) end script, small, v1, v2, begin if(v1 >> v2) then(exit returning(v2)) exit returning(v1) end script, large, v1, v2, begin if(v1 << v2) then(exit returning(v2)) exit returning(v1) end #----------------------------------------------------------------------- # Saving and Loading plotscript, on load game, begin suspend player play song(0) prepare mouse main loop end script, save game, begin save version := current save version save in slot(1) end #-----------------------------------------------------------------------