######################################################################## # Many of the tests in this script might seem silly. That is okay. # # See interactivetest.hss for tests which require user input. # # Any time you are preparing to fix an engine bug, consider adding a # test that demonstrates the bug FIRST before you fix the bug. include, hstests.hss include, autotest.hsi include, "autotest-plotstr.hsi" # Save slots used: # 1 for save/load tests # 2 for save/load tests # 3 for export globals tests # 4 test expanding strings from save slots # 5 empty, for testing failure of expanding strings from empty save slots # 31 save slot: persistent ######################################################################## define constant(1, default wait) define constant(10, timer:checkpoint) global variable(100, menu item script global) global variable(101, timer global) global variable(102, timer global will become) global variable(103, battle script sequence) global variable(104, menu close global) global variable(105, embedding global) global variable(106, export global 1) global variable(107, export global 2) global variable(108, expecting death) global variable(109, died) global variable(110, map autorun triggered) global variable(111, eachstep triggered) global variable(112, textbox script triggered) global variable(113, npc script triggered) global variable(114, testing script triggers) global variable(115, savegame map) global variable(116, savegame slice) global variable(117, savegame npc) global variable(118, called resetgame) global variable(119, hook loadgame) global variable(120, timer checkpoint interval) global variable(121, saveglobal) global variable(50000, the global with the biggest id) # 200-500 used in hstests.hss # 1000-1063 used in zonetests define constant(1000, array:zones) # 5000-6000 used in hstests.hss #string 0 = error messages #string 1-9 = temporary misc #string 10 = error message arg #string 11 = asserts #string 95-99 = temp misc define constant(10, err arg string) define constant(11, assert expression string) # see notes at the top of this file for what save slots get used define constant(31, save slot: persistent) ######################################################################## # Set on starting map 0 plotscript, mapautorun, begin # Test that the map autorun script on the starting map happens before # the newgame script map autorun triggered += 1 end # TODO: What would be nice is to reset the game between each test suite, # making use of the ability to pass args to a new/load game script, # so that we don't have to worry about things interfering with each other plotscript, new game, arg1, arg2, arg3, begin trace($1="newgame script") tracevalue(arg1, arg2, arg3) suspend player seed random(4444) # This stuff is for "test reset game" import globals(save slot: persistent, @called resetgame, @called resetgame) if (called resetgame || arg1) then ( after resetgame(arg1, arg2, arg3) run tests 2 # continue tests ) else ( run tests 1 # start tests ) end plotscript, load game, slot, arg1, arg2, arg3, begin trace($1="loadgame script") tracevalue(slot, arg1, arg2, arg3, hook loadgame) suspend player seed random(4444) if (hook loadgame) then ( after loadgame(arg1, arg2, arg3) run tests 3 # continue tests ) else ( # This means we weren't expecting this script to be called crash ) end # testing starts here script, run tests 1, begin assert(map autorun triggered == 1) interpreter tests scheduling tests plotstr tests string load tests save slot tests slice tests maptile tests wallchecking tests zone tests inventory tests hero tests death tests trigger tests door tests npc tests menu tests textbox tests script trigger tests enemy tests battle tests timer tests pathfinding tests run game tests resetgame tests # Resets the game crash end script, start checkpoint timer, interval, begin timer checkpoint interval := interval do start checkpoint interval end script, do start checkpoint interval , begin _checkpoint set timer(timer:checkpoint, 0, timer checkpoint interval, @do start checkpoint interval) end script, stop checkpoint timer, begin stop timer(timer:checkpoint) end # follows "resetgame tests" script, run tests 2, begin savegame tests # Saves and loads the game crash end # follows "savegame tests" script, run tests 3, begin # more tests here, potentially passed tests end script, passed tests, begin $0="TESTS SUCCEEDED" trace(0) gameover end ######################################################################## script, w, ticks=default wait, begin wait(ticks) _checkpoint end # Returns a string of the script call stack in given string id script, callstack, string, begin variable(depth, id) depth := 1 $ string = "" while (true) do ( id := getcallingscriptid(depth) if (id == 0) then (break) if (depth == 1) then ( getscriptname(string, id) ) else ( getscriptname(95, id) stringsprintf(string, $96="%s -> %s", 95, string) ) depth += 1 ) return(string) end script, crash, begin if(string length(10) >> 0) then( $0+"(" concatenate strings(0, err arg string) $0+")" ) show text box(1) $1="crash() called from " callstack(2) 1 $+ 2 trace(1) $1="in testsuite: " 1 $+ 0 trace(1) w(25) # script error(0) game over end script, assert failure, begin $1="ASSERT FAILURE:" trace(1) trace(assert expression string) crash end ######################################################################## # Test the interaction of different script fibres, including pausing, # waiting, and back-compat blocking. # This makes use of timers, but the real timer tests are elsewhere. # Triggering scripts is also tested in "script trigger tests" and # a number of other tests for npcs, menus, battles, etc. script, scheduling tests, begin $0="scheduling tests" tick counter slice := create container set slice velocity x(tick counter slice, 1, 1000) blocking tests assert(check bug 430 enabled == false) variable (oldval) oldval := read general(178) # genBits2 write general(178, oldval, or, (2 ^ 1)) # Enable bug 430 assert(check bug 430 enabled == true) write general(178, oldval) free slice(tick counter slice) end script, ticknumber, begin return(slice x(tick counter slice)) end ######################################################################## script, blocker script, begin # assert(ticker 0 == expected ticker 0) ticker 1 += 1 wait ticker 1 += 1 end script, blocker script 2, begin assert(ticker 1 == expected ticker 1) ticker 2 += 1 wait ticker 2 += 1 assert(ticker 1 == expected ticker 1) end script, eachtick script, begin ticker 0 += 1 set timer(3, 0, 1, @eachtick script) end script, blocking tests, begin $0="blocking tests" variable (start tick) start tick := ticknumber ticker 0 := 0 ticker 1 := 0 # globals ticker 2 := 0 # Start an each-tick script on a timer that should not interfer with anything else # (since it has a higher timer ID) set timer(3, 0, 1, @eachtick script) wait(2) assert(ticknumber == start tick + 2) # Trigger another script and check that this one is blocked # (This is also a test for bug 430, because of eachtick script) expected ticker 0 := 0 set timer(1, 0, 1, @blocker script) assert(ticknumber == start tick + 2) # This script will continue running until the next tick assert(ticker 1 == 0) wait(1) assert(ticker 1 == 2) assert(ticknumber == start tick + 4) # Trigger two scripts to run at once; one blocks the other (test for bug 430) expected ticker 1 := 2 set timer(1, 0, 1, @blocker script) set timer(2, 0, 1, @blocker script 2) # Runs first assert(ticknumber == start tick + 4) wait assert(ticknumber == start tick + 7) # one tick wait each plus the wait above assert(ticker 1 == 4) assert(ticker 2 == 2) # Check eachtick ran every tick #trace value(ticknumber, start tick, ticker 0, ticker 1, ticker 2) assert(ticker 0 == ticknumber -- start tick) stop timer(3) end ######################################################################## script, bug 430 tester, begin variable (start tick) start tick := ticknumber wait # should be skipped if (ticknumber == start tick) then ( # was skipped ticker 1 += 1 ) end # blocking tests is completely broken if bug 430 is enabled, so here is a separate test, # Returns whether bug 430 is enabled script, check bug 430 enabled, begin $0="check bug 430 enabled" variable (start tick) start tick := ticknumber ticker 1 := 0 # globals ticker 2 := 0 # Trigger two scripts to run at once; one blocks the other (test for bug 430) expected ticker 1 := 0 set timer(1, 0, 1, @bug 430 tester) set timer(2, 0, 1, @blocker script 2) # Runs first wait assert(ticker 2 == 2) if(ticknumber == start tick + 2 && ticker 1 == 1) then ( # wait in blocker script 2 plus the wait above return (true) ) else if(ticknumber == start tick + 3 && ticker 1 == 0) then ( return (false) ) else ( # Other combinations should be impossible crash ) end ######################################################################## script, inventory tests, begin $0="Inventory tests" # This tests only the inventory and commands to manipulate it. # Far more item tests including some equipment/inventory stuff is in 'equipment tests' # Precondition: empty inventory assert(get inventory size == 600) variable(slot, lastslot) for (slot, 0, get inventory size -- 1) do ( assert(item in slot(slot) == -1) assert(item count in slot(slot) == 0) ) # Simple stuff get item(item:Boots, 3) assert(inventory(item:Boots) == 3) assert(item in slot(0) == item:Boots) assert(item count in slot(0) == 3) get item(item:Boots, 99) assert(inventory(item:Boots) == 102) delete item(item:Boots) assert(inventory(item:Boots) == 101) delete item(item:Boots, 101) assert(inventory(item:Boots) == 0) # test item slot commands assert(item in slot(0) == -1) assert(item count in slot(0) == 0) assert(item in slot(1) == -1) assert(item count in slot(1) == 0) set item in slot(1, item:Boots) # used on empty slot, adds one item assert(item in slot(1) == item:Boots) assert(item count in slot(1) == 1) assert(inventory(item:Boots) == 1) lastslot := get inventory size -- 1 set item in slot(lastslot, item:Boots) assert(item in slot(lastslot) == item:Boots) set item count in slot(lastslot, 99) assert(inventory(item:Boots) == 100) # check deleteitem deletes in right order delete item(item:Boots, 5) assert(inventory(item:Boots) == 95) assert(item count in slot(1) == 0) assert(item count in slot(lastslot) == 95) # transmog a stack of items set item in slot(lastslot, item:SteelSho) assert(item in slot(lastslot) == item:SteelSho) assert(item count in slot(lastslot) == 95) assert(inventory(item:SteelSho) == 95) assert(inventory(item:Boots) == 0) # test the two additional ways of deleting items set item in slot(lastslot, -1) assert(item count in slot(lastslot) == 0) set item in slot(2, item:Boots) set item count in slot(2, 0) assert(item in slot(2) == -1) # leave nothing for (slot, 0, get inventory size -- 1) do ( assert(item in slot(slot) == -1) ) # test max stack sizes assert(get item maximum stack size(item:Boots) == 99) assert(get item maximum stack size(item:Bulky) == 3) get item(item:Bulky, 6) assert(inventory(item:Bulky) == 6) assert(item count in slot(0) == 3) assert(item count in slot(1) == 3) set item in slot(2, item:Boots) set item count in slot(2, 40) # changing type should cause stacks to overflow if too large set item in slot(2, item:Bulky) assert(inventory(item:Bulky) == 46) assert(item count in slot(2) == 3) delete item(item:Bulky, 46) end ######################################################################## script, hero tests, begin hero party management tests # The party now contains heroes 0, 1, 2, 3 in that order hero appearance tests hero caterpillar tests hero exp and levels tests hero stat growth test hero stat tests equipment tests hero misc tests hero names embed tests # The party should continue to be 0, 1, 2, 3 end ## hero commands left to test ## spell lists #can learn spell (hero,attack) #forget spell (hero,attack) #knows spell (hero,attack) #read spell (hero,list,slot) #teach spell (hero,attack) #write spell (hero,list,slot,attack) ## Equipment #set default weapon (hero,item) ## Stats #get level MP (who, mp level slot, type) #set level MP (who, mp level slot, new value) ## Misc #hero base elemental resist as int (who, element) #hero total elemental resist as int (who, element) #set hero base elemental resist (who, element, percent) script, hero party management tests, begin $0="hero party management tests" assert(room in active party == 3) add hero(hero:Helga) add hero(hero:Olaf) add hero(hero:Frumpy) assert(room in active party == 0) assert(hero by rank(0) == hero:Freki) assert(hero by rank(1) == hero:Helga) assert(hero by rank(2) == hero:Olaf) assert(hero by rank(3) == hero:Frumpy) # with a full party, hero by rank and hero by slot should returnt he same values assert(hero by rank(0) == hero by slot(0)) assert(hero by rank(1) == hero by slot(1)) assert(hero by rank(2) == hero by slot(2)) assert(hero by rank(3) == hero by slot(3)) # now delete the leader delete hero(hero:Freki) assert(room in active party == 1) assert(hero by rank(0) == 1) assert(hero by rank(1) == 2) assert(hero by rank(2) == 3) assert(hero by rank(3) == -1) assert(hero by slot(0) == -1) assert(hero by slot(1) == 1) assert(hero by slot(2) == 2) assert(hero by slot(3) == 3) # add a different leader add hero(hero:Styrge) assert(hero by slot(0) == hero:Styrge) # test find hero assert(find hero(hero:Freki) == -1) assert(find hero(hero:Helga) == 1) assert(find hero(hero:Olaf) == 2) assert(find hero(hero:Frumpy) == 3) assert(find hero(hero:Styrge) == 0) # test rank in caterpillar assert(rank in caterpillar(hero:Freki) == -1) assert(rank in caterpillar(hero:Helga) == 1) assert(rank in caterpillar(hero:Olaf) == 2) assert(rank in caterpillar(hero:Frumpy) == 3) assert(rank in caterpillar(hero:Styrge) == 0) # Add a hero to the reserve add hero(hero:Kitt) assert(room in active party == 0) variable(slot) slot := find hero(hero:Kitt) assert(slot >= 4) assert(rank in caterpillar(hero:Kitt) == -1) assert(hero by slot(slot) == hero:Kitt) # this command needs to work on reserve slots assert(hero by rank(4) == -1) # this command should not work on reserve slots # names $1="Styrge" get hero name(2, 0) assert(string compare(1, 2)) $1="Helga" get hero name(2, 1) assert(string compare(1, 2)) $1="Olaf" get hero name(2, 2) assert(string compare(1, 2)) $1="Frumpy" get hero name(2, 3) assert(string compare(1, 2)) $1="Kitt" get hero name(2, find hero(hero:Kitt)) assert(string compare(1, 2)) $1="Kittzilla" set hero name(1, find hero(hero:Kitt)) get hero name(2, find hero(hero:Kitt)) assert(string compare(1, 2)) # Swapping swap out hero(hero:Helga) assert(hero by slot(1) == -1) assert(find hero(hero:Helga) >= 4) swap in hero(hero:Kitt) assert(hero by slot(1) == hero:Kitt) assert(find hero(hero:Kitt) >> 0 && find hero(hero:Kitt) <= 3) swap by position(0, 3) # swap Styrge and Frumpy assert(hero by slot(0) == hero:Frumpy) assert(hero by slot(3) == hero:Styrge) swap by position(3, find hero(hero:Helga)) # swap Styrge and Helga assert(hero by slot(3) == hero:Helga) assert(find hero(hero:Styrge) >= 4) swap by name(hero:Kitt, hero:Styrge) assert(hero by slot(1) == hero:Styrge) assert(find hero(hero:Kitt) >= 4) swap out hero(hero by slot(0)) # swap out frumpy assert(hero by slot(0) == -1) # restore numeric order add hero(hero:Freki) # Freki assert(hero by slot(0) == hero:Freki) swap by position(1, find hero(hero:Helga)) assert(hero by slot(1) == hero:Helga) swap by position(2, find hero(hero:Olaf)) assert(hero by slot(2) == hero:Olaf) swap by position(3, find hero(hero:Frumpy)) assert(hero by slot(3) == hero:Frumpy) end script, hero appearance tests, begin # preconditions assert(hero by slot(3) == hero:Frumpy) # ensure we're using party slots, not hero ids or caterpillar position swap by position(2, 3) swap by position(1, 10) # 2 = hero:Frumpy assert(get hero picture(2, inside battle) == 8) assert(get hero picture(2, outside battle) == 9) assert(get hero picture(2, hero portrait) == 2) assert(get hero palette(2, inside battle) == -1) assert(get hero palette(2, outside battle) == -1) assert(get hero palette(2, hero portrait) == 2) set hero picture(2, 0, inside battle) set hero picture(2, 4, outside battle) set hero picture(2, 7, hero portrait) set hero palette(2, 37, inside battle) set hero palette(2, 1, outside battle) set hero palette(2, -1, hero portrait) show text box(17) # test portrait by party slot w(3) advance text box assert(get hero picture(2, inside battle) == 0) assert(get hero picture(2, outside battle) == 4) assert(get hero picture(2, hero portrait) == 7) assert(get hero palette(2, inside battle) == 37) assert(get hero palette(2, outside battle) == 1) assert(get hero palette(2, hero portrait) == -1) reset hero picture(2, inside battle) reset hero picture(2, outside battle) reset hero picture(2, hero portrait) reset hero palette(2, inside battle) reset hero palette(2, outside battle) reset hero palette(2, hero portrait) assert(get hero picture(2, inside battle) == 8) assert(get hero picture(2, outside battle) == 9) assert(get hero picture(2, hero portrait) == 2) assert(get hero palette(2, inside battle) == -1) assert(get hero palette(2, outside battle) == -1) assert(get hero palette(2, hero portrait) == 2) # Restore state swap by position(2, 3) swap by position(1, 10) end script, hero names embed tests, begin $0="hero names embed tests" variable(h0, h1, h2, h3) # remember the old party order h0 := hero by slot(0) h1 := hero by slot(1) h2 := hero by slot(2) h3 := hero by slot(3) swap by position(0, find hero(hero:Olaf)) swap out hero(hero by slot(1)) swap out hero(hero by slot(2)) swap out hero(hero by slot(3)) $1="Olaf,,," $2="Olaf,,," $3="Freki,Helga,Olaf,Frumpy,Styrge" hero names embed helper swap by position(2, find hero(hero:Olaf)) $1="Olaf,,," $2=",,Olaf," hero names embed helper swap by position(0, find hero(hero:Frumpy)) $1="Frumpy,Olaf,," $2="Frumpy,,Olaf," hero names embed helper swap by position(1, find hero(hero:Olaf)) swap by position(3, find hero(hero:Frumpy)) $1="Olaf,Frumpy,," $2=",Olaf,,Frumpy" hero names embed helper add hero(hero:Olaf) # slot 1 $4="Nolaf" set hero name(4, 1) $1="Olaf,Nolaf,Frumpy," $2="Olaf,Nolaf,,Frumpy" hero names embed helper swap by position(0, find hero(hero:Frumpy)) $1="Frumpy,Nolaf,Olaf," $2="Frumpy,Nolaf,,Olaf" $3="Freki,Helga,Nolaf,Frumpy,Styrge" hero names embed helper show no value, w advance textbox swap by position(0, 1) # Nolaf to front delete hero(hero:Olaf) # Test embedtext from save slots # Control test, no change to hero name save in slot(4), w expand string($1="${H1}", 4) show string(1), w assert(string compare(1, $2="Helga")) # Hero name by hero id # Helga should be in the reserve when this happens, but we don't care exactly which reserve slot variable(helgaslot) helgaslot := find hero(hero:Helga) assert(helgaslot > 3) # Change Helga's name set hero name($3="Hagar", helgaslot) save in slot(4), w expand string($1="${H1}", 4) show string(1), w assert(string compare(1, $2="Hagar")) # Restore hero name, check again set hero name($3="Helga", helgaslot) assert(string compare(get hero name(1, helgaslot), $2="Helga")) expand string($1="${H1}", 4) show string(1), w assert(string compare(1, $2="Hagar")) # Hero name by party slot # Put helga in slot 2 swap by position(find hero(hero:Helga), 2) assert(find hero(hero:Helga) == 2) # Rename her and resave set hero name($3="Humpty", 2) save in slot(4), w expand string($1="${P2}", 4) show string(1), w assert(string compare(1, $2="Humpty")) # Restore name, check again set hero name($3="Helga", 2) assert(string compare(get hero name(1, 2), $2="Helga")) expand string($1="${P2}", 4) show string(1), w assert(string compare(1, $2="Humpty")) # Hero name by caterpillar slot # Put helga in slot 3 swap by position(find hero(hero:Helga), 3) assert(find hero(hero:Helga) == 3) # Make slot 2 empty show string(get hero name(1, 2)), w swap out hero(hero:Olaf) assert(hero by slot(2) == -1) # Make sure slot 0 is empty assert(hero by slot(0) == -1) # Helga should be rank 1 (2nd) in the caterpillar assert(rank in caterpillar(hero:Helga) == 1) # Rename Helga and save set hero name($1="Hissy", 3) save in slot(4), w expand string($1="${C1}", 4) show string(1), w assert(string compare(1, $2="Hissy")) # Restore name, check again set hero name($3="Helga", 3) assert(string compare(get hero name(1, 3), $2="Helga")) expand string($1="${C1}", 4) show string(1), w assert(string compare(1, $2="Hissy")) show no value # Check strings being expanded from an empty slot # Make sure slot 5 is really empty delete save(5) assert(string compare($1="${H1}", expand string($2="${H1}", 5))) assert(string compare($1="${P0}", expand string($2="${P0}", 5))) assert(string compare($1="${C0}", expand string($2="${C0}", 5))) assert(string compare($1="${H1},${H2},${H3}", expand string($2="${H1},${H2},${H3}", 5))) # Although not hero related, lets throw some tests for ${V} and ${S} in here too. #saveglobal is global id 121 saveglobal := 54321 show string(expand string($1="Var=${V121}")), w assert(string compare(1, $2="Var=54321")) # Save the global to save slot 4, check it save in slot(4), w saveglobal := 1 show string(expand string($1="Var=${V121}", 4)), w assert(string compare(1, $2="Var=54321")) # Replace it with another value saveglobal := 100001 save in slot(4), w saveglobal := 1 show string(expand string($1="Var=${V121}", 4)), w assert(string compare(1, $2="Var=100001")) assert(saveglobal == 1) # Check empty slot 5 show string(expand string($1="Var=${V121}", 5)), w assert(string compare(1, $2="Var=${V121}")) # Test strings $3="A very fine mess" save in slot(4), w $3="Cleaned up" show string(expand string($2="${S3}", 4)), w assert(string compare(2, $1="A very fine mess")) assert(string compare(3, $1="Cleaned up")) # A different string $2="Is better than sloppy order" save in slot(4), w $2="" show string(expand string($3="${S2}", 4)), w assert(string compare(3, $1="Is better than sloppy order")) # An empty save slot (5) show string(expand string($3="${S2}", 5)), w assert(string compare(3, $1="${S2}")) # restore old party order swap by position(0, find hero(h0)) swap by position(1, find hero(h1)) swap by position(2, find hero(h2)) swap by position(3, find hero(h3)) show box names advance textbox end script, hero names embed helper, begin show string(2) $4="${C0},${C1},${C2},${C3}" expand string(4) $5="${P0},${P1},${P2},${P3}" expand string(5) $6="${H65},${H1},${H2},${H3},${H4}" expand string(6) assert(string compare(1, 4)) assert(string compare(2, 5)) assert(string compare(3, 6)) show box names end script, show box names, begin show text box(9) w(10) show text box(10) w(10) show text box(11) w(10) end ## Party management #lock hero (who) #unlock hero (who) script, hero caterpillar tests, begin variable(i) $0="hero caterpillar tests" $err arg string="leader, cater=ON" do hero cater tests(me) suspend caterpillar for(i, 0, 3) do( $err arg string="hero " append number(err arg string, i) $err arg string=", cater=OFF" do hero cater tests(i) ) resume caterpillar $err arg string="" end script, do hero cater tests, who, begin variable(d) walk hero to x (who, 8), w wait for hero(who) assert(hero x(who) == 8) walk hero to y(who, 10), w wait for hero(who) assert(hero y(who) == 10) camera follows hero(who) walk hero to x(who, 9), w wait for hero(who) assert(hero x(who) == 9) walk hero to y(who, 8), w wait for hero(who) assert(hero y(who) == 8) camera follows hero(0) walk hero to x (who, 6), w wait for hero(who) assert(hero x(who) == 6) set hero position(who, 7, 7), w assert(hero x(who) == 7) assert(hero y(who) == 7) walk hero(who, south, 2) wait for hero(who), w assert(hero y(who) == 9) assert(hero direction(who) == south) walk hero(who, south, -1) # negative distance means walk backwards wait for hero(who), w assert(hero y(who) == 8) assert(hero direction(who) == south) walk hero(who, south, 1) wait for hero(who), w assert(hero y(who) == 9) assert(hero direction(who) == south) walk hero(who, west, 2) wait for hero(who), w assert(hero x(who) == 5) assert(hero direction(who) == west) walk hero(who, north, 1) wait for hero(who), w assert(hero y(who) == 8) assert(hero direction(who) == north) walk hero(who, east, 1) wait for hero(who), w assert(hero x(who) == 6) assert(hero direction(who) == east) # spin for(d, north, west) do( set hero direction(who, d), w assert(hero direction(who) == d) ) # moonwalk in a circle walk hero(who, south, 1) set hero direction(who, north) wait for hero(who), w assert(hero direction(who) == north) assert(hero x(who) == 6) assert(hero y(who) == 9) walk hero(who, west, 1) set hero direction(who, east) wait for hero(who), w assert(hero direction(who) == east) assert(hero x(who) == 5) assert(hero y(who) == 9) walk hero(who, north, 1) set hero direction(who, south) wait for hero(who), w assert(hero direction(who) == south) assert(hero x(who) == 5) assert(hero y(who) == 8) walk hero(who, east, 1) set hero direction(who, west) wait for hero(who), w assert(hero direction(who) == west) assert(hero x(who) == 6) assert(hero y(who) == 8) # moonwalk in a circle using negative distance walk hero(who, north, -1) wait for hero(who), w assert(hero direction(who) == north) assert(hero x(who) == 6) assert(hero y(who) == 9) walk hero(who, east, -1) wait for hero(who), w assert(hero direction(who) == east) assert(hero x(who) == 5) assert(hero y(who) == 9) walk hero(who, south, -1) wait for hero(who), w assert(hero direction(who) == south) assert(hero x(who) == 5) assert(hero y(who) == 8) walk hero(who, west, -1) wait for hero(who), w assert(hero direction(who) == west) assert(hero x(who) == 6) assert(hero y(who) == 8) # walk into wall walk hero(who, north, 3) # should only make it 2 tiles wait for hero(who) assert(hero Y(who) == 6) # check walls expect hero walls(who, true, false, false, false) walk hero(who, west, 1) wait for hero(who), w walk hero(who, north, 1) wait for hero(who), w expect hero walls(who, false, true, false, false) walk hero(who, north, 2) wait for hero(who), w walk hero(who, east, 1) wait for hero(who), w expect hero walls(who, false, false, true, false) walk hero(who, east, 5) wait for hero(who), w expect hero walls(who, true, true, false, false) # speed test time! set hero speed(who, 2) assert(get hero speed(who) == 2) walk hero(who, south, 1) w(9), assert(hero is walking(who)) w(1), assert(hero is walking(who) == false) set hero speed(who, 4) assert(get hero speed(who) == 4) walk hero(who, south, 1) w(4), assert(hero is walking(who)) w(1), assert(hero is walking(who) == false) set hero speed(who, 5) assert(get hero speed(who) == 5) walk hero(who, south, 1) w(3), assert(hero is walking(who)) w(1), assert(hero is walking(who) == false) set hero speed(who, 10) assert(get hero speed(who) == 10) walk hero(who, south, 1) w(1), assert(hero is walking(who)) w(1), assert(hero is walking(who) == false) set hero speed(who, 20) assert(get hero speed(who) == 20) walk hero(who, south, 1) w(1), assert(hero is walking(who) == false) walk hero(who, west, 1), w walk hero(who, north, 2), w(2) assert(hero x(who) == 10) assert(hero y(who) == 6) set hero speed(who) assert(get hero speed(who) == 4) walk hero(who, west, 3) wait for hero(who) #FIXME: should probably test misaligned walking too # frame variable(fr) for(fr, 1, 8) do( set hero frame(who, (fr ,mod, 2)) assert(hero frame(who) == (fr ,mod, 2)) w(fr) ) #pixel pos variable(px, py) px := hero pixel x(who) assert(px == 140) py := hero pixel y(who) assert(py == 120) variable(ix, iy) for(iy, 0, 5) do( for(ix, 0, 5) do( put hero(who, 105 + ix, 105 + iy) assert(hero pixel x(who) == 105 + ix) assert(hero pixel y(who) == 105 + iy) w ) ) # Test one-wall walls set hero position(who, 5, 9) walk hero(who, south, 1) # normal walk onto a tile with aone-way wall wait for hero(who) assert(hero y(who) == 10) walk hero(who, east, 1) # walk off, where there is no wall wait for hero(who) assert(hero x(who) == 6) walk hero(who, west, 2) # walking between tiles with one-way walls in other directions wait for hero(who) assert(hero x(who) == 4) walk hero(who, west, 1) # attempt to walk through a normal wall while on a oneway wall wait for hero(who) assert(hero x(who) == 4) walk hero(who, north, 1) # walk through one-way wall (allowed) wait for hero(who) assert(hero y(who) == 9) walk hero(who, south, 1) # try to walk disallowed direction wait for hero(who) assert(hero y(who) == 9) walk hero(who, east, 1) wait for hero(who) walk hero(who, south, 2) # walk through one-way wall wait for hero(who) assert(hero y(who) == 11) walk hero(who, north, 1) # try to walk disallowed direction wait for hero(who) assert(hero y(who) == 11) put hero(who, px, py), w end script, expect hero walls, who, wn, we, ws, ww, begin assert(check hero wall(who, north) == wn) assert(check hero wall(who, east) == we) assert(check hero wall(who, south) == ws) assert(check hero wall(who, west) == ww) end ## caterpillar #suspend hero walls #resume hero walls #set hero frame (who, frame) #set hero speed (who, speed) #set hero z (who, z) script, hero exp and levels tests, begin variable(i) $0="hero exp and levels tests" # check default level curve assert(experience to level(1) == 30) assert(experience to level(2) == 71) assert(experience to level(3) == 125) assert(experience to level(4) == 195) assert(experience to level(5) == 284) assert(experience to level(6) == 396) assert(experience to level(7) == 535) assert(experience to level(8) == 707) assert(experience to level(9) == 918) assert(experience to level(10) == 1176) assert(experience to level(11) == 1491) assert(experience to level(12) == 1874) assert(experience to level(13) == 2339) assert(experience to level(14) == 2902) assert(experience to level(15) == 3583) assert(experience to level(99) == 50183838) # check Freki's level curve (should be same as default) variable(freki slot) freki slot := find hero(hero:freki) assert(freki slot >= 0) assert(experience to level(1, freki slot) == 30) assert(experience to level(2, freki slot) == 71) assert(experience to level(3, freki slot) == 125) assert(experience to level(4, freki slot) == 195) assert(experience to level(5, freki slot) == 284) assert(experience to level(6, freki slot) == 396) assert(experience to level(7, freki slot) == 535) assert(experience to level(8, freki slot) == 707) assert(experience to level(9, freki slot) == 918) assert(experience to level(10, freki slot) == 1176) assert(experience to level(11, freki slot) == 1491) assert(experience to level(12, freki slot) == 1874) assert(experience to level(13, freki slot) == 2339) assert(experience to level(14, freki slot) == 2902) assert(experience to level(15, freki slot) == 3583) assert(experience to level(99, freki slot) == 50183838) # check Bram's level curve (should faster than default) add hero(hero:Bram) variable(bram slot) bram slot := find hero(hero:Bram) assert(bram slot >= 0) assert(experience to level(1, bram slot) == 30) assert(experience to level(2, bram slot) == 70) assert(experience to level(3, bram slot) == 121) assert(experience to level(4, bram slot) == 185) assert(experience to level(5, bram slot) == 264) assert(experience to level(6, bram slot) == 360) assert(experience to level(7, bram slot) == 475) assert(experience to level(8, bram slot) == 612) assert(experience to level(9, bram slot) == 775) assert(experience to level(10, bram slot) == 967) assert(experience to level(11, bram slot) == 1193) assert(experience to level(12, bram slot) == 1458) assert(experience to level(13, bram slot) == 1768) assert(experience to level(14, bram slot) == 2130) assert(experience to level(15, bram slot) == 2551) assert(experience to level(99, bram slot) == 36587434) delete hero(hero:Bram) assert(get hero level(0) == 0) # level setting for(i, 1, 99) do( set hero level(0, i) assert(get hero level(0) == i) assert(total experience(0) == experience to level(i)) ) # level-based spell learning/forgetting set hero level(0, 9) assert(knows spell (0, 2) == false) # Freki should not have L.10 Wolf at level 9 set hero level(0, 10) assert(knows spell (0, 2) == true) # Freki should learn L.10 Wolf at level 10 set hero level(0, 0, false) assert(get hero level(0) == 0) assert(hero levelled(0) == -10) assert(knows spell (0, 2) == true) # Freki should not forget L.10 Wolf because of how we deleveled update level up learning(0, true) assert(knows spell (0, 2) == false) # Now Freki should forget L.10 Wolf. # experience assert(experience to next level(0) == 30) give experience(0, 5) assert(hero levelled(0) == 0) assert(experience to next level(0) == 25) give experience(0, 25) assert(get hero level(0) == 1) assert(hero levelled(0) == 1) assert(experience to next level(0) == 41) give experience(0, -1) # de-level should not work with this command, but experience will go down assert(get hero level(0) == 1) assert(hero levelled(0) == 0) assert(experience to next level(0) == 42) give experience(0, 42) assert(get hero level(0) == 2) assert(hero levelled(0) == 1) set hero level(0, 9) give experience(0, experience to next level(0)) assert(get hero level(0) == 10) assert(hero levelled(0) == 1) assert(spells learned(0, get count) == 1) assert(spells learned(0, 0) == 2) assert(spells learnt(0, 0) == 1) #deprecated, but why not test it? give experience(0, 1) # should not cause levelling assert(hero levelled == 0) assert(spells learned(0, get count) == 0) # split experience set hero level(0, 0, true) give experience(party, 30) assert(hero levelled(0) == 0) assert(total experience(0) == 8) assert(total experience(1) == 8) assert(total experience(2) == 8) assert(total experience(3) == 8) give experience(party, 88) assert(get hero level(0) == 1) assert(get hero level(1) == 1) assert(get hero level(2) == 1) assert(get hero level(3) == 1) assert(total experience(find hero(hero:Kitt)) == 0) # outside of the party # experience for dead heroes set hero level(0, 0, true) set hero level(1, 0, true) set hero level(2, 0, true) set hero level(3, 0, true) set hero stat(2, 0, 0) # kill Olaf set dead heroes gain experience (false) give experience(party, 120) assert(total experience(0) == 40) assert(total experience(1) == 40) assert(total experience(2) == 0) assert(total experience(3) == 40) set hero level(0, 0, true) set hero level(1, 0, true) set hero level(2, 0, true) set hero level(3, 0, true) set dead heroes gain experience (true) give experience(party, 120) assert(total experience(0) == 30) assert(total experience(1) == 30) assert(total experience(2) == 30) assert(total experience(3) == 30) set hero level(0, 0, true) set hero level(1, 0, true) set hero level(2, 0, true) set hero level(3, 0, true) set hero stat(2, 0, get hero stat(2, 0, maximum stat)) # revive Olaf # level caps set hero level(0, 1) assert(get level cap == 99) set level cap(2) assert(get level cap == 2) give experience(0, 41) assert(get hero level(0) == 2) assert(total experience(0) == 71) assert(experience to next level(0) == 54) # being at the level cap does not alter the exp to next level give experience(0, 10000000) assert(hero levelled(0) == 0) assert(get hero level(0) == 2) set level cap(99) # Hero level range check tags assert(hero by slot(0) == hero:Freki) set hero level(0, 0, true), w assert(check tag(tag: freki level 0) == true) assert(check tag(tag: freki level teens) == false) set hero level(0, 12, true), w assert(check tag(tag: freki level 0) == false) assert(check tag(tag: freki level teens) == false) set hero level(0, 13, true), w assert(check tag(tag: freki level 0) == false) assert(check tag(tag: freki level teens) == true) set hero level(0, 19, true), w assert(check tag(tag: freki level 0) == false) assert(check tag(tag: freki level teens) == true) set hero level(0, 20, true), w assert(check tag(tag: freki level 0) == false) assert(check tag(tag: freki level teens) == false) # reset set hero level(0, 0, true) set hero level(1, 0, true) set hero level(2, 0, true) set hero level(3, 0, true) end script, hero stat growth test, begin $0="hero stat growth test" show string(0), w # This tests the crappy default stat growth curve, which we will hopefully replace someday set hero level(0 ,0) assert(get hero stat(0, 0, maximum stat) == 10) set hero level(0 ,1) assert(get hero stat(0, 0, maximum stat) == 13) set hero level(0 ,2) assert(get hero stat(0, 0, maximum stat) == 16) # set hero level(0 ,3) # assert(get hero stat(0, 0, maximum stat) == 19) # set hero level(0 ,4) # assert(get hero stat(0, 0, maximum stat) == 23) # set hero level(0 ,5) # assert(get hero stat(0, 0, maximum stat) == 26) # set hero level(0 ,6) # assert(get hero stat(0, 0, maximum stat) == 30) # set hero level(0 ,7) # assert(get hero stat(0, 0, maximum stat) == 34) # set hero level(0 ,8) # assert(get hero stat(0, 0, maximum stat) == 38) # set hero level(0 ,9) # assert(get hero stat(0, 0, maximum stat) == 42) set hero level(0 ,10) assert(get hero stat(0, 0, maximum stat) == 46) assert(get level mp(0, 0) == 5) assert(get level mp(0, 1) == 3) assert(get level mp(0, 2) == 2) assert(get level mp(0, 3) == 1) assert(get level mp(0, 4) == 0) assert(get level mp(0, 5) == 0) assert(get level mp(0, 6) == 0) assert(get level mp(0, 7) == 0) # set hero level(0 ,11) # assert(get hero stat(0, 0, maximum stat) == 50) # set hero level(0 ,12) # assert(get hero stat(0, 0, maximum stat) == 55) # set hero level(0 ,13) # assert(get hero stat(0, 0, maximum stat) == 60) # set hero level(0 ,14) # assert(get hero stat(0, 0, maximum stat) == 64) # set hero level(0 ,15) # assert(get hero stat(0, 0, maximum stat) == 69) # set hero level(0 ,16) # assert(get hero stat(0, 0, maximum stat) == 75) # set hero level(0 ,17) # assert(get hero stat(0, 0, maximum stat) == 80) # set hero level(0 ,18) # assert(get hero stat(0, 0, maximum stat) == 85) # set hero level(0 ,19) # assert(get hero stat(0, 0, maximum stat) == 91) set hero level(0 ,20) assert(get hero stat(0, 0, maximum stat) == 96) # set hero level(0 ,21) # assert(get hero stat(0, 0, maximum stat) == 102) # set hero level(0 ,22) # assert(get hero stat(0, 0, maximum stat) == 108) # set hero level(0 ,23) # assert(get hero stat(0, 0, maximum stat) == 114) # set hero level(0 ,24) # assert(get hero stat(0, 0, maximum stat) == 121) # set hero level(0 ,25) # assert(get hero stat(0, 0, maximum stat) == 127) # set hero level(0 ,26) # assert(get hero stat(0, 0, maximum stat) == 134) # set hero level(0 ,27) # assert(get hero stat(0, 0, maximum stat) == 140) # set hero level(0 ,28) # assert(get hero stat(0, 0, maximum stat) == 147) # set hero level(0 ,29) # assert(get hero stat(0, 0, maximum stat) == 154) set hero level(0 ,30) assert(get hero stat(0, 0, maximum stat) == 161) # set hero level(0 ,31) # assert(get hero stat(0, 0, maximum stat) == 168) # set hero level(0 ,32) # assert(get hero stat(0, 0, maximum stat) == 176) # set hero level(0 ,33) # assert(get hero stat(0, 0, maximum stat) == 183) # set hero level(0 ,34) # assert(get hero stat(0, 0, maximum stat) == 191) # set hero level(0 ,35) # assert(get hero stat(0, 0, maximum stat) == 199) # set hero level(0 ,36) # assert(get hero stat(0, 0, maximum stat) == 207) # set hero level(0 ,37) # assert(get hero stat(0, 0, maximum stat) == 215) # set hero level(0 ,38) # assert(get hero stat(0, 0, maximum stat) == 223) # set hero level(0 ,39) # assert(get hero stat(0, 0, maximum stat) == 232) set hero level(0 ,40) assert(get hero stat(0, 0, maximum stat) == 240) # set hero level(0 ,41) # assert(get hero stat(0, 0, maximum stat) == 249) # set hero level(0 ,42) # assert(get hero stat(0, 0, maximum stat) == 258) # set hero level(0 ,43) # assert(get hero stat(0, 0, maximum stat) == 267) # set hero level(0 ,44) # assert(get hero stat(0, 0, maximum stat) == 276) # set hero level(0 ,45) # assert(get hero stat(0, 0, maximum stat) == 285) # set hero level(0 ,46) # assert(get hero stat(0, 0, maximum stat) == 295) # set hero level(0 ,47) # assert(get hero stat(0, 0, maximum stat) == 304) # set hero level(0 ,48) # assert(get hero stat(0, 0, maximum stat) == 314) # set hero level(0 ,49) # assert(get hero stat(0, 0, maximum stat) == 324) set hero level(0 ,50) assert(get hero stat(0, 0, maximum stat) == 334) # set hero level(0 ,51) # assert(get hero stat(0, 0, maximum stat) == 344) # set hero level(0 ,52) # assert(get hero stat(0, 0, maximum stat) == 354) # set hero level(0 ,53) # assert(get hero stat(0, 0, maximum stat) == 365) # set hero level(0 ,54) # assert(get hero stat(0, 0, maximum stat) == 375) # set hero level(0 ,55) # assert(get hero stat(0, 0, maximum stat) == 386) # set hero level(0 ,56) # assert(get hero stat(0, 0, maximum stat) == 397) # set hero level(0 ,57) # assert(get hero stat(0, 0, maximum stat) == 408) # set hero level(0 ,58) # assert(get hero stat(0, 0, maximum stat) == 419) # set hero level(0 ,59) # assert(get hero stat(0, 0, maximum stat) == 430) set hero level(0 ,60) assert(get hero stat(0, 0, maximum stat) == 442) # set hero level(0 ,61) # assert(get hero stat(0, 0, maximum stat) == 453) # set hero level(0 ,62) # assert(get hero stat(0, 0, maximum stat) == 465) # set hero level(0 ,63) # assert(get hero stat(0, 0, maximum stat) == 477) # set hero level(0 ,64) # assert(get hero stat(0, 0, maximum stat) == 489) # set hero level(0 ,65) # assert(get hero stat(0, 0, maximum stat) == 501) # set hero level(0 ,66) # assert(get hero stat(0, 0, maximum stat) == 513) # set hero level(0 ,67) # assert(get hero stat(0, 0, maximum stat) == 526) # set hero level(0 ,68) # assert(get hero stat(0, 0, maximum stat) == 538) # set hero level(0 ,69) # assert(get hero stat(0, 0, maximum stat) == 551) set hero level(0 ,70) assert(get hero stat(0, 0, maximum stat) == 564) # set hero level(0 ,71) # assert(get hero stat(0, 0, maximum stat) == 577) # set hero level(0 ,72) # assert(get hero stat(0, 0, maximum stat) == 590) # set hero level(0 ,73) # assert(get hero stat(0, 0, maximum stat) == 604) # set hero level(0 ,74) # assert(get hero stat(0, 0, maximum stat) == 617) # set hero level(0 ,75) # assert(get hero stat(0, 0, maximum stat) == 631) # set hero level(0 ,76) # assert(get hero stat(0, 0, maximum stat) == 644) # set hero level(0 ,77) # assert(get hero stat(0, 0, maximum stat) == 658) # set hero level(0 ,78) # assert(get hero stat(0, 0, maximum stat) == 672) # set hero level(0 ,79) # assert(get hero stat(0, 0, maximum stat) == 686) set hero level(0 ,80) assert(get hero stat(0, 0, maximum stat) == 701) # set hero level(0 ,81) # assert(get hero stat(0, 0, maximum stat) == 715) # set hero level(0 ,82) # assert(get hero stat(0, 0, maximum stat) == 730) # set hero level(0 ,83) # assert(get hero stat(0, 0, maximum stat) == 745) # set hero level(0 ,84) # assert(get hero stat(0, 0, maximum stat) == 759) # set hero level(0 ,85) # assert(get hero stat(0, 0, maximum stat) == 774) # set hero level(0 ,86) # assert(get hero stat(0, 0, maximum stat) == 790) # set hero level(0 ,87) # assert(get hero stat(0, 0, maximum stat) == 805) # set hero level(0 ,88) # assert(get hero stat(0, 0, maximum stat) == 820) # set hero level(0 ,89) # assert(get hero stat(0, 0, maximum stat) == 836) set hero level(0 ,90) assert(get hero stat(0, 0, maximum stat) == 852) # set hero level(0 ,91) # assert(get hero stat(0, 0, maximum stat) == 868) # set hero level(0 ,92) # assert(get hero stat(0, 0, maximum stat) == 884) # set hero level(0 ,93) # assert(get hero stat(0, 0, maximum stat) == 900) # set hero level(0 ,94) # assert(get hero stat(0, 0, maximum stat) == 916) # set hero level(0 ,95) # assert(get hero stat(0, 0, maximum stat) == 933) # set hero level(0 ,96) # assert(get hero stat(0, 0, maximum stat) == 949) # set hero level(0 ,97) # assert(get hero stat(0, 0, maximum stat) == 966) set hero level(0 ,98) assert(get hero stat(0, 0, maximum stat) == 983) set hero level(0 ,99) assert(get hero stat(0, 0, maximum stat) == 1000) set hero level(0, 0, true) show no value, w end script, restore hp and mp, begin variable(i) for (i, 0, 40) do ( if (hero by slot(i) <> -1) then ( set hero stat(i, stat:hp, get hero stat(i, stat:hp, maximum stat), current stat) set hero stat(i, stat:mp, get hero stat(i, stat:mp, maximum stat), current stat) ) ) end script, hero stat tests, begin $0="hero stat tests" # test hero stat commands, stat capping, equip stat bonuses, current vs. max quirks, negative stats, level mp # check initial condition assert(hero by slot(1) == hero:Helga) assert(get hero level(1) == 0) assert(get hero stat(1, stat:hp, current stat) == 10) assert(get hero stat(1, stat:mp, current stat) == 20) assert(get hero stat(1, stat:atk, current stat) == 10) assert(get hero stat(1, stat:spd, current stat) == 30) assert(get hero stat(1, stat:hp, base stat) == 10) assert(get hero stat(1, stat:mp, base stat) == 20) assert(get hero stat(1, stat:atk, base stat) == 9) # default weapon has +1 atk assert(get hero stat(1, stat:spd, base stat) == 30) # test stat caps assert(get hero stat cap(stat:hp) == 0) assert(get hero stat cap(stat:mp) == 0) assert(get hero stat cap(stat:atk) == 100) #in-editor assert(get hero stat cap(stat:spd) == 0) # set capped hero stat set capped hero stat(1, stat:atk, 110, current stat) assert(get hero stat(1, stat:atk, current stat) == 100) assert(get hero stat(1, stat:atk, base stat) == 9) set capped hero stat(1, stat:atk, 120, maximum stat) assert(get hero stat(1, stat:atk, maximum stat) == 100) assert(get hero stat(1, stat:atk, base stat) == 99) set capped hero stat(1, stat:hp, 999999, current stat) assert(get hero stat(1, stat:hp, current stat) == 999999) set hero stat(1, stat:hp, 10, current stat) #back to original # set hero stat should not be affected by caps set hero stat(1, stat:atk, 110, current stat) assert(get hero stat(1, stat:atk, current stat) == 110) # modify caps set hero stat cap(stat:hp, 5) set hero stat cap(stat:mp, 12) assert(get hero stat cap(stat:hp) == 5) assert(get hero stat(1, stat:hp, current stat) == 5) assert(get hero stat(1, stat:hp, maximum stat) == 5) assert(get hero stat(1, stat:hp, base stat) == 10) assert(get hero stat(1, stat:mp, current stat) == 12) assert(get hero stat(1, stat:mp, maximum stat) == 12) assert(get hero stat(1, stat:mp, base stat) == 20) # set base stat set hero stat(1, stat:atk, 20, base stat) assert(get hero stat(1, stat:atk, maximum stat) == 21) #+1 from weapon set hero stat(1, stat:atk, 200, base stat) assert(get hero stat(1, stat:atk, base stat) == 200) assert(get hero stat(1, stat:atk, maximum stat) == 100) #capped set hero stat(1, stat:atk, 10, current stat) #back to original set hero stat(1, stat:atk, 10, maximum stat) #original max stat but not base stat! assert(get hero stat(1, stat:atk, base stat) == 110) set hero stat(1, stat:atk, 9, base stat) #back to original max and base assert(get hero stat(1, stat:atk, maximum stat) == 10) set hero stat cap(stat:atk, 0) set hero stat cap(stat:spd, 10) assert(get hero stat cap(stat:atk) == 0) assert(get hero stat cap(stat:spd) == 10) assert(get hero stat(1, stat:atk, current stat) == 10) assert(get hero stat(1, stat:atk, maximum stat) == 10) assert(get hero stat(1, stat:spd, current stat) == 10) assert(get hero stat(1, stat:spd, maximum stat) == 10) set hero stat cap(stat:hp, 0) set hero stat cap(stat:mp, 0) set hero stat cap(stat:spd, 0) # gain hero stat assert(gain hero stat(1, stat:atk, 3) == 13) #return new maximum assert(get hero stat(1, stat:atk, base stat) == 12) assert(get hero stat(1, stat:atk, maximum stat) == 13) assert(get hero stat(1, stat:atk, current stat) == 13) # Only max and current should respect caps set hero stat cap(stat:atk, 11) assert(gain hero stat(1, stat:atk, 4) == 11) #return new maximum assert(get hero stat(1, stat:atk, base stat) == 16) assert(get hero stat(1, stat:atk, maximum stat) == 11) assert(get hero stat(1, stat:atk, current stat) == 11) gain hero stat(1, stat:atk, -7) #back to original set hero stat cap(stat:atk, 0) # Test proportional increase assert(get hero stat(1, stat:hp, current stat) == 5) # HP: 5/10 assert(gain hero stat(1, stat:hp, 6) == 16) assert(get hero stat(1, stat:hp, current stat) == 8) # HP: 8/16 assert(get hero stat(1, stat:hp, maximum stat) == 16) assert(gain hero stat(1, stat:hp, -7) == 9) # Test reset-to-max assert(gain hero stat(1, stat:hp, 1, true) == 10) assert(get hero stat(1, stat:hp, current stat) == 10) # HP: 10/10 assert(get hero stat(1, stat:hp, maximum stat) == 10) # test original stats restored assert(get hero stat(1, stat:hp, maximum stat) == 10) assert(get hero stat(1, stat:hp, base stat) == 10) assert(get hero stat(1, stat:mp, maximum stat) == 20) assert(get hero stat(1, stat:mp, base stat) == 20) assert(get hero stat(1, stat:atk, current stat) == 10) assert(get hero stat(1, stat:atk, maximum stat) == 10) assert(get hero stat(1, stat:atk, base stat) == 9) assert(get hero stat(1, stat:spd, current stat) == 30) assert(get hero stat(1, stat:spd, maximum stat) == 30) assert(get hero stat(1, stat:spd, base stat) == 30) # but not current values for hp, mp assert(get hero stat(1, stat:hp, current stat) == 10) assert(get hero stat(1, stat:mp, current stat) == 12) # ...fix that up restore hp and mp # Simple test of hero level mp # The hero is level 0. Other levels are tested in "hero stat growth test" assert(get level mp(1, 0, current stat) == 1) assert(get level mp(1, 0, maximum stat) == 1) variable(level) for(level, 1, 7) do ( assert(get level mp(1, level, current stat) == 0) assert(get level mp(1, level, maximum stat) == 0) ) set level mp(1, 7, 99) assert(get level mp(1, 7) == 99) set level mp(1, 7, 0) end script, equipment tests, begin $0="equipment tests" # This is a continuation of 'hero stat tests', see that for preconditions # additional precondition: empty inventory, as well as: assert(find hero(hero:Freki) == 0) assert(find hero(hero:Helga) == 1) # test equipment commands get item(item:Boots) assert(inventory(item:Boots) == 1) assert(equip where(1, item:Boots) == slot:legs) # equippable by all heroes assert(check equipment(1, slot:legs) == -1) assert(check equipment(1, slot:weapon) == item:DefltWep) # default weapon (not properly tested) assert(get default weapon(1) == item:DefltWep) force equip(1, slot:legs, item:Boots) # stat bonuses: spd+2 hp+3 assert(check equipment(1, slot:legs) == item:Boots) assert(inventory(item:Boots) == 0) # test stat bonuses assert(get hero stat(1, stat:hp, current stat) == 10) assert(get hero stat(1, stat:hp, maximum stat) == 13) # only affects max values of hp, mp assert(get hero stat(1, stat:hp, base stat) == 10) assert(get hero stat(1, stat:spd, current stat) == 32) assert(get hero stat(1, stat:spd, maximum stat) == 32) # resets current value to max for other stats assert(get hero stat(1, stat:spd, base stat) == 30) assert(inventory(item:SteelSho) == 0) assert(equip where(0, item:SteelSho) == slot:legs) #equippable only by Freki assert(equip where(1, item:SteelSho) == false) # Note that force equip can be used to equip an item not in the inventory, # in that case you get a free copy. # Force equip also allows equipping in wrong slot force equip(1, slot:weapon, item:SteelSho) # stat bonuses: atk+4 (default weapon has atk+1) assert(check equipment(1, slot:weapon) == item:SteelSho) assert(check equipment(1, slot:legs) == item:Boots) assert(inventory(item:DefltWep) == 0) # shouldn't gain a default weapon assert(get hero stat(1, stat:atk, current stat) == 13) assert(get hero stat(1, stat:atk, maximum stat) == 13) # test unequipping unequip(1, slot:legs) assert(inventory(item:Boots) == 1) assert(check equipment(1, slot:legs) == -1) set hero stat(1, stat:hp, 29, current stat) # check effects of unequipping... even on stats set hero stat(1, stat:spd, 29, current stat) # which the equipment doesn't have bonuses on unequip(1, slot:weapon) assert(inventory(item:SteelSho) == 1) assert(check equipment(1, slot:weapon) == item:DefltWep) assert(get hero stat(1, stat:hp, current stat) == 10) # current values of hp,mp should be capped to max assert(get hero stat(1, stat:hp, maximum stat) == 10) assert(get hero stat(1, stat:spd, current stat) == 30) assert(get hero stat(1, stat:spd, maximum stat) == 30) # resets current value to max for other stats # TODO: test equip elemental resists # test for Bug 743 - Unequipping items with stat bonuses that exceed stat limits is broken assert(get hero stat(1, stat:hp, current stat) == 10) # preconditions (max same) assert(get hero stat(1, stat:spd, current stat) == 30) set hero stat cap(stat:hp, 5) set hero stat cap(stat:spd, 5) force equip(1, slot:legs, item:Boots) assert(get hero stat(1, stat:hp, current stat) == 5) # cap hp, mp to the cap assert(get hero stat(1, stat:hp, maximum stat) == 5) assert(get hero stat(1, stat:spd, current stat) == 5) # resets current value to max for other stats assert(get hero stat(1, stat:spd, maximum stat) == 5) unequip(1, slot:legs) assert(get hero stat(1, stat:hp, current stat) == 5) assert(get hero stat(1, stat:hp, maximum stat) == 5) assert(get hero stat(1, stat:spd, current stat) == 5) assert(get hero stat(1, stat:spd, maximum stat) == 5) set hero stat cap(stat:hp, 0) set hero stat cap(stat:spd, 0) assert(get hero stat(1, stat:hp, current stat) == 5) # only affects max values of hp, mp assert(get hero stat(1, stat:hp, maximum stat) == 10) assert(get hero stat(1, stat:spd, current stat) == 30) # resets current value to max for other stats assert(get hero stat(1, stat:spd, maximum stat) == 30) # ...fix that up restore hp and mp assert(get hero stat(1, stat:hp, current stat) == 10) # cleanup delete item(item:SteelSho) delete item(item:Boots) end script, hero misc tests, begin $0="hero misc tests" show string(0), w variable(n) assert(hero by slot(0) == hero:Freki) assert(get hero hand x(0, hand:attack A) == 22) assert(get hero hand y(0, hand:attack A) == 11) assert(get hero hand x(0, hand:attack B) == 2) assert(get hero hand y(0, hand:attack B) == 17) set hero hand x(0, hand:attack A, 50) set hero hand y(0, hand:attack A, -25) set hero hand x(0, hand:attack B, -10) set hero hand y(0, hand:attack B, 1) assert(get hero hand x(0, hand:attack A) == 50) assert(get hero hand y(0, hand:attack A) == -25) assert(get hero hand x(0, hand:attack B) == -10) assert(get hero hand y(0, hand:attack B) == 1) set hero hand x(0, hand:attack A, get default hero hand x(0, hand:attack A)) set hero hand y(0, hand:attack A, get default hero hand y(0, hand:attack A)) set hero hand x(0, hand:attack B, get default hero hand x(0, hand:attack B)) set hero hand y(0, hand:attack B, get default hero hand y(0, hand:attack B)) assert(get hero hand x(0, hand:attack A) == 22) assert(get hero hand y(0, hand:attack A) == 11) assert(get hero hand x(0, hand:attack B) == 2) assert(get hero hand y(0, hand:attack B) == 17) end ######################################################################## script, npc tests, begin npc movement tests(1) npc movement tests(NPC reference(1)) npc id tests(NPC reference(1)) npc tag and onetime tests use npc script tests alter npc tests end script, npc movement tests, n, begin $0="npc movement tests" $err arg string="n=", append number(err arg string, n) show string(0) # assert starting pos assert(npc X(n) == 3) assert(npc Y(n) == 5) # walk in a circle, testing speed set npc speed(n, 4) walk npc(n, south, 1), w wait for npc(n),w assert(npc Y(n) == 6) set NPC speed(n, 5) walk npc(n, east, 1), w wait for npc(n),w assert(npc X(n) == 4) set NPC speed(n, 10) walk npc(n, north, 1), w wait for npc(n),w assert(npc Y(n) == 5) set NPC speed(n, 2) walk npc(n, west, 1), w wait for npc(n),w assert(npc X(n) == 3) set npc speed(n, 4) # Walk backwards walk npc(n, east, -1) wait for npc(n), w assert(npc X(n) == 2) assert(npc direction(n) == east) walk npc(n, south, -1) wait for npc(n), w assert(npc Y(n) == 4) assert(npc direction(n) == south) set npc position(n, 3, 5) show no value $err arg string="" end script, npc id tests, n, begin set npc direction(n, south), w assert(get npc id(n) == 1) change npc id(n, 2), w(4) assert(get npc id(n) == 2) change npc id(n, 1), w end script, npc tag and onetime tests, begin $0="npc onetime tests" variable(hx, hy, n) # Moving the hero in this script is a little silly, # but ensures that the onetime NPCs are on-screen # ...which they probably would have been anyway hx := hero x(me) hy := hero y(me) walk hero to y(me, 12) wait for hero(me), w walk hero to x(me, 4) wait for hero(me), w assert(check onetime(3) == false) assert(check onetime(4) == false) use npc(3), w assert(check onetime(3) == true) assert(check onetime(4) == false) use npc(4), w assert(check onetime(3) == true) assert(check onetime(4) == true) w n := npc reference(4) assert(n == false) set onetime(4, false), w n := npc reference(4) assert(n <> false) assert(check tag(10000) == false) w n := npc reference(5) assert(n <> false) set tag(10000, true) w n := npc reference(5) assert(n == false) assert(check tag(10000) == true) walk hero to x(me, hx) wait for hero(me), w walk hero to y(me, hy) wait for hero(me), w end plotscript, another npc script, begin assert(ticknumber == 2) npc script triggered := 1 end script, use npc script tests, begin $0="use npc script tests" # Tests the implicit wait behaviour of usenpc tick counter slice := create container set slice velocity x(tick counter slice, 1, 1000) assert(ticknumber == 0) create npc(8) # Does nothing use npc(8) assert(ticknumber == 1) delete npc(8) # Both this script and anothernpcscript should wait create npc(7) # Calls anothernpcscript npc script triggered := 0 use npc(7) assert(npc script triggered == 1) assert(ticknumber == 2) delete npc(7) free slice(tick counter slice) end script, alter npc tests, begin $0="alter npc tests" assert(current map == 0) w # make a pair of NPCs to use in these tests variable(n1, n2) n1 := create npc(9, 5, 5, west),w n2 := create npc(9, 11, 5, east),w # First do picture and palette changes on the first instance # and verify the changes on the second instance assert(get npc sprite id(n2) == 13) assert(get npc sprite palette(n2) == -1) alter npc(n1, NPCStat:picture, 12),w assert(get npc sprite id(n2) == 12) alter npc(n1, NPCStat:palette, 5),w assert(get npc sprite palette(n2) == 5) alter npc(n1, NPCStat:picture, 13),w alter npc(n1, NPCStat:palette, -1),w # Test move speed variable(ox, oy) assert(read npc(n1, NPCStat:move speed) == 0) alter npc(n1, NPCStat:move speed, 1), w ox := npc pixel x(n2) oy := npc pixel y(n2) walk npc(n2, east, 1) w(10) assert(npc pixel x(n2) == ox + 10) w(10) assert(npc pixel x(n2) == ox + 20) alter npc(n1, NPCStat:move speed, 2),w walk npc(n2, south, 1) w(1) assert(npc pixel y(n2) == oy + 2) wait for npc(n2) assert(npc pixel y(n2) == oy + 20) alter npc(n1, NPCStat:move speed, 4),w walk npc(n2, west, 1) w(1) assert(npc pixel x(n2) == ox + 16) wait for npc(n2) alter npc(n1, NPCStat:move speed, 5),w walk npc(n2, north, 1) w(1) assert(npc pixel y(n2) == oy + 15) wait for npc(n2) # Has gone in a complete circle assert(npc pixel x(n2) == ox) assert(npc pixel y(n2) == oy) # How about diagonal next? alter npc(n1, NPCStat:move speed, 10),w walk npc(n2, right, 1) walk npc(n2, down, 1) w(1) assert(npc pixel x(n2) == ox + 10) assert(npc pixel y(n2) == oy + 10) w(1) assert(npc pixel x(n2) == ox + 20) assert(npc pixel y(n2) == oy + 20) alter npc(n1, NPCStat:move speed, 20) walk npc(n2, left, 1) walk npc(n2, up, 1) w(1) assert(npc pixel x(n2) == ox + 0) assert(npc pixel y(n2) == oy + 0) alter npc(n1, NPCStat:move speed, 0) # Now test textbox display assert(read npc(n1, NPCStat:display text) == 0) alter npc(n1, NPCStat:display text, 18),w assert(current text box == -1) use npc(n2), w assert(current text box == 18) advance text box, w assert(current text box == -1) # Test touch and step-on activation # We will use a text box for this test alter npc(n1, NPCStat:display text, 18),w assert(current text box == -1) assert(read npc(n1, NPCstat:activation) == NPCactivation:use) # Move the hero adjacent to the npc walk hero to x(me, npc x(n2)),w wait for hero(me),w assert(hero x(me) == npc x(n2)) assert(hero y(me) == npc y(n2) + 1) assert(current text box == -1) # Try to walking into the npc, nothing should happen walk hero(me, north, 1), w wait for hero(me),w assert(hero y(me) == npc y(n2) + 1) assert(current text box == -1) # Make the NPC touch-activated alter npc(n1, NPCstat:activation, NPCactivation:touch), w # Nothing should happen yet assert(current text box == -1) # Walk the hero into the NPC walk hero(me, north, 1), w wait for hero(me), w assert(current text box == 18) advance text box assert(current text box == -1) # Walk the hero next to the NPC (does nothing because the NPC isn't moving) walk hero(me, right, 1), w wait for hero(me), w assert(current text box == -1) walk hero(me, left, 1), w wait for hero(me), w assert(current text box == -1) # Now move the npc. Even when moving away into a tile one space diagonal, activation should happen alter npc(n1, NPCStat:move speed, 5) walk npc(n2, right, 1), w wait for npc(n2), w assert(current text box == 18) advance text box assert(current text box == -1) # Move one tile further. This should not activate walk npc(n2, right, 1), w wait for npc(n2), w assert(current text box == -1) # Walk back one tile, into the diagonal space. Will activate walk npc(n2, left, 1), w wait for npc(n2), w assert(current text box == 18) advance text box, w assert(current text box == -1) # Walk back one more space, into the adjacent tile, will activate again walk npc(n2, left, 1), w wait for npc(n2), w assert(current text box == 18) advance text box, w assert(current text box == -1) # Now try step-on activation alter npc(n1, NPCstat:activation, NPCactivation:stepon),w walk hero(me, north, 1), w assert(current text box == -1) wait for hero(me), w assert(current text box == 18) advance text box, w assert(current text box == -1) # Move the heroes around walk hero(me, north, 1), w wait for hero(me),w assert(current text box == -1) walk hero(me, right, 1), w wait for hero(me),w walk hero(me, down, 2), w wait for hero(me),w walk hero(me, left, 1), w wait for hero(me),w assert(hero x(me) == npc x(n2)) assert(hero y(me) == npc y(n2) + 1) # Move the step-on npc under the hero (for better or for worse, this does not activate) assert(current text box == -1) walk npc(n2, down, 1), w assert(current text box == -1) wait for npc(n2), w assert(current text box == -1) # Walk the npc back and reset its activation walk npc(n2, up, 1), w wait for npc(n2), w assert(current text box == -1) alter npc(n1, NPCstat:activation, NPCactivation:use), w assert(read npc(n1, NPCstat:activation) == NPCactivation:use) alter npc(n1, NPCstat:display text, 0) #_cancel runfast #wait for key #_runfast # Test getting items assert(read npc(n1, NPCstat:give item) == 0) alter npc(n1, NPCstat:give item, item:Whatsit + 1), w assert(read npc(n1, NPCstat:give item) == item:Whatsit + 1) # There should not be any Whatsits in your inventory yet assert(inventory(item:Whatsit) == 0) # Now get one use npc(n2),w assert(inventory(item:Whatsit) == 1) # Get a few more use npc(n2),w use npc(n2),w use npc(n2),w assert(inventory(item:Whatsit) == 4) # Now clear the get item alter npc(n1, NPCstat:give item, 0), w # This should not give the item use npc(n2),w assert(inventory(item:Whatsit) == 4) ### still needs tests: # NPCstat:move type # NPCstat:when activated # NPCstat:pushability # NPCstat:script # NPCstat:script argument # NPCstat:vehicle # NPCstat:default movement zone # NPCstat:default avoidance zone # NPCstat:ignore passmap while (npc copy count(9) > 0) do( delete npc(9),w ) end script, get npc sprite id, ref, begin variable(sl, spr) sl := get npc slice(ref) spr := lookup slice(sl:walkabout sprite component, sl) assert(get sprite type(spr) == spritetype:walkabout) exit returning(get sprite set number(spr)) end script, get npc sprite palette, ref, begin variable(sl, spr) sl := get npc slice(ref) spr := lookup slice(sl:walkabout sprite component, sl) assert(get sprite type(spr) == spritetype:walkabout) exit returning(get sprite palette(spr)) end ######################################################################## script, death tests, begin $0="death tests" # See also "test harm tile death" below assert (get death script == 0) set death script(@on death script) assert (get death script == @on death script) assert(died == 0) expecting death := false # Setting hero stats to 0 should NOT trigger death variable (i) for (i, 0, 3) do ( set hero stat(i, stat:hp, 0) ) wait assert(died == 0) # Death by oob attack set hero stat(0, stat:hp, 10) # Only hero 0 alive expecting death := true map cure(atk:suicide, 0) assert(get hero stat(0, stat:hp) == 0) # Death script should not be triggered until next tick assert(died == 0) wait(1) assert(died == 1) # Re-trigger even if already dead map cure(atk:suicide, 0) assert(died == 1) wait(1) assert(died == 2) # Death shouldn't be triggered if one hero has 0 max hp variable(old maxhp) oldmaxhp := get hero stat(1, stat:hp, maximum stat) set hero stat(1, stat:hp, 0, maximum stat) map cure(atk:suicide, 0) wait(1) assert(died == 2) set hero stat(1, stat:hp, old maxhp, maximum stat) # Death shouldn't be triggered if heroes are healed before the next tick map cure(atk:suicide, 0) set hero stat(0, stat:hp, 1) wait(1) assert(died == 2) #FIXME: test death by battle expecting death := false died := 0 restore hp and mp end script, on death script, begin $9="on death script" trace(9) if (expecting death) then ( died += 1 exit script ) crash end script, test harm tile death, start hp, begin # Called from "harm tile tests" expecting death := true set harm tile damage(100) walk hero(me, right, 1) wait for hero(me) # The step finishes, causing death, then it will be processed the same tick, spawning the script assert(died == 1) assert hurt pattern(7, start hp, start hp, start hp, start hp, start hp) expecting death := false died := 0 end ######################################################################## script, trigger tests, begin harm tile tests end script, assert hurt pattern, test no, start hp, h0, h1, h2, h3, begin # h# is the amount of damage by which hero # in the walkabout party should be hurt # h# is ignored if # > number of heroes in walkabout party $0="assert hurt pattern, test no. " append number(0, test no) subscript, consider rank, rank, harm amount, begin if (hero by rank(rank) == -1) then (exit script) # This will break if there are duplicate heroes, a well known flaw variable(slot) slot := find hero(hero by rank(rank)) tracevalue(rank, slot, get hero stat(slot, stat:hp), start hp -- harm amount) assert(get hero stat(slot, stat:hp) == start hp -- harm amount) set hero stat(slot, stat:hp, start hp) end consider rank(0, h0) consider rank(1, h1) consider rank(2, h2) consider rank(3, h3) end script, harm tile tests, begin $0="harm tile tests" # Test harmtile damage walk hero to x(me, 7) walk hero to y(me, 6) wait for hero(me) variable(start hp) start hp := get hero stat(0, stat:hp, current stat) write map block(6, 6, 140, 1) write pass block(6, 6, harmtile) subscript, test damage patterns, begin set caterpillar mode(on) # Turn off "Harm tiles harm non-caterpillar party" (actually the current setting in the .rpg) write general(177, read general(177), and, (-1, xor, 2^12)) # hero is now at tile 7,6, caterpillar is enabled and not suspended, and all heroes have 'start hp' hp # Test damage to individual heroes, caterpillar enabled # also testing crossing over harmtile without stopping walk hero(me, left, 1) wait for hero(me), _checkpoint # check for flash assert hurt pattern(0, start hp, true, false, false, false) walk hero(me, left, 2) wait for hero(me), _checkpoint assert hurt pattern(1, start hp, false, true, true, false) # Test damage to individual heroes, caterpillar suspended suspend caterpillar walk hero(1, right, 1) # step onto harm tile walk hero(2, down, 1) # step off harm tile walk hero(3, left, 1) # step onto harm tile wait for hero(2) assert hurt pattern(2, start hp, false, true, false, true) # Test damage to whole party, caterpillar disabled # (Leader walks back and forth over the tile) set caterpillar mode(off) walk hero(me, right, 3) # two tiles onto harm, then one off wait for hero(me) # "Harm tiles harm non-caterpillar party" is off assert hurt pattern(3, start hp, true, false, false, false) # Turn on "Harm tiles harm non-caterpillar party" write general(177, read general(177), or, 2^12) walk hero(me, left, 2) wait for hero(me) assert hurt pattern(4, start hp, true, true, true, true) # Check this makes no difference resume caterpillar walk hero(me, right, 2) wait for hero(me) assert hurt pattern(5, start hp, true, true, true, true) end # Test with four heroes in the party trace($99="First harmtile test run") test damage patterns # Move hero back to 7,6 set hero position(me, 11, 6) walk hero to x(me, 7) wait for hero(me) # Test party and walkabout slots not matching trace($99="Second harmtile test run") swap by position(0, 20) # remove leader test damage patterns # Test damage value set harm tile damage(2) walk hero(me, left, 2) wait for hero(me) assert hurt pattern(6, start hp, 2, 2, 2, 2) # Test death test harm tile death(start hp) # Cleanup write map block(6, 6, 0, 1) write pass block(6, 6, 0) swap by position(0, 20) # return leader set caterpillar mode(on) set harm tile damage(1) # restore # Caterpiller on and resumed, all heroes have 'start hp' hp end ######################################################################## script, menu tests, begin $0="menu tests" variable(i, m, mi, main, m1) m := create menu, w if(get menu id(m) <> -1) then($0="get menu id should have reported -1 for script-generated menu", crash) mi := add menu item(m), w $1="Puppies" set menu item caption(mi, 1), w mi := add menu item(m), w $1="Kittens" set menu item caption(mi, 1), w mi := add menu item(m), w $1="Walruses" set menu item caption(mi, 1), w mi := add menu item(m), w $1="Octopus" set menu item caption(mi, 1), w mi := add menu item(m), w $1="Plip" set menu item caption(mi, 1), w main := open menu, w bring menu forward(bottom menu), w for(i, align:left, align:right) do( set menu anchor x(m, i), w if(get menu anchor x(m) <> i) then($0="menu anchor x", crash) set menu anchor y(m, i), w if(get menu anchor y(m) <> i) then($0="menu anchor y", crash) ) $1="Puppies" mi := find menu item caption(m, 1) if(mi == 0) then($0="failed to find first menu item by caption", crash) get menu item caption(mi, 2) if(not(string compare(1, 2))) then($0="found menu item that was not puppies", crash) $1="Walruses" mi := find menu item caption(m, 1) get menu item caption(mi, 2) if(not(string compare(1, 2))) then($0="found menu item that was not walruses", crash) mi := find menu item caption(m, 1, mi) #search for Walruses starting after Walruses if(mi <> 0) then($0="find menu item walrus should have failed", crash) mi := add menu item(m) $1="Kittens" set menu item caption(mi, 1), w variable(kitten1, kitten2, walruses) #search for Kitten from top $1="Kittens" kitten1 := find menu item caption(m, 1) #search for Kitten starting after Walruses $2="Walruses" walruses := find menu item caption(m, 2) kitten2 := find menu item caption(m, 1, walruses) if(kitten1 == 0) then($0="failed to find first kitten", crash) if(kitten2 == 0) then($0="failed to find second kitten", crash) get menu item caption(kitten1, 2) if(not(string compare(1, 2))) then($0="found menu item that was not kitten(1)", crash) get menu item caption(kitten2, 2) if(not(string compare(1, 2))) then($0="found menu item that was not kitten(2)", crash) if(kitten1 == kitten2) then($0="found the same kitten twice", crash) mi := add menu item(m), w delete menu item(mi), w $1="Kittens" mi := find menu item caption(m, 1) delete menu item(mi), w mi := first menu item(m) delete menu item(mi), w if(find menu ID(1) <> 0) then($0="found unopened menu", crash) open menu(1),w m1 := find menu ID(1) if(get menu ID(m1) <> 1) then($0="get menu ID mismatch vs find menu", crash) if(m1 == 0) then($0="failed to find opened menu", crash) close menu(m1),w for(i, -3, 12) do( set menu border(main, i), w ) if(get menu border(main) <> 12) then($0="readback of menu border thickness failed", crash) for(i, 0, 10) do( set menu boxstyle(main, i) ) if(get menu boxstyle(main) <> 10) then($0="readback of menu boxstyle failed", crash) for(i, 0, 15) do( set menu max chars(main, i), w if(get menu max chars(main) <> i) then($0="readback of menu max chars failed", crash) ) set menu max chars(main, 0), w for(i, 10, 30) do( set menu min chars(main, i), w if(get menu min chars(main) <> i) then($0="readback of menu min chars failed", crash) ) set menu min chars(main, 0), w for(i, -50, 50, 10) do( set menu offset x(main, i), w if(get menu offset x(main) <> i) then($0="readback of menu offset x failed", crash) set menu offset y(main, i), w if(get menu offset y(main) <> i) then($0="readback of menu offset y failed", crash) ) set menu offset x(main, 0) set menu offset y(main, 0) for(i, align:left, align:right) do( set menu anchor x(main, i), w if(get menu anchor x(main) <> i) then($0="readback of menu anchor x failed", crash) set menu anchor y(main, i), w if(get menu anchor y(main) <> i) then($0="readback of menu anchor y failed", crash) ) set menu anchor x(main, 0), w set menu anchor y(main, 0), w for(i, align:left, align:right) do( set menu text align(main, i), w if(get menu text align(main) <> i) then($0="readback of menu text align failed", crash) ) set menu text align(main, 0), w set menu bit(main, 0, true), w #Transparent box if(get menu bit(main, 0) <> true) then($0="failed to set menu bit", crash) set menu bit(main, 0, false), w #Opaque box if(get menu bit(main, 0) <> false) then($0="failed to unset menu bit", crash) variable(save rows) save rows := get menu max rows(main) set menu max rows(main, 3), w set menu bit(main, 1, true), w #never show scrollbar set menu bit(main, 1, false), w #show scrollbar set menu max rows(main, save rows) set menu bit(main, 4, true), w #no box set menu bit(main, 4, false), w #show box set menu bit(main, 8, true), w #Advance text box when menu closes show text box(6), w if(not(menu is open(main))) then($0="why isn't the main menu open?", crash) close menu(top menu), w close menu(main), w if(current text box <> -1) then($0="menu bit failed to close textbox", crash) if(menu is open(main)) then($0="why is the main menu still open?", crash) variable(antelope, buffalo, catbus, duiker) m := create menu, w antelope := add menu item(m), $0="Antelope", set menu item caption(antelope, 0), w buffalo := add menu item(m), $0="Buffalo", set menu item caption(buffalo, 0), w catbus := add menu item(m), $0="Catbus", set menu item caption(catbus, 0), w duiker := add menu item(m), $0="Duiker", set menu item caption(duiker, 0), w # Hide when disabled set menu item bit(catbus, 0, true), w if(get menu item bit(catbus, 0) <> true) then($0="menu item bit readback failed", crash) # Disable now set menu item type(catbus, menutype:label) set menu item subtype(catbus, 1), w # Don't hide set menu item bit(catbus, 0, false), w # Re-enable set menu item subtype(catbus, 0), w set menu item settag(catbus, 3) if(get menu item settag(catbus) <> 3) then($0="menu item settag readback failed", crash) if(check tag(3)) then($0="tag 3 shouldn't be on yet (menu)", crash) use menu item(catbus), w if(not(check tag(3))) then($0="tag 3 shouldn't be on now (menu)", crash) set menu item settag(catbus, 0) set menu item togtag(catbus, 3) use menu item(catbus), w if(check tag(3)) then($0="tag 3 should be toggled off (menu)", crash) use menu item(catbus), w if(check tag(3)==OFF) then($0="tag 3 should be toggled on (menu)", crash) use menu item(catbus), w if(check tag(3)) then($0="tag 3 should be toggled off again (menu)", crash) set menu item togtag(catbus, 0) for(i, 1, 2) do( set menu item tag(catbus, -3, i), w if(get menu item tag(catbus, i) <> -3) then($0="menu item tag readback failed", crash) set tag(3, ON), w set menu item tag(catbus, 3, i), w set tag(3, OFF), w set menu item tag(catbus, 0, i), w ) $0="menu item tag req", show string(0) for(i, 1, 2) do( set tag(3, OFF) if(get menu item tag(catbus, i) <> 0) then($0="menu item tag req should be zero:", append number(0, i), crash) set menu item tag(catbus, 3, i), w if(get menu item tag(catbus, i) <> 3) then($0="menu item tag req readback fail:", append number(0, i), crash) set tag(3, ON), w set menu item tag(catbus, -3, i), w set tag(3, OFF), w set menu item tag(catbus, 0, i), w ) show no value for(i, 0, 2) do( set menu item extra(buffalo, i, (i + 1) * 10) if(get menu item extra(buffalo, i) <> (i + 1) * 10) then($0="menu item extra readback failed", crash) ) set menu item type(catbus, menutype: special) $0="" # use default caption set menu item caption(catbus, 0), w for (i, 0, 13) do( set menu item subtype(catbus, i), w ) $0="Catbus, not Save" set menu item caption(catbus, 0), w $0="" set menu item caption(catbus, 0), w set menu item type(catbus, menutype:menu), w for(i, 0, 2) do( set menu item subtype(catbus, i), w if(get menu item subtype(catbus) <> i) then($0="menu item subtype readback failed", crash) ) $0="Catbus" set menu item caption(catbus, 0), w # open another menu set menu item type(catbus, menutype:menu) set menu item subtype(catbus, 2) use menu item(catbus), w if(get menu id(top menu) <> 2) then($0="Failed to open a menu from a menu", crash) close menu(top menu), w # open a text box set menu item type(catbus, menutype:textbox) set menu item subtype(catbus, 7) use menu item(catbus), w if(current textbox <> 7) then($0="Failed to open a text box from a menu", crash) advance text box, w if(get menu item type(catbus) <> menutype:textbox) then($0="menu item type readback failed", crash) set menu item type(catbus, menutype:label) # run a script from a menu set menu item type(catbus, menutype:script) set menu item subtype(catbus, @on menu item use) use menu item(catbus), w if(menu item script global <> 99) then($0="Failed to run a script from a menu", crash) variable(oldcol) oldcol := get menu textcolor(m) for(i, 0, 10) do( set menu textcolor(m, i * 13), w if(get menu textcolor(m) <> i * 13) then($0="menu textcolor readback failed", crash) ) set menu textcolor(m, oldcol) # iterate all menu items variable(count) count := 0 mi := first menu item(m) while(mi) do( count += 1 mi := next menu item(mi) ) if(count <> 4) then($0="iterated wrong number of menu items (all)") # now hide catbus set menu item bit(catbus, menu item bit:hide when disabled, true) set menu item tag(catbus, 3) set tag(3, OFF) # iterate all except hidden count := 0 mi := first menu item(m) while(mi) do( count += 1 mi := next menu item(mi, true) ) if(count <> 3) then($0="iterated wrong number of menu items (vis only)") # iterate all including hidden count := 0 mi := first menu item(m) while(mi) do( count += 1 mi := next menu item(mi, false) ) if(count <> 4) then($0="iterated wrong number of menu items (vis only)") # close when selected set menu item bit(antelope, 1, true) use menu item(antelope), w if(top menu == m) then($0="Even Toed Ungulate menu failed to close", crash) menu close global := 0 m := create menu, w mi := add menu item(m) $1="close me" set menu item caption(mi, 1), w set menu item bit(mi, menu item bit:close menu when selected, true) set menu on close script(m, @on close menu test) if(get menu on close script(m) <> @on close menu test) then($0="menu close script readback failed", crash) use menu item(mi), w if(menu close global <> 99) then($0="menu close script didn't run", crash) # Test background highlight w(2) m := create menu, w mi := add menu item(m), w set menu item caption(mi, $1="Lorem"), w mi := add menu item(m), w set menu item caption(mi, $1="Ipsum"), w mi := add menu item(m), w set menu item caption(mi, $1="Dolor"), w mi := add menu item(m), w set menu item caption(mi, $1="Sit"), w mi := add menu item(m), w set menu item caption(mi, $1="Amet"), w assert(get menu bit(m, menubit:highlight selection background) == false) set menu bit(m, menubit:highlight selection background), w assert(get menu bit(m, menubit:highlight selection background) == true) mi := first menu item(m) while(mi) do( mi := next menu item(mi, true) if(mi) then(select menu item(mi)) w(2) ) w close menu(m),w # Test closing a textbox by closing the menu m := create menu, w mi := add menu item(m), w set menu item caption(mi, $1="Twas brillig"), w mi := add menu item(m), w set menu item caption(mi, $1="And the slithy toaves..."), w assert(get menu bit(m, menubit:advance text box when menu closes) == false) show text box(2),w # first, closing the menu should not close the textbox by default close menu(m),w assert(current text box == 2) advance text box, w assert(current text box == -1) # Now do it again... m := create menu, w mi := add menu item(m), w set menu item caption(mi, $1="Did gyre and gimbal"), w mi := add menu item(m), w set menu item caption(mi, $1="In the wabe..."), w assert(get menu bit(m, menubit:advance text box when menu closes) == false) set menu bit(m, menubit:advance text box when menu closes), w assert(get menu bit(m, menubit:advance text box when menu closes) == true) show text box(2),w # This time, closing the menu should close the textbox too close menu(m),w assert(current text box ==-1) menu scroll tests end script, on menu item use, begin menu item script global := 99 end script, on close menu test, begin menu close global := 99 end script, scroll through menu, menu, numitems, begin variable (i, j, mi) # test scrolling for (i, 1, 3, 2) do ( set menu max rows(menu, i) # forwards mi := first menu item(menu) while (mi) do ( select menu item(mi), w mi := next menu item(mi) ) # backwards mi := menu item by slot(menu, numitems -- 1) while (mi) do ( select menu item(mi), w mi := previous menu item(mi) ) # randomly for (j, 0, 4) do ( select menu item(menu item by slot(menu, random(0, numitems -- 1))), w ) ) set menu max rows(menu, 0) end script, menu scroll tests, begin $0="menu scroll tests" variable (main, mi, next, i, numitems) main := open menu, w set menu bit(main, 1, false), w #show scrollbar allow minimap(true), w #make sure there are no hidden items allow save anywhere(true), w # test menu item iteration mi := first menu item(main) while (mi) do ( get menuitemcaption(mi, err arg string) #trace(err arg string) appendnumber(err arg string, numitems) assert (menu item slot(mi) == numitems) assert (menu item by slot(main, numitems, true) == mi) assert (menu item by slot(main, numitems, false) == mi) assert (menu item true slot(mi) == numitems) assert (menu item by true slot(main, numitems) == mi) next := next menu item(mi, false) if (next) then ( assert (mi == previous menu item(next)) ) set menu item extra(mi, 0, numitems) mi := next numitems += 1 ) $err arg string="" # menu item iteration edge cases assert (previous menu item(first menu item(main)) == 0) assert (next menu item(menu item by slot(main, numitems -- 1)) == 0) assert (menu item by slot(main, numitems, true) == 0) assert (menu item by slot(main, numitems, false) == 0) assert (menu item by slot(main, -1) == 0) assert (menu item by true slot(main, -1) == 0) assert (menu item by true slot(main, numitems) == 0) # test "select menu item" mi := first menu item(main) while (mi) do ( select menu item(mi), w assert (selected menu item(main) == mi) mi := next menu item(mi) ) # test scrolling scroll through menu(main, numitems) # check hidden items sorted to end: # 1. hide three items set tag(3, OFF) variable(hidden1, hidden2, hidden3) hidden3 := menu item by slot(main, 4) set menu item bit(hidden3, menu item bit: hide when disabled, true) set menu item tag(hidden3, 3, 1) hidden1 := menu item by slot(main, 0) set menu item bit(hidden1, menu item bit: hide when disabled, true) set menu item tag(hidden1, 3, 1) hidden2 := menu item by slot(main, 3) set menu item bit(hidden2, menu item bit: hide when disabled, true) set menu item tag(hidden2, 3, 1) w # 2. add new item mi := add menu item(main) set menu item extra(mi, 0, numitems) numitems += 1 $1="a new item!" set menu item caption(mi, 1), w # 3. check visible items in correct order variable (temp, extra, mi2) temp := -1 for (i, 0, num items -- 3 -- 1) do ( mi := menu item by slot(main, i, true) mi2 := menu item by slot(main, i, false) assert (mi == mi2) extra := get menu item extra(mi2, 0) if (extra <= temp) then ($0="menu items not in increasing order", crash) temp := extra ) # 4. check hidden items at end in correct order if (menu item by slot(main, numitems -- 3, true) <> 0) then ($0="menuitembyslot returned hidden item", crash) if (menu item by slot(main, numitems -- 3, false) <> hidden1) then ($0="hidden items out of order", crash) if (menu item by slot(main, numitems -- 2, false) <> hidden2) then ($0="hidden items out of order", crash) if (menu item by slot(main, numitems -- 1, false) <> hidden3) then ($0="hidden items out of order", crash) assert (menu item by slot(main, numitems, false) == 0) # 5. check "true order" hasn't changed for (i, 0, num items -- 1) do ( mi := menu item by true slot(main, i) assert (menu item true slot(mi) == i) assert (get menu item extra(mi, 0) == i) ) # test scrolling again scroll through menu(main, numitems -- 3) # check unhidden menu items sorted back correctly set tag(3, ON), w for (i, 0, numitems -- 1) do ( mi := menu item by slot(main, i, false) assert (mi == menu item by slot(main, i, true)) assert (get menu item extra(mi, 0) == i) ) close menu(main) end #next menu(menu handle) #open menu (ID, allow duplicate) #parent menu(menu item handle) #previous menu(menu handle) #swap menu items(handle1, handle2) #wait for menu (menu handle) ######################################################################## script, textbox tests, begin $0="textbox tests" show text box(2), w advance text box, w show text box(3), w advance text box, w if(current textbox <> 4) then(crash) advance text box, w show text box(3), w advance text box, w if(current textbox <> 5) then(crash) advance text box, w if(current textbox <> -1) then(crash) w show text box(12), w, advance text box, w show text box(13), w, advance text box, w variable (oldval) oldval := read general(178) # genBits2 assert((oldval, and, 2^2) == 2^2) # "showtextbox happens immediately" is on # check showtextbox isn't delayed show text box(14) assert(checktag(tag:textbox 14 happened) == true) # no wait required before advance advance textbox wait assert(current textbox == -1) settag(tag:textbox 14 happened, false) # check both showtextboxes work show text box(14) show text box(15) assert(checktag(tag:textbox 14 happened) == true) assert(checktag(tag:textbox 15 happened) == true) advance textbox settag(tag:textbox 14 happened, false) settag(tag:textbox 15 happened, false) write general(178, oldval -- 2^2) # "showtextbox happens immediately" OFF # Check currenttextbox still updates immediately show text box(2) assert(current textbox == 2) # wait required before advance wait advance text box assert(current textbox == -1) # check showtextbox is delayed show text box(14) assert(checktag(tag:textbox 14 happened) == false) wait assert(checktag(tag:textbox 14 happened) == true) advance textbox settag(tag:textbox 14 happened, false) # check only last showtextbox works show text box(14) show text box(15) wait assert(checktag(tag:textbox 14 happened) == false) assert(checktag(tag:textbox 15 happened) == true) advance textbox write general(178, oldval) end ######################################################################## script, battle tests, begin # there are some other battle tests in with the timer tests $0="battle tests" set battle countdown (182) assert(get battle countdown == 182) show value(random(1, 999999999)), w force random battle(1) show value(random(1, 999999999)), w # this should remain deterministic after battle show no value, w # attack forces run set tag(tag:Victory, true) assert(fight formation(1) == false), w # sets victory tag assert(check tag(tag:Victory) == false) # attack forces victory assert(fight formation(2) == true), w assert(check tag(tag:Victory) == true) # attack forces exit assert(fight formation(3) == false), w # test tag check: battle should not trigger force random battle(2) assert(last formation <> 4) w(5) fight formation(5) w(5) # Test attacks setting tags. set tag(4, false) set tag(5, false) fight formation(6) w(5) # The first time should NOT set tag 5 because tag 4 was not set assert(not(check tag(5))), w set tag(4, true) fight formation(6) w(5) # The second time SHOULD set tag 5 because tag 4 WAS set assert(check tag(5)), w set tag(6, false) fight formation(7) w(5) # The third one should always turn the tag on because the tag check is 0. assert(check tag(6)), w test battle formation modification end # Formation set should be 1-2 script, force random battle, formation set = 1, begin variable(s, x, y, d) if (formation set == 0) then (formation set := 1) # If run with runscriptbyid # save hero state s := get hero speed(me) x := hero x(me) y := hero y(me) d := hero direction(me) # get the hero ready for forcing the battle set hero speed(0, 20) # Formations 1-3 are at x = 14-16 set hero position(0, 13 + formation set, 9), w # force the battle walk hero(0, north, 1), w # restore hero state set hero speed(me, s) set hero position(me, x, y) set hero direction(me, d) w # Countdown should be in range 40-160 (test this here so we see multiple battles assert(get battle countdown >= 40 && get battle countdown <= 160) end script, force non random battle, begin w fight formation(0) w(2) end plotscript, after battle, begin $0="After battle script:" battle script sequence += 1 append number(0, battle script sequence) trace(0) show string at(0, 0, 0) w hide string(0) end plotscript, instead of battle, form, begin $0="Instead of battle script(" append number(0, form) $0+")" trace(0) w fight formation(form) $0=" finish instead of battle" trace(0) end script, test battle formation modification, begin # Test formation editing commands # use reward gold to keep track of how many enemies are present in each formation variable(orig gold, gold) orig gold := party money gold := party money fight formation(8), w assert(party money == gold + 1) # Add an enemy to the formation add enemy to formation (8, 8, 100, 90, 1) assert(formation slot enemy(8, 1) == 8) assert(formation slot x(8, 1) == 100) assert(formation slot y(8, 1) == 90) gold := party money fight formation(8), w assert(party money == gold + 2) # Fill the empty slots in the formation variable(i) for(i, 2, 7) do( add enemy to formation (8, 8, 100, 90 + i * 20, 1) ) gold := party money fight formation(8), w assert(party money == gold + 8) # remove several enemies, including the original enemy in slot 0 delete enemy from formation (8, 0) delete enemy from formation (8, 1) delete enemy from formation (8, 2) delete enemy from formation (8, 3) w assert(formation slot enemy(8, 0) == -1) assert(formation slot enemy(8, 1) == -1) assert(formation slot enemy(8, 2) == -1) assert(formation slot enemy(8, 3) == -1) gold := party money fight formation(8), w assert(party money == gold + 4) # Test finding an enemy w # an enemy that will not be found assert(find enemy in formation (8, 1, 0) == -1) assert(find enemy in formation (8, 1, get count) == 0) # an enemy that is actually present assert(find enemy in formation (8, 8, 0) == 4) assert(find enemy in formation (8, 8, 3) == 7) assert(find enemy in formation (8, 8, get count) == 4) # Test background changing assert(get formation background(8) == 1) set formation background(8, 0) assert(get formation background(8) == 0) # Test writing song id number show value(get formation song(8)) assert(get formation song(8) == song:silence) set formation song(8, song:same as map) assert(get formation song(8) == song:same as map) set formation song(8, song:tin glazed and noncommutative) assert(get formation song(8) == song:tin glazed and noncommutative) # actually run the battle. We can't test the visuals, but -autosnap will see it fight formation(8), w # Test resetting the formation to default reset formation(8), w assert(get formation background(8) == 1) assert(get formation song(8) == song:silence) assert(find enemy in formation (8, 8, 0) == 0) assert(find enemy in formation (8, 8, get count) == 1) assert(formation slot enemy(8, 0) == 8) assert(formation slot x(8, 0) == 131) assert(formation slot y(8, 0) == 169) show string(string sprintf(2, $1="%dx%d", formation slot x(8, 0), formation slot y(8, 0))), w fight formation(8), w # Test modifying and resetting individual formation slots # Assert original values assert(formation slot enemy(9, 0) == 0) assert(formation slot x(9, 0) == 18) assert(formation slot y(9, 0) == 201) assert(formation slot enemy(9, 1) == -1) assert(formation slot x(9, 1) == 0) assert(formation slot y(9, 1) == 0) # Make changes delete enemy from formation(9, 0) add enemy to formation(9, 8, 50, 190, 1) assert(formation slot enemy(9, 0) == -1) # deleted enemies do not have their x,y deleted, but width/height are no longer included assert(formation slot x(9, 0) == 1) assert(formation slot y(9, 0) == 167) assert(formation slot enemy(9, 1) == 8) assert(formation slot x(9, 1) == 50) assert(formation slot y(9, 1) == 190) fight formation(9) # Reset single slots reset formation slot(9, 0) assert(formation slot enemy(9, 0) == 0) assert(formation slot x(9, 0) == 18) assert(formation slot y(9, 0) == 201) assert(formation slot enemy(9, 1) == 8) assert(formation slot x(9, 1) == 50) assert(formation slot y(9, 1) == 190) reset formation slot(9, 1) assert(formation slot enemy(9, 0) == 0) assert(formation slot x(9, 0) == 18) assert(formation slot y(9, 0) == 201) assert(formation slot enemy(9, 1) == -1) assert(formation slot x(9, 1) == 0) assert(formation slot y(9, 1) == 0) # restore original money set money(orig gold) show no value end ######################################################################## script, enemy tests, begin $0="enemy tests" assert(enemy elemental resist as int(enemy:Data Read Test, 2) == 0) assert(enemy elemental resist as int(enemy:Data Read Test, 15) == -5) # Name get enemy name(enemy:Data Read Test, 1) $2 = "Data read test" assert(string compare(1, 2)) $2 = "Data read test2" set enemy name(enemy:Data Read Test, 2) get enemy name(enemy:Data Read Test, 1) assert(string compare(1, 2)) # Stats assert(get enemy stat(enemy:Data Read Test, stat:HP) == 13) set enemy stat(enemy:Data Read Test, stat:Hits, 6) assert(get enemy stat(enemy:Data Read Test, stat:Hits) == 6) # Other set enemy appearance(enemy:Data Read Test, Enemy:PictureSize, EnemySize:large) assert(get enemy appearance(enemy:Data Read Test, Enemy:PictureSize) == EnemySize:large) assert(get enemy appearance(enemy:Data Read Test, Enemy:Palette) == -1) assert(read enemy data(enemy:Data Read Test, Enemy:Item) == 1) assert(read enemy data(enemy:Data Read Test, Enemy:ItemPercent) == 50) write enemy data(enemy:Data Read Test, Enemy:RareItem, 2) assert(read enemy data(enemy:Data Read Test, Enemy:RareItem) == 2) end ######################################################################## script, timer tests, begin variable(i) allocate timers(32) set timer(31, 10, 1, @timer test 1, 1) show string at(1, 10, 10) w, w, w, w if(read timer(31) <> 6) then($0="read timer failed", crash) w(6), w timer global := 100 set timer(31, 0, 1, @looping timer test, 1) w(11) $err arg string="random" test timer and battle interactions(@force random battle) $err arg string="fight formation" test timer and battle interactions(@force non random battle) $err arg string="" $0="timer interactions with after battle", trace(0) teleport to map(1, 10, 8), w # after battle battle script sequence := 0 test timer and battle interactions(@force random battle) if(battle script sequence <> 3) then($0="(ab) afterbattle should have happened 3 times", crash) $0="timer interactions with instead of battle", trace(0) teleport to map(2, 10, 8), w # instead of battle battle script sequence := 0 test timer and battle interactions(@force random battle) if(battle script sequence <> 0) then($0="(ib) afterbattle should have happened 0 times", crash) $0="timer interactions with after battle + instead of battle", trace(0) teleport to map(3, 10, 8), w # after battle + instead of battle battle script sequence := 0 test timer and battle interactions(@force random battle) if(battle script sequence <> 3) then($0="(ab+ib) afterbattle should have happened 3 times", crash) teleport to map(0, 10, 8), w hide string(1) end script, test timer and battle interactions, trigger battle, begin #regular timer timer global := 0 timer global will become := 1000 set timer(31, 10, 1, @battle timer test, -1, 0) run script by id(trigger battle) if(read timer(31) <= 0) then($0="timer should still be running", crash) if(timer global <> 0) then($0="timer global should still be zero", crash) w(10) if(read timer(31) >> 0) then($0="timer should be done by now", crash) if(timer global <> timer global will become) then($0="timer global didn't change", crash) #timerflag:battle timer global := 0 timer global will become := 2000 set timer(31, 10, 1, @battle timer test, 1, timerflag:battle) run script by id(trigger battle) if(read timer(31) >> 0) then($0="(bat) timer should be done by now", crash) if(timer global <> timer global will become) then($0="(bat) timer global didn't change", crash) #timerflag:battle ,or, timerflag:critical timer global := 0 timer global will become := 3000 set timer(31, 10, 1, @battle timer test, 1, (timerflag:battle,or,timerflag:critical)) set timer(30, 20, 1, @battle timer test, 0, (timerflag:battle)) run script by id(trigger battle) if(read timer(31) >> 0) then($0="(bat+crit) timer should be done by now", crash) if(timer global <> timer global will become) then($0="(bat+crit) timer global didn't change", crash) timer global will become := 4000 if(read timer(30) <= 0) then($0="(bat+crit) second timer should still be running", crash) w(12) if(read timer(30) >> 0) then($0="(bat+crit) second timer should be done by now", crash) if(timer global <> timer global will become) then($0="(bat+crit) timer global didn't change on second timer", crash) timer global := 0 w end script, timer test 1, begin show value(12345) w end script, looping timer test, begin if(timer global <= 0) then(timer global := 0, exit script) set timer(31, 0, 1, @looping timer test, 1) timer global -= 10 show value(timer global) _checkpoint end script, battle timer test, begin timer global := timer global will become $0="battle timer test:" append number(0, timer global) trace(0) show string(0), w end ######################################################################## script, pathfinding tests, begin $0="Pathfinding tests" variable(oldx, oldy, oldmap) oldx := herox(me) oldy := heroy(me) oldmap := current map teleport to map(map:Pathland, 8, 7) start checkpoint timer(4) variable(ref) ref := create NPC(0, 17, 3) pathfind npc to(ref, hero x(me), hero y(me), 1) wait for npc(ref) assert(dist from leader(ref) == 1) pathfind npc to(ref, 8, 3) wait for npc(ref) assert(npc x(ref) == 8) assert(npc y(ref) == 3) # With pacing NPCs in the way create npc(1, 8, 10, right) create npc(1, 8, 11, right) create npc(1, 8, 12, right) create npc(1, 8, 13, right) camera follows npc(ref) pathfind npc to(ref, 10, 16) wait for npc(ref) assert(npc x(ref) == 10) assert(npc y(ref) == 16) # To an unreachable zone destination pathfind npc to(ref, 15, 5, 1) wait for npc(ref) assert(dist from pos(ref, 15, 5) == 2) # Cancelling a walk pathfind npc to(ref, 14, 9) wait for npc(ref) assert(is at pos(ref, 14, 9)) pathfind npc to(ref, 17, 11) wait(10) cancel npc walk(ref) assert(is at pos(ref, 15, 8)) # also test cancelling a regular walk npc walk npc(ref, left, 4) wait(10) cancel npc walk(ref) assert(is at pos(ref, 13, 8)) # cancel a walk mid-step walk npc(ref, right, 3) wait(1) cancel npc walk(ref) assert(npc is walking(ref) == true) # this doesn't become false until the current step finishes wait for npc(ref) assert(npc is walking(ref) == false) assert(is at pos(ref, 14, 8)) # Test obstructed wait with no timeout create npc(2, 9, 8) pathfind npc to(ref, 9, 7) wait(7 * 5) # wait the time it takes to walk 7 steps (will get stuck after 6 steps) assert(is at pos(ref, 10, 8)) walk npc(2, south, 1) wait for npc(ref) assert(is at pos(ref, 9, 7)) # Test npc following npc walk npc(ref, south, 1) wait for npc(1) assert(is at pos(ref, 9, 7)) pathfind npc to(ref, 16, 18) wait(10) npc chases npc(2, ref, false, 10) wait for npc(ref) assert(is at pos(ref, 16, 18)) wait for npc(2) assert(dist from pos(2, 16, 18) == 1) # clean up camera follows hero stop checkpoint timer teleport to map(oldmap, oldx, oldy) end script, is at pos, ref, x, y, begin exit returning(npc x (ref) == x && npc y (ref) == y) end script, dist from leader, ref, begin exit returning(dist from pos(ref, hero x(me), hero y(me))) end script, dist from pos, ref, x, y, begin variable(dx, dy) dx := abs(npc x(ref) -- x) dy := abs(npc y(ref) -- y) exit returning(dx + dy) end ######################################################################## script, door tests, begin $0="Door tests" # preconditions assert(herox(me) == 6) assert(heroy(me) == 6) # querying doors assert(get door x(0) == 8) assert(get door y(0) == 5) assert(door at spot(8, 5) == 0) assert(door at spot(0, 0) == -1) # lots of doors at 0,0 with exists=NO assert(door at spot(1, 1) == 1) # door 1 has no enabled doorlinks assert(get door destination id(0) == 1) assert(get door destination map(0) == 4) assert(door exists(0)) assert(get door destination id(1) == -1) assert(get door destination map(1) == -1) assert(door exists(1)) assert(door exists(3) == false) # using doors walk hero to x(0, 8) wait for hero walk hero to y(0, 5) wait for hero assert(current map == map:door test map) assert(hero x(0) == 4) assert(hero y(0) == 4) walk hero(0, south, 1) wait for hero use door(1) # shouldn't work, disabled by tag assert(hero x(0) == 4) # not triggered walk hero(0, north, 1) wait for hero assert(hero x(0) == 4) # not triggered set tag(tag:door req tag, on) wait assert(hero x(0) == 4) # not triggered by enabling a door underneath you suspend doors walk hero(0, south, 1) wait for hero walk hero(0, north, 1) wait for hero assert(hero x(0) == 4) # not triggered resume doors wait assert(hero x(0) == 4) # door underneath hero not triggered walk hero(0, south, 1) wait for hero walk hero(0, north, 1) wait for hero assert(hero x(0) == 11) # triggered assert(hero y(0) == 4) use door(0) # door underneath hero assert(current map == map:test town) walk hero to y(0, 6) wait for hero walk hero to x(0, 6) wait for hero # querying doors on other maps assert(current map == map:test town) assert(door exists(0, map:Door test map)) assert(not(door exists(2, map:Door test map))) assert(get door x(0, map:Door test map) == 11) assert(get door y(0, map:Door test map) == 4) assert(check tag(7) == on) assert(get door destination id(0, map:Door test map) == 0) assert(get door destination map(0, map:Door test map) == map:Test Town) assert(get door destination id(1, map:Door test map) == 0) assert(get door destination map(1, map:Door test map) == map:Door test map) set tag(7, off) assert(get door destination id(1, map:Door test map) == -1) assert(get door destination map(1, map:Door test map) == -1) set tag(7, on) assert(get door destination id(2, map:Door test map) == -1) assert(get door destination map(2, map:Door test map) == -1) end ######################################################################## # Not defined as a plotscript on purpose script, each-step script, x, y, dir, begin $0="each-step script", trace assert(x == hero x) assert(y == hero y) assert(dir == hero direction) # First to run assert(npc script triggered == 0) assert(map autorun triggered == 0) eachstep triggered += 1 end plotscript, npc triggered script, arg, npc, begin $0="npc triggered script", trace assert(arg == -1) assert(npc == npc reference(6)) # Second to run assert(eachstep triggered == 1) assert(map autorun triggered == 0) npc script triggered += 1 # Should happen immediately (also tested in textbox tests) # and trigger two scripts advance textbox # Fifth to run assert(current textbox == -1) assert(textbox script triggered == 1) assert(map autorun triggered == 1) npc script triggered += 1 end plotscript, textbox advance script, begin $0="textbox advance script", trace assert(current map == 4) assert(hero direction == left) # These should be the correct position on the new map assert(hero x == 11) assert(hero y == 4) # Third to run assert(current textbox == -1) assert(npc script triggered == 1) assert(eachstep triggered == 1) assert(map autorun triggered == 0) textbox script triggered += 1 end # Set on map 4 plotscript, map 4 autorun, arg, begin if (testing script triggers == false) then (exit script) $0="map 4 autorun", trace assert(arg == 42) assert(current map == 4) # Fourth to run assert(textbox script triggered == 1) map autorun triggered += 1 # also set in "map autorun" end script, concurrent script trigger tests, begin $0="concurrent script trigger tests" # Test multiple triggers happening the same tick, and that they all happen in the right order. # This tests both scripts triggered inside and outside the interpreter # Take a step, triggering each-step script and stepping on an NPC, which runs a script, # and opens a textbox, which is advanced, running a script and activating a door which # goes to a map with an autorun script # Preconditions assert(current map == 0) set hero position(0, 6, 6) npc script triggered := 0 map autorun triggered := 0 set eachstep script (@each-step script) testing script triggers := true tick counter slice := create container set slice velocity x(tick counter slice, 1, 1000) assert(ticknumber == 0) assert(get hero speed(me) == 4) create npc(6, hero x -- 1, hero y) walk hero(me, left, 1) wait for hero #Events happen in this order, and scripts should run in reverse #order of triggering: # (step completes) # (npc triggered, opens textbox) # npc script triggered # each step triggered # (interpreter entered) # (npc script calls advancetextbox) # (textbox loaded) # (preparemap called) # autorun triggered # after textbox script triggered # (this script resumes, waitfornpc finishing) #So scripts run in order (all in the same tick): # | each step # | npc # | | autorun # | | textbox # | npc finishes # this script # Sixth to run assert(npc script triggered == 2) assert(textbox script triggered == 1) assert(map autorun triggered == 1) assert(ticknumber == 5) # reset testing script triggers := false free slice(tick counter slice) teleport to map (0, 6, 6) assert(current map == 0) # Incremented by the other map autorun script assert(map autorun triggered == 2) end ######################################################################## script, another eachstep script, begin eachstep triggered += 1 wait for hero end script, yet another eachstep script, begin eachstep triggered += 1 subscript, waiting, begin wait for hero end waiting end script, script double trigger tests, begin $0="script trigger tests" # precondition assert(hero x == 6 && hero y == 6) # Test double triggering of scripts set eachstep script(@another eachstep script) variable (oldval) oldval := read general(101) # genBits assert((oldval, and, 2^10) == 0) # "permit double triggering scripts" is off eachstep triggered := 0 walk hero(me, left, 3) wait for hero # eachstep should only trigger once assert(eachstep triggered == 1) write general(101, oldval + 2^10) # turn on "permit double triggering scripts" eachstep triggered := 0 walk hero(me, right, 3) wait for hero assert(eachstep triggered == 3) set eachstep script(@yet another eachstep script) eachstep triggered := 0 walk hero(me, left, 3) wait for hero assert(eachstep triggered == 3) write general(101, oldval) # turn off "permit double triggering scripts" eachstep triggered := 0 walk hero(me, right, 3) wait for hero # eachstep should should trigger three times because the "waiting" # subscript foils the double trigger check assert(eachstep triggered == 3) set eachstep script(0) assert(hero x == 6 && hero y == 6) end script, script trigger tests, begin concurrent script trigger tests script double trigger tests end ######################################################################## script, slice tests, begin $0="Slice tests" # Extremely unfinished! slice collection tests slice find tests slice tree tests slice correspondence tests # Test rect transparency variable (sl) sl := create rect(100, 100), w assert(slice is rect(sl)) assert(slice type(sl) == slicetype:rect) assert(get rect trans(sl) == trans:solid) assert(get rect fuzziness(sl) == 100) set rect trans(sl, trans:hollow), w assert(get rect trans(sl) == trans:hollow) assert(get rect fuzziness(sl) == 0) set rect fuzziness(sl, 25), w assert(get rect trans(sl) == trans:fuzzy) assert(get rect fuzziness(sl) == 25) set rect fuzziness(sl, 0), w assert(get rect trans(sl) == trans:hollow) assert(get rect fuzziness(sl) == 0) set rect fuzziness(sl, 100), w assert(get rect trans(sl) == trans:solid) assert(get rect fuzziness(sl) == 100) set rect trans(sl, trans:fuzzy), w assert(get rect trans(sl) == trans:fuzzy) assert(get rect fuzziness(sl) == 50) free slice(sl) # Test rect box border and raw box border sl := create rect(99, 99), w set slice x(sl, 10) set slice y(sl, 10) assert(get rect style(sl) == 0) assert(get rect border(sl) == 0) assert(get rect raw border(sl) == border:line) set rect raw border(sl, 0), w assert(get rect style(sl) == -1) assert(get rect border(sl) == border:raw) assert(get rect raw border(sl) == 0) set rect border(sl, border:none), w assert(get rect border(sl) == border:none) assert(get rect raw border(sl) == border:none) set rect border(sl, border:line), w assert(get rect border(sl) == border:line) assert(get rect raw border(sl) == border:line) set rect raw border(sl, 1), w assert(get rect border(sl) == border:raw) assert(get rect raw border(sl) == 1) set rect border(sl, 13), w assert(get rect border(sl) == 13) assert(get rect raw border(sl) == 1) set rect raw border(sl, border:none), w assert(get rect border(sl) == border:none) assert(get rect raw border(sl) == border:none) set rect raw border(sl, border:line), w assert(get rect border(sl) == border:line) assert(get rect raw border(sl) == border:line) free slice(sl) # Test rect style sl := create rect(120, 120, 14), w assert(get rect style(sl) == 14) # Testing that the style is as in the box style editor assert(get rect border(sl) == 14) assert(get rect raw border(sl) == 1) assert(get rect fg col(sl) == 252) assert(get rect bg col(sl) == 65) set rect fg col(sl, 42), w assert(get rect style(sl) == -1) set rect style(sl, 0), w assert(get rect style(sl) == 0) assert(get rect border(sl) == 0) assert(get rect raw border(sl) == border:line) assert(get rect fg col(sl) == 249) assert(get rect bg col(sl) == 33) free slice(sl) # Text slices $2="fee Fi\n \n foe" sl := create text assert(slice is text(sl)) assert(slice type(sl) == slicetype:text) set slice text(sl, 3) get slice text(2, sl) assert(string compare(2, 3)) $2="" $3="" free slice(sl) # Test cloneslice variable(sl2, ch, ch2) sl := get npc slice(next npc reference) set slice extra(sl, extra 2, 42) sl2 := clone slice(sl) assert(next sibling(sl2) == sl) # Check that things got copied assert(slice screen x(sl) == slice screen x(sl2)) assert(slice screen y(sl) == slice screen y(sl2)) assert(get slice extra(sl2, extra 2) == 42) assert(child count(sl) == child count(sl2)) ch := first child(sl) ch2 := first child(sl2) assert(get slice lookup(ch) < 0) assert(get slice lookup(ch2) == 0) # special lookup codes removed free slice(sl2) sl := sprite layer assert(slice type(sl) == slicetype:special) sl2 := clone slice(sl) assert(slice is container(sl2)) # Special slices turn into containers assert(previous sibling(sl) == sl2) assert(child count(sl) == child count(sl2)) free slice(sl2) sl2 := clone slice(sl, false) # recurse == false assert(child count(sl2) == 0) # Didn't recurse free slice(sl2) end ######################################################################## # A lot more could be added to this script, slice collection tests, begin $0="slice collection tests" variable(sl, sl2) # This is a slice collection with the root slice edited sl := load slice collection(0) w assert(sl) assert(parent slice(sl) == sprite layer) # default parent assert(slice is rect(sl) == true) assert(is filling parent(sl) == false) assert(slice x(sl) == -10) assert(slice y(sl) == -20) assert(slice width(sl) == 100) assert(slice height(sl) == 50) assert(get slice visible(sl) == true) assert(get slice extra(sl, 0) == 10) assert(get slice extra(sl, 1) == 20) assert(get slice extra(sl, 2) == 30) assert(get top padding(sl) == 1) assert(get right padding(sl) == 2) assert(get bottom padding(sl) == 3) assert(get left padding(sl) == 4) assert(get slice clipping(sl) == true) assert(get slice lookup(sl) == sli:my root slice) assert(get rect fuzziness(sl) == 48) assert(get rect fg col(sl) == 101) assert(get rect bg col(sl) == 71) assert(get rect style(sl) == -1) assert(get horiz align(sl) == edge:right) assert(get vert align(sl) == edge:middle) assert(get horiz anchor(sl) == edge:right) assert(get vert anchor(sl) == edge:top) assert(slice screen x(sl) == 310) # position of the anchor point assert(slice screen y(sl) == 80) sl2 := lookup slice(sli:some lookup) assert(sl2) assert(parent slice(sl2) == sl) assert(slice is sprite(sl2) == true) assert(get sprite type(sl2) == spritetype:walkabout) assert(get spriteset number(sl2) == 6) assert(get sprite palette(sl2) == 1) assert(get sprite frame(sl2) == 4) assert(get sprite trans(sl2) == false) assert(sprite is horiz flipped(sl2) == true) assert(sprite is vert flipped(sl2) == false) assert(sprite is dissolving(sl2) == false) assert(slice width(sl2) == 20) assert(slice height(sl2) == 20) assert(slice x(sl2) == 10) assert(slice y(sl2) == -4) assert(slice screen x(sl2) == 224) assert(slice screen y(sl2) == 77) free slice(sl) # A simpler collection sl := load slice collection(1) assert(sl) assert(get slice visible(sl) == false) # edited assert(is filling parent(sl) == true) # the default free slice(sl) end ######################################################################## # Unfinished tests of findcollidingslice and sliceatpixel script, slice find tests, begin $0="Slice find tests" variable(parent, sl1, sl2, sl3, sl4, sl5, temp) parent := create select # f put slice (parent, 100, 200) sl1 := create container(0, 0) set parent(sl1, parent) assert(slice at pixel(parent, 0, 0) == 0) # can't be hit assert(slice at pixel(parent, 0, 0, get count) == 0) sl2 := create container(10, 10) set parent(sl2, parent) sl3 := create container(1, 1) set parent(sl3, parent) put slice(sl3, 4, 5) sl4 := create container(1, 1) set parent(sl4, sl3) wait(1) # update select visibility ### Testing slice at pixel # Unfinished: no testing of slices with negative width/height. # Only sl1 should be visible... assert(get slice visible(sl1) == true) assert(get slice visible(sl2) == false) assert(get slice visible(sl3) == false) assert(get slice visible(sl4) == true) assert(slice at pixel(parent, 100, 200) == sl2) # topleft corner assert(slice at pixel(parent, 105, 205) == sl2) # inside assert(slice at pixel(parent, 100, 210) == 0) # on the edge of sl2 assert(slice at pixel(parent, 110, 200) == 0) # on the edge of sl2 assert(slice at pixel(parent, 100, 200, get count) == 1) # sliceatpixel and findcollidingslice must return slices from bottommost to topmost assert(slice at pixel(parent, 104, 205, get count) == 3) assert(slice at pixel(parent, 104, 205, 0) == sl2) assert(slice at pixel(parent, 104, 205, 1) == sl3) assert(slice at pixel(parent, 104, 205, 2) == sl4) assert(slice at pixel(parent, 104, 205, 3) == 0) # now without descending: assert(slice at pixel(parent, 104, 205, get count, false) == 2) assert(slice at pixel(parent, 104, 205, 0, false) == sl2) assert(slice at pixel(parent, 104, 205, 1, false) == sl3) assert(slice at pixel(parent, 104, 205, 2, false) == 0) # test visibleonly assert(slice at pixel(parent, 104, 205, get count, true, true) == 0) # visibility of the 'parent' slice doesn't affect anything (sl3 is not visible) assert(slice at pixel(sl3, 104, 205, get count, true, true) == 1) # change visible slice to sl3 set select slice index(parent, 2) wait(1) # update select visibility assert(get slice visible(sl3) == true) # now sl3 and sl4 should be hit assert(slice at pixel(parent, 104, 205, get count, true, true) == 2) assert(slice at pixel(parent, 104, 205, 0, true, true) == sl3) assert(slice at pixel(parent, 104, 205, 1, true, true) == sl4) # ##Testing find colliding slice # Unfinished: don't yet check all the cases of an AABB collision test. # (Easier to test manually with collisiontest.rpg) # Also, no testing of slices with negative width/height. sl5 := load walkabout sprite(0) assert(slice height(sl5) == 20) put slice(sl5, 100, 190) # sliceatpixel and findcollidingslice must return slices from bottommost to topmost #tracevalue(parent, sl1, sl2, sl3, sl4, sl5) assert(find colliding slice(parent, sl5, get count) == 3) # Don't find sl1 which is zero size (FIXME: which I think probably isn't correct, since "slice contains" would say yes) #assert(find colliding slice(parent, sl5, 0) == sl1) assert(find colliding slice(parent, sl5, 0) == sl2) assert(find colliding slice(parent, sl5, 1) == sl3) assert(find colliding slice(parent, sl5, 2) == sl4) assert(find colliding slice(parent, sl5, 3) == 0) # Test non-overlap of adjacent slices set parent(sl5, parent) put slice(sl5, 0, 5 -- 20) # positioned so sl3 on bottom edge # Create another couple slices adjacent to sl5 on the top and left temp := create container(1, 1) set parent(temp, parent) put slice(temp, -1, 0) # 1 left of sl5 temp := create container(1, 1) set parent(temp, parent) put slice(temp, 0, 5 -- 20 -- 1) # 1 up from sl5 assert(find colliding slice(parent, sl5, 0) == sl2) # doesn't find sl1, zero size assert(find colliding slice(parent, sl5, 1) == 0) # should not find sl3, nor sl5, nor the temp slices # Now overlap by one put slice(sl5, 0, 5 -- 20 + 1) # now sl3 overlaps assert(find colliding slice(parent, sl5, 0) == sl2) # doesn't find sl1, zero size assert(find colliding slice(parent, sl5, 1) == sl3) assert(find colliding slice(parent, sl5, 2) == sl4) assert(find colliding slice(parent, sl5, 3) == 0) # should not find sl5 # try using a 0x0 slice to search for overlaps - should find nothing. # (FIXME: This is probably not correct; as an infinitesimal point it overlaps sl2 and sl5. assert(find colliding slice(parent, sl1, 0) == 0) # Test no descending # Don't find sl1 which is zero size (FIXME: which I think probably isn't correct, since "slice contains" would say yes) assert(find colliding slice(parent, sl5, 0, false) == sl2) assert(find colliding slice(parent, sl5, 1, false) == sl3) assert(find colliding slice(parent, sl5, 2, false) == 0) # shouldn't find sl4 assert(find colliding slice(parent, sl5, get count, false) == 2) # Test visible only (only sl3 is visible) assert(find colliding slice(parent, sl5, get count, true, true) == 2) assert(find colliding slice(parent, sl5, 0, true, true) == sl3) assert(find colliding slice(parent, sl5, 1, true, true) == sl4) assert(find colliding slice(parent, sl5, 2, true, true) == 0) # Do two 0x0 slices at the same point overlap? (they shouldn't) free slice children(parent) temp := create container(0, 0) set parent(temp, parent) temp := create container(0, 0) set parent(temp, parent) assert(find colliding slice(parent, temp, get count) == 0) free slice(parent) end ######################################################################## # Return index of a child of the root slice. script, root child index, lookup code, begin variable(sl) clear string(err arg string) append number(err arg string, lookup code) sl := lookup slice(lookup code) assert(sl) assert(parent slice(sl) == lookup slice(sl:root)) return(slice child indeX(sl)) end # Unfinished, only inspects children of root. # But see also "slice correspondence tests" for NPC & hero slices script, slice tree tests, begin $0="Slice tree tests" assert(sprite layer == lookup slice(sl:script layer)) # Ensure the major slice layers appear in a fixed order. # Probably OK for new slices to get added between these (anyone making assumptions about the n-th # child here may be too much pain to support) variable (scr, map, textbox, backdrop, strings) map := root child index(sl:map root) backdrop := root child index(sl:backdrop) scr := root child index(sl:script layer) textbox := root child index(sl:textbox layer) strings := root child index(sl:string layer) assert(map < backdrop) assert(backdrop < scr) assert(scr < textbox) assert(textbox < strings) end ######################################################################## # This tests commands for converting between slices and hero/npc references script, slice correspondence tests, begin #### Test NPC slices variable(npc, sl, sl2, walkabout layer) walkabout layer := lookup slice(sl:npc layer) npc := next npc reference while (npc) do ( sl := get npc slice(npc) assert(sl) assert(npc reference from slice(sl) == npc) # Should be the top-level walkabout container assert(slice parent(sl) == walkabout layer) assert(slice x(sl) == npc pixel x(npc)) assert(slice y(sl) == npc pixel y(npc)) sl2 := lookup slice(sl:walkabout sprite component, sl) assert(sl2) assert(npc reference from slice(sl2) == 0) npc := next npc reference(npc) ) sl := get hero slice(0) assert(sl && npc reference from slice(sl) == 0) #### Test hero slices # Preconditions assert(hero by slot(0) == hero:Freki) assert(hero by slot(1) == -1) assert(hero by slot(2) == -1) assert(hero by slot(3) == -1) sl := get hero slice(0) assert(sl) assert(slice parent(sl) == lookup slice(sl:hero layer)) assert(slice x(sl) == hero pixel x(0)) assert(slice y(sl) == hero pixel y(0)) assert(hero rank from slice(sl) == 0) assert(lookup slice(sl:walkabout sprite component, sl)) # Defaults to -1 assert(hero rank from slice(get npc slice(next npc reference)) == -1) # Check it returns rank, not party slot swap by position(0, 1) sl := get hero slice(0) assert(sl) assert(hero rank from slice(sl) == 0) # Test rank > 0 add hero(hero:Bram) sl := get hero slice(1) assert(sl) assert(hero rank from slice(sl) == 1) # Test hero slices belonging to non-existent heroes! There are always 4 hero slices!! # I don't really want to lock in this weird behaviour. Probably we should add a general bitset to disable it. sl := get hero slice(2) assert(sl) assert(get slice visible(sl) == false) assert(hero rank from slice(sl) == 2) # Restore delete hero(hero:Bram) swap by position(0, 1) end ######################################################################## define constant(1, zone:center) define constant(2, zone:wholegrass) define constant(3, zone:rightedge) define constant(4, zone:leftedge) define constant(5, zone:everything) define constant(6, zone:topedge) define constant(7, zone:bottomedge) # Equivalent to readzone, but checks it agrees with zoneatspot script, check zone, id, x, y, begin variable(i, what) for (i, 0, zone at spot(x, y, getcount) -- 1) do ( what := zone at spot(x, y, i) assert(what > 0) if (what == id) then ( assert(read zone(id, x, y) == true) exit returning (true) ) ) assert(read zone(id, x, y) == false) return(false) end script, zone tests, begin $0="zone tests" # Could do with more tests of the internal complexities of ZoneMap # Read some existing tiles (green plot of grass) assert(zone at spot(17, 15, getcount) == 3) assert(check zone(1, 17, 15) == 1) assert(check zone(2, 17, 15) == 1) assert(check zone(3, 17, 15) == 0) assert(check zone(5, 17, 15) == 1) assert(zone at spot(16, 16, getcount) == 4) assert(check zone(1, 16, 16) == 0) assert(check zone(2, 16, 16) == 1) assert(check zone(3, 16, 16) == 0) assert(check zone(4, 16, 16) == 1) assert(check zone(5, 16, 16) == 1) assert(check zone(7, 16, 16) == 1) # zone number of tiles assert(zone number of tiles(1) == 1) assert(zone number of tiles(2) == 9) assert(zone number of tiles(5) == 800) assert(zone number of tiles(8) == 0) assert(zone number of tiles(9988) == 0) # Other zone data commands get zone name (95, zone:leftedge) $96="left edge" assert(string compare(95, 96)) assert(get zone extra(5, 0) == 10) assert(get zone extra(5, 1) == -2147483648) assert(get zone extra(5, 2) == 2147483647) # A nonexistent zone get zone name (95, 9000) assert(string length(95) == 0) assert(get zone extra(9000, 0) == 0) assert(get zone extra(9000, 1) == 0) set zone extra (9000, 2, 32) assert(get zone extra(9000, 2) == 32) # Erasing a zone shouldn't affect others on the same tile write zone(1, 17, 15, 0) assert(check zone(1, 17, 15) == 0) assert(check zone(2, 17, 15) == 1) assert(check zone(5, 17, 15) == 1) assert(zone at spot(17, 15, getcount) == 2) write zone(1, 17, 15, 1) assert(check zone(1, 17, 15) == 1) # Write a zone that doesn't exist at all yet write zone(1003, 16, 14, 1) assert(check zone(1003, 16, 14) == 1) variable(idx, idx2, count) # Already 3 zones here; place 15 zones on one tile (the max) count := 3 for (idx, 1001, 1012) do ( write zone(idx, 17, 15, 1) assert(check zone(idx, 17, 15) == 1) count += 1 assert(zone at spot(17, 15, getcount) == count) ) # Remove them again in FIFO order for (idx, 1001, 1012) do ( write zone(idx, 17, 15, 0) assert(check zone(idx, 17, 15) == 0) count -= 1 assert(zone at spot(17, 15, getcount) == count) for (idx2, idx + 1, 1012) do ( assert(check zone(idx2, 17, 15) == 1) ) ) # Check other zones within the same 4x4 block are undisturbed assert(zone at spot(16, 14, getcount) == 5) assert(check zone(1, 16, 14) == 0) assert(check zone(2, 16, 14) == 1) assert(check zone(3, 16, 14) == 0) assert(check zone(4, 16, 14) == 1) assert(check zone(5, 16, 14) == 1) assert(check zone(6, 16, 14) == 1) assert(check zone(1003, 16, 14) == 1) zones randomized test end script, zones randomized test, begin # Do a randomised test of writing and reading zones in a 8x8 area # (four 4x4 blocks) at top-left corner of the map). # The idea is that the zonemap code has a lot of edge cases as a result of # implementation details which are a huge pain to write tests for, and those # tests wouldn't be worth much if the implementation changes. # Unfortunately these tests still aren't worth much; changing the various magic # constants results in them not hitting the edge cases anyway! :( # We check which zones we expect to see in 64 globals which act as bitvectors, # the i-th bit set if that tile should be in zone i. show value(1) wait # Returns true or false. id >= 1 subscript, readarray, id, x, y, begin return((read global(array:zones + x + y * 8) / 2^(id--1)), and, 1) end # id >= 1 subscript, writearray, id, x, y, value, begin variable(bits) bits := read global(array:zones + x + y * 8) bits := bits, and, (-1 -- 2^(id--1)) if (value) then (bits += 2^(id--1)) write global(array:zones + x + y * 8, bits) end # Num zones at tile subscript, array count zones, x, y, begin return(bitcount(read global(array:zones + x + y * 8))) end # Check the whole area is as it should be subscript, test area, begin variable(x, y, id) for (x, 0, 7) do ( for (y, 0, 7) do ( for (id, 1, 31) do ( assert(readarray(id, x, y) == read zone(id, x, y)) ) assert(zone at spot(x, y, getcount) == array count zones(x, y)) ) ) end # Initial state variable(x,y) for (x, 0, 7) do ( for (y, 0, 7) do (writearray(zone:everything, x, y, 1)) ) #test area # Stick to 15 zones in the whole area, so no overflow occurs variable(it, id, newvalue) for (it, 0, 300) do ( show value(it) x := random(0,4) y := random(0,5) id := random(1,15) newvalue := random(0,1000) 0 assert(readarray(id, x, y) == readzone(id, x, y)) writezone(id, x, y, newvalue) writearray(id, x, y, newvalue) if (it, mod, 5 == 0) then (test area) ) show value(2) wait # Now start using more zones, so that overcrowding occurs # But don't use more than 15 per tile for (it, 0, 5000) do ( show value(10000+it) x := random(0,7) y := random(0,3) id := random(1,31) newvalue := random(0,2) > 0 if (newvalue == 1 && array count zones(x, y) == 15) then (continue) assert(readarray(id, x, y) == readzone(id, x, y)) writezone(id, x, y, newvalue) writearray(id, x, y, newvalue) if (it, mod, 200 == 0) then (test area) ) shownovalue wait end ######################################################################## script, maptile tests, begin $0="maptile tests" # Test some tilemap and passmap commands # (Zones are tested separately in 'zone tests', and wallchecking # in 'wallchecking tests' and 'do hero cater tests') # Read some tiles on the left edge of the house (of map 0) assert(read map block(6, 5, 0) == 112) assert(read map block(6, 4, 0) == 96) assert(read map block(6, 4, 1) == 0) assert(read map block(6, 4, 2) == 58) assert(read pass block(6, 5) == westwall + southwall) # Oneway doors assert(read zone(zone:OneWayExit, 4, 10) == 1) assert(read pass block(4, 10) == southwall + northwall) assert(read pass block(5, 10) == southwall) # Write tilemap write map block(3, 2, 255, 1) assert(read map block(3, 2, 1) == 255) resetmapstate(mapstate:tilemap) assert(read map block(3, 2, 1) == 0) # Write passmap write pass block(3, 2, 255) assert(read pass block(3, 2) == 255) write pass block(3, 2, 0) # Test tile animations # An animated tile (water assert(read map block(3, 3, 0) == 192) # animation start tile (tile number, layer) assert(animation start tile (192, 0) == 144) # get tile animation offset (animation pattern, layer) # Second animation pattern isn't used, so this should be zero assert(get tile animation offset(1, 0) == 0) assert(currentdisplaytile(208) == 0) # first tile of the range assert(currentdisplaytile(192) >= 144 && currentdisplaytile(192) <= 147) assert(currentdisplaytile(192) == 144 + get tile animation offset(0, 0)) #set tile animation offset (animation pattern, offset, layer) not tested end ######################################################################## script, wallchecking tests, begin $0="wallchecking tests" # This tests moveslicewithwallchecking and checkwallcollisionx/y commands. # This follows previous tests of basic hero movement ("do hero cater tests") # which check hero movement obeys walls. variable(tilex, tiley) tilex := 6 tiley := 15 # The tile at tilex,tiley is called the center tile # hitbox size variable(hitboxw, hitboxh) variable(hitbox) hitbox := create container set parent(hitbox, lookupslice(sl:map layer 0)) subscript, set hitbox size, wide, high, begin hitboxw := wide hitboxh := high set slice size(hitbox, wide, high) end subscript, testcollide, testnum, x, y, xgo, ygo, expectedx, expectedy, expectedret = -1, begin #show value(testnum) #tracevalue(testnum, x, y, xgo, ygo, expectedx, expectedy) variable(resultx, resulty, ret) # if (false) then ( # resultx := check wall collision x(x, y, hitboxw, hitboxh, xgo, ygo) # resulty := check wall collision y(x, y, hitboxw, hitboxh, xgo, ygo) # ) else ( putslice(hitbox, x, y) ret := moveslicewithwallchecking(hitbox, xgo, ygo) resultx := slicex(hitbox) -- x resulty := slicey(hitbox) -- y # ) #tracevalue(resultx, resulty) if (expectedret <> -1) then ( #trace(string sprintf(98, $99="ret: %b wanted %b", ret, expectedret)) assert(ret == expectedret) ) assert(resultx == expectedx) assert(resulty == expectedy) end # Test 45 degree and near-45 degree collisions with one of the 4 corners of the center tile # cornerx and cornery are 0 or 1 for left/up or right/bottom, # and also possibly the far corner if there are no walls at the first one. subscript, test corner, cornerx, cornery, cornermask, begin #tracevalue(cornerx, cornery) # The four walls of the center tile variable(wall up, wall left, wall right, wall down) wall left := (readpassblock(tilex, tiley), and, westwall) || (readpassblock(tilex--1, tiley), and, eastwall) wall right := (readpassblock(tilex, tiley), and, eastwall) || (readpassblock(tilex+1, tiley), and, westwall) wall up := (readpassblock(tilex, tiley ), and, northwall) || (readpassblock(tilex, tiley--1), and, southwall) wall down := (readpassblock(tilex, tiley ), and, southwall) || (readpassblock(tilex, tiley+1 ), and, northwall) # whether there is a wall on the vertical or horizontal side of # the center tile adjacent to the corner variable(vside, hside, far vside, far hside) if (cornerx == 0) then ( vside := wall left far vside := wall right ) else ( vside := wall right far vside := wall left ) if (cornery == 0) then ( hside := wall up far hside := wall down ) else ( hside := wall down far hside := wall up ) # position in pixels of the corner variable(x, y) x := (tilex + cornerx) * 20 y := (tiley + cornery) * 20 # Convert to position of (top-left of) collider when at the corner if (cornerx == 0) then (x -= hitboxw) if (cornery == 0) then (y -= hitboxh) # Distance moved by collider before reaching corner variable(strikedist) strikedist := 22 # should be >= 2 # 1 or -1, the sign of xgo/ygo of the collider variable(xgodir, ygodir) if (cornerx == 0) then (xgodir := 1) else (xgodir := -1) if (cornery == 0) then (ygodir := 1) else (ygodir := -1) # xgo/ygo are 10 pixels beyond the corner variable(xgo, ygo) xgo := xgodir * 2 * strikedist #(10 + strikedist) ygo := ygodir * 2 * strikedist #(10 + strikedist) # start position of collider (top-left), in pixels variable(startx, starty) startx := x -- xgodir * strikedist starty := y -- ygodir * strikedist if (vside || hside) then ( # Hit the corner at 45 degree testcollide(1, startx, starty, xgo, ygo, xgodir * strikedist, ygodir * strikedist, cornermask) # Move parallel to the corner, so we miss it by 1 pixel, but still at 45 degree testcollide(2, startx + xgodir, starty, xgo, ygo, xgodir * strikedist, ygodir * strikedist) testcollide(3, startx, starty + ygodir, xgo, ygo, xgodir * strikedist, ygodir * strikedist) # Try angles slightly above and below 45 degree but which still hit the corner at the same time testcollide(4, startx+1, starty, xgo -- 2, ygo, xgodir * strikedist -- 1, ygodir * strikedist, cornermask) testcollide(5, startx, starty+1, xgo, ygo -- 2, xgodir * strikedist, ygodir * strikedist -- 1, cornermask) testcollide(6, startx--1, starty, xgo + 2, ygo, xgodir * strikedist + 1, ygodir * strikedist, cornermask) testcollide(7, startx, starty--1, xgo, ygo + 2, xgodir * strikedist, ygodir * strikedist + 1, cornermask) # Hit the corner in one axis a fraction of a pixel before the other testcollide(8, startx+1, starty, xgo -- 1, ygo, xgodir * strikedist -- 1, ygodir * strikedist, cornermask) testcollide(9, startx--1, starty, xgo + 1, ygo, xgodir * strikedist + 1, ygodir * strikedist, cornermask) testcollide(10, startx, starty -- 1, xgo, ygo + 1, xgodir * strikedist, ygodir * strikedist + 1, cornermask) testcollide(11, startx, starty + 1, xgo, ygo -- 1, xgodir * strikedist, ygodir * strikedist -- 1, cornermask) ) else if (strikedist > 20 && (far vside || farhside)) then ( # Pass through the corner, but hit a wall on the opposite side variable(expectx, expecty, expect ret) expectx := xgodir * (strikedist+20) expecty := ygodir * (strikedist+20) # Hit the inside corner at 45 degree if (far vside) then ( if (cornerx == 0) then (expectret += eastwall) else (expectret += westwall) ) if (far hside) then ( if (cornery == 0) then (expectret += southwall) else (expectret += northwall) ) testcollide(20, startx, starty, xgo, ygo, expectx, expecty, expectret) # Hit the inside corner in one axis a fraction of a pixel before the other testcollide(21, startx + 1, starty, xgo -- 1, ygo, expectx -- 1, expecty) testcollide(22, startx -- 1, starty, xgo + 1, ygo, expectx + 1, expecty) testcollide(23, startx, starty + 1, xgo, ygo -- 1, expectx, expecty -- 1) testcollide(24, startx, starty -- 1, xgo, ygo + 1, expectx, expecty + 1) ) else ( # Hit no walls testcollide(30, startx, starty, xgo, ygo, xgo, ygo, 0) ) end # Some simple manually written test configurations # The tile at tilex,tiley has walls on all sides variable(x,y) x := tilex*20 y := tiley*20 set hitbox size(10, 10) testcollide(100, x--20, y--5, 20, 0, 10, 0, eastwall) # hit wall from west testcollide(101, x+40, y--5, -40, 0, -20, 0, westwall) # ...east testcollide(102, x--5, y--15, 0, 20, 0, 5, southwall) # ...north testcollide(103, x--5, y+35, 0, -20, 0, -15, northwall) # ...south # Diagonal movement that hits the corner in one axis a fraction of a pixel # before the other axis variable(hitx, hity) # position of the the corner to hit hitx := tilex*20 + 20 hity := tiley*20 + 20 testcollide(110, hitx + 2, hity + 3, -5, -6, -2, -3, northwest corner) testcollide(111, hitx + 3, hity + 2, -6, -5, -3, -2, northwest corner) hitx := tilex*20 -- hitboxw testcollide(112, hitx -- 3, hity + 2, 6, -5, 3, -2, northeast corner) testcollide(113, hitx -- 2, hity + 3, 5, -6, 2, -3, northeast corner) hity := tiley*20 -- hitboxh testcollide(114, hitx -- 3, hity -- 2, 6, 5, 3, 2, southeast corner) testcollide(115, hitx -- 2, hity -- 3, 5, 6, 2, 3, southeast corner) # Test collision with the ends and center of a large hitbox (only x axis) set hitbox size(1, 58) variable(dx) # the sign of xgo (whether hit from left or right) variable(expected) # expected return value (wall mask) for(dx, 1, -1, -2) do ( x := tilex*20 if (dx == 1) then (x -= 10 + hitboxw) else (x += 10 + 20) if (dx == 1) then (expected := eastwall) else (expected := westwall) testcollide(104, x, y--19,dx*30, 9, dx*10, 3, expected) # hitting with the center of the hitbox testcollide(105, x, y+9, dx*30, 30, dx*10, 10, expected) # just hit the corner w/ the top by 1 pixel testcollide(106, x, y+10, dx*30, 30, dx*30, 30, 0) # just miss testcollide(107, x, y--47,dx*30, -30, dx*10, -10, expected) # just hit the corner w/ the bottom by 1 pixel testcollide(108, x, y--58,dx*30, -30, dx*30, -30, 0) # just miss ) # Test hitting diagonal hits of corners of various wall configurations walls. # We test multiple hitbox sizes, but we're not actually doing a serious test of that for (hitboxw, 10, 30, 10) do ( for (hitboxh, 10, 30, 10) do ( set hitbox size(hitboxw, hitboxh) variable(tt, walls) tt := microseconds # Try all possible walls on the center tile for (walls, 15, 0, -1) do ( #tracevalue(hitboxw, hitboxh, walls, 1) write pass block(tilex, tiley, walls) testcorner(0,0, southeast corner) testcorner(0,1, northeast corner) testcorner(1,0, southwest corner) testcorner(1,1, northwest corner) ) # Test walls in the same places, but on the adjacent 4 tiles instead for (walls, 15, 0, -1) do ( #tracevalue(hitboxw, hitboxh, walls, 2) write pass block(tilex+1, tiley, walls,and,westwall) write pass block(tilex, tiley+1, walls,and,northwall) write pass block(tilex--1, tiley, walls,and,eastwall) write pass block(tilex, tiley--1, walls,and,southwall) testcorner(0,0, southeast corner) testcorner(0,1, northeast corner) testcorner(1,0, southwest corner) testcorner(1,1, northwest corner) ) ) ) tracevalue(microseconds--tt) show no value free slice(hitbox) end ######################################################################## script, save slot tests, begin $0="save slot tests" # This includes tests for commands which operate on save slots, # but doesn't test load saves itself; that's in "savegame tests" delete save(1) assert(save slot used(1) == false) # import/export globals export global 1 := -123456789 export globals(1, @export global 1, @export global 1) export global 1 := -2 assert(import globals(1, @export global 1) == -123456789) assert(export global 1 == -2) import globals(1, @export global 1, @export global 2) assert(export global 1 == -123456789) assert(export global 2 == 0) export global 2 := -100 export globals(1, @export global 2, @export global 2) save in slot(2) export global 1 := 0 export global 2 := 0 export globals(1, @export global 1, @export global 2) export global 1 := 100 export global 2 := 100 import globals(1, @export global 1, @export global 2) assert(export global 1 == 0) assert(export global 2 == 0) # high global id numbers # (Export this to slot 3 so I can inspect autotest.saves/2.rsav) the global with the biggest id := 123 assert(the global with the biggest id == 123) assert(@the global with the biggest id == 50000) export globals(3, @the global with the biggest id, @the global with the biggest id) write global(@the global with the biggest id, 321) assert(import globals(3, @the global with the biggest id) == 123) assert(the global with the biggest id == 321) # exporting globals should not cause a slot to appear as used assert(save slot used(1) == false) assert(save slot used(2) == true) # testing saveinslot earlier import globals(2, @export global 1, @export global 2) assert(export global 1 == -123456789) assert(export global 2 == -100) # different form export global 1 := -3 assert(import globals(2, @export global 1, @export global 1) == 0) assert(export global 1 == -123456789) # loading from nonexistent save... it's not actually specified # what's meant to happen, but this is reasonable import globals(3, @export global 1, @export global 2) assert(export global 1 == 0) assert(export global 2 == 0) # delete save is meant to preserve stored global variables (FAILS!!) delete save(1) delete save(2) assert(save slot used(1) == false) assert(save slot used(2) == false) export global 1 := -1 export global 2 := -2 #import globals(1, @export global 1, @export global 2) #assert(export global 1 == 0) #assert(export global 2 == 0) #import globals(2, @export global 1, @export global 2) #assert(export global 1 == -123456789) #assert(export global 2 == -100) end ######################################################################## script, string load tests, begin $0="string load tests" $1="SelfStab" read attack name(2, 0 + 1) assert(string compare(1,2)) $1="Attack self" get attack caption(2, 0 + 1) assert(string compare(1,2)) embedding global := -1234 $3=" " # Test the obsolete stringfromtextbox: 4th arg ignored stringfromtextbox(1, 8, 2) $2="." assert(string compare(1, 2)) stringfromtextbox(1, 8, 3) $2="" assert(string compare(1, 2)) stringfromtextbox(1, 8, 4) $2="##" assert(string compare(1, 2)) stringfromtextbox(1, 8, 5, false) $2=",-1234. , " assert(string compare(1, 2)) stringfromtextbox(1, 8, 5, true) assert(string compare(1, 2)) # textbox line textboxline(1, 8, 2) $2="." assert(string compare(1, 2)) textboxline(1, 8, 3) $2="" assert(string compare(1, 2)) textboxline(1, 8, 4) $2=" ## " assert(string compare(1, 2)) textboxline(1, 8, 4, true, false) assert(string compare(1, 2)) textboxline(1, 8, 4, true, true) $2="##" assert(string compare(1, 2)) textboxline(1, 8, 5, false) $2=" ,${V105}. ,${S3} " assert(string compare(1, 2)) textboxline(1, 8, 5, true) $2=" ,-1234. , " assert(string compare(1, 2)) textboxline(1, 8, 5, true, true) $2=",-1234. , " assert(string compare(1, 2)) # textbox text $2=" This box is for testing textboxline\n and stringfromtextbox\n.\n\n ## \n ,-1234. , " textboxtext(1, 8, true, false) assert(string compare(1, 2)) end ######################################################################## script, savegame tests, begin $0="saving/loading tests 1" trace(0) # Partially split into savegame tests 2 # Preconditions assert(current map == 0) delete save(1) assert(save slot used(1) == false) savegame map := current map savegame slice := create rect(15, 20) put slice(savegame slice, 40, 40) savegame npc := createnpc(0, 5, 5) # Saving of string state # There are no commands to return the current colour and style # of a string (and I don't see any need to add them), so that can only be # tested by screenshot. $5 = "This is a green string" show string at(5, 100, 100) string color(5, 72) # Should default to 'string:outline' style $6 = "This is flat yellow-on-purple" show string at(6, 100, 110) string style(6, string:flat) string color(6, 14, 194) # yellow, purple $7="This should be plain style" show string at(7, 100, 120) w hook loadgame := 1 save in slot(1) hook loadgame := 0 assert(save slot used(1) == true) # Change state a bit to check it's actually reset and loaded hide string(5) $5 = "" $6 = "Now it's plain" string color(6) $7 = "Now it's yellow-on-purple" string style(7, string:flat) string color(7, 14, 194) # yellow, purple show string at(8, 0, 0) teleport to map(1) savegame map := -1 free slice(savegame slice) w load from slot(1) # continues from "after loadgame" $0="Loadgame didn't happen!" crash end script, after loadgame, arg1, arg2, arg3, begin if (hook loadgame == 1) then ( assert(arg1 == 0) assert(arg2 == 0) assert(arg3 == 0) savegame tests 2 crash ) else ( assert(arg1 == 30) assert(arg2 == -100) assert(arg3 == 0) hook loadgame := 0 ) end # This is called from the loadgame plotscript script, savegame tests 2, begin $0="saving/loading tests 2" trace(0) # Check globals, map number, slices loaded (game is set to save slices) assert(savegame map == current map) assert(slicewidth(savegame slice) == 15) # Check NPCs were NOT saved assert(get npc id(savegame npc) == -1) # doesn't exist # Check strings were loaded assert(string is visible(5)) assert(string is visible(6)) assert(string is visible(8) == false) $8 = "This is a green string" assert(string compare(5, 8)) assert(string x(6) == 100) assert(string y(6) == 110) # Can't test colour, style w # Clean up hide string(5) hide string(6) hide string(7) free slice(savegame slice) # Now try passing args to the loadgame script hook loadgame := 2 save in slot(1) hook loadgame := 0 load from slot(1, 30, -100) # continues from "after loadgame" $0="Loadgame didn't happen!" crash end ######################################################################## script, reset game tests, begin $0="reset game tests" trace(0) # Test with no args called resetgame := true export globals(save slot: persistent, @called resetgame, @called resetgame) reset game $0="resetgame didn't happen!" crash end # Called with default args plotscript, after resetgame, arg1, arg2, arg3, begin $0="reset game tests" trace(0) called resetgame := false export globals(save slot: persistent, @called resetgame, @called resetgame) if (arg1 == 0) then ( # after resetting with no args assert(arg2 == 0) assert(arg3 == 0) reset game(10, 20) $0="resetgame didn't happen!" crash ) else ( # after resetting with args assert(arg1 == 10) assert(arg2 == 20) assert(arg3 == 0) # exit the script and continue to next tests ) end ######################################################################## # rungame is not actually tested! script, run game tests, begin $0="run game tests" assert(check game exists($1="") == false) assert(check game exists($1="test.rpg")) assert(check game exists($1="foo.rpg") == false) #assert(check game exists($1="test.rpgdir")) assert(check game exists($1="autotest.rpg")) assert(check game exists($1="autotest.hss") == false) assert(check game exists($1="../testgame") == false) assert(check game exists($1="../testgame/autotest.rpg")) assert(check game exists($1="..\\testgame/Autotest.rpg")) assert(check game exists($1="../testgame\\autotest.rpg")) assert(check game exists($1="autotest.rpgdir/") == false) #assert(check game exists($1="./testgame\\autotest.rpgDIR")) # Also check .rpg if given .rpgdir (not implemented) assert(check game exists($1=".//..\\TESTGAME\\autotest.RPG")) #assert(check game exists($1="../vikings/vikings.rpg")) # Also check .rpgdir if given .rpg (not implemented) # Should trailing slashes be allowed? #assert(check game exists($1="../vikings/vikings.rpgdir/") == false) #assert(check game exists($1="..\\vikings\\vikings.rpgdir\\") == false) end ######################################################################## #### COMMANDS THAT STILL NEED TESTS #### (Actually, this list is totally out of date) #### (Note: interactive commands should be in interactivetest.hss) #allow minimap (setting) #allow save anywhere (setting) #value,and,value #append ascii (ID, char) #append number (ID, number) #ascii from string (ID, position) #autosave #break #camera follows hero (who) #camera follows NPC (who) #camera pixel X #camera pixel Y #cancel map name display #center slice (handle) #change tileset (tileset, layer) #check NPC wall (who, direction) #check parentage (handle, parent handle) #check tag (tag) #child count (handle) #clamp slice (handle1, handle2) #clone sprite (handle) #concatenate strings (dest, source) #continue #copy string (dest, source) #create container (width, height) #create ellipse (width, height, border color, fill color) #create grid (width, height, rows, columns) #create NPC (ID,X,Y,direction) #create rect (width, height, style) #create text #current map #current stat #days of play #decrement (variable,amount) #delete char (ID, position) #delete map state (whichdata) #delete save (slot) #destroy NPC (reference) #dismount vehicle #number / number #draw NPCs above heroes (setting) #number == number #exit returning(value) #exit script #expand string(ID) #number ^ power #extended scancodes enabled #extract color(color, component) #fade screen in #fade screen out (red,green,blue) #fill parent (handle, true_or_false) #first child(handle) #first container child(handle) #first rect child(handle) #first sprite child(handle) #focus camera (x,y,speed) #for(counter,start,finish,step) do(commands) #formation probability (formation set, formation) #formation set frequency (formation set) #free slice (handle) #free slice children (handle) #free sprite (handle) #game over #get ambient music #get attack name #get color(index) #get damage cap #get each step script #get ellipse border col (handle) #get ellipse fill col (handle) #get foot offset #get global string (ID, global) #get grid columns (handle) #get grid rows (handle) #get instead of battle script #get item name (ID, item) #get load script #get map edge mode #get map name (ID, map) #get map tileset #get money (amount) #get NPC ignores walls (who) #get NPC moves (who) #get NPC obstructs (who) #get NPC usable (who) #get on keypress script #get outline(handle) #get slice velocity x (handle) #get slice velocity y (handle) #get song name (ID, song) #get sort order (handle) #get text bg(handle) #get text color(handle) #get victory music #get wrap(handle) #globals to string(ID, starting global, length) #number >> number #number >= number #greyscale palette (first, last) #grid is shown (handle) #hide battle health meter (state) #hide battle ready meter (state) #horiz flip sprite (handle, flip) #hours of play #increment (variable,amount) #inside battle #is filling parent (handle) #last child(handle) #last formation #last save slot #layer tileset (layer) #leader #number << number #number <= number #load attack sprite (num, palette) #load backdrop sprite (num) #load border sprite (num, palette) #load hero sprite (num, palette) #load large enemy sprite (num, palette) #load map state (whichdata, customid) #load medium enemy sprite (num, palette) #load palette (palette number) #load portrait sprite (num, palette) #load small enemy sprite (num, palette) #load tileset (tileset, layer) #load walkabout sprite (num, palette) #load weapon sprite (num, palette) #value && value #value || value #value ^^ value #lookup slice (lookup code, start slice) #lose money (amount) #map cure (attack, target, attacker) #map height (map) #map width (map) #milliseconds #minutes of play #number,mod,number #move slice above (handle, above what handle) #move slice below (handle, below what handle) #move slice by (handle, relative x, relative y, ticks) #move slice to (handle, x, y, ticks) #number * number #next container sibling(handle) #next rect sibling(handle) #next sibling(handle) #next sprite sibling(handle) #not (value) #number <> number #NPC at pixel (x, y, number) #NPC at spot (x, y, number) #NPC copy count (ID) #NPC direction (who) #NPC extra (who, which) #NPC frame (who) #NPC is walking (who) #NPC pixel X (who) #NPC pixel Y (who) #NPC reference (ID, copy) #NPC X (who) #NPC Y (who) #number from string (ID, default) #value,or,value #order menu #outside battle #outside battle cure #overhead tile #pan camera (direction,distance,pixelstep) #party money #pay money (amount) #place sprite #previous sibling(handle) #put camera (x,y) #put npc (who,x,y) #put slice (handle, X, Y) #put slice screen (handle, x, y) #put sprite (handle, x, y) #random (lownumber, highnumber) #random formation (formation set) #read attack name (ID, attack) #read color (index, element) #read map block (x,y,layer) #read NPC (who,NPCstat) #read pass block (x,y) #read timer (id) #realign slice (handle, horiz align, vert align, horiz anchor, vert anchor) #replace attack sprite (handle, num, palette) #replace backdrop sprite (handle, num) #replace border sprite (handle, num, palette) #replace char (ID, position, char) #replace hero sprite (handle, num, palette) #replace large enemy sprite (handle, num, palette) #replace medium enemy sprite (handle, num, palette) #replace portrait sprite (handle, num, palette) #replace small enemy sprite (handle, num, palette) #replace walkabout sprite (handle, num, palette) #replace weapon sprite (handle, num, palette) #reset map state (whichdata) #reset palette #resume map music #resume NPCs #resume NPC walls #resume obstruction #resume overlay #resume random enemies #resume random enemys #resume timers #RGB(red, green, blue) #run game #run script by ID (id, argument1, argument2, argument3...) #save map state (whichdata, customid) #save menu (reallysave) #search string (ID1, ID2, start) #seconds of play #seed random (new seed) #set battle wait mode (state) #set bottom padding (handle, pixels) #set color(index, value) #set damage cap (cap) #set days of play (days) #set debug keys disable (state) #set each step script (id) #set ellipse border col (handle, color) #set ellipse fill col (handle, color) #set foot offset (offset) #set grid columns (handle, columns) #set grid rows (handle, rows) #set harm tile damage (amount) #set harm tile flash (color) #set horiz align (handle, edge) #set horiz anchor (handle, edge) #set hours of play (hours) #set inn no revive mode (state) #set instead of battle script (id) #set inventory size (new size) #set left padding (handle, pixels) #set load script (id) #set map edge mode (mode, default tile) #set minutes of play (min) #set money (amount) #set no HP level up restore (state) #set no MP level up restore (state) #set NPC direction (who, direction) #set NPC extra (who, which, value) #set NPC frame (who, frame) #set NPC ignores walls (who, value) #set NPC moves (who, value) #set NPC obstructs (who, value) #set NPC position (who, X, Y) #set NPC speed (who, speed) #set NPC usable (who, value) #set on keypress script (id) #set outline(handle, outline) #set padding (handle, pixels) #set parent (handle, parent handle) #set rect bgcol (handle, color) #set rect fgcol (handle, color) #set right padding (handle, pixels) #set seconds of play (sec) #set slice clipping (handle, clip) #set slice edge x (handle, edge, value) #set slice edge y (handle, edge, value) #set slice extra (handle, extra, value) #set slice height (handle, height) #set slice lookup (handle, code) #set slice screen x (handle, x) #set slice screen y (handle, y) #set slice velocity (handle, horiz pixels per tick, vert pixels per tick, ticks) #set slice velocity x (handle, pixels per tick, ticks) #set slice velocity y (handle, pixels per tick, ticks) #set slice visible (handle, vis) #set slice width (handle, width) #set slice x (handle, X) #set slice y (handle, Y) #set sort order (handle, order) #set sprite frame (handle, num) #set sprite palette (handle, num) #set sprite trans (handle, drawtransparent) #set sprite visible #set tag (tag,value) #set text bg(handle, color) #set text color(handle, color) #set tile animation offset (animation pattern, offset, layer) #set timer (id, count, speed, trigger, string, flags) #set top padding (handle, pixels) #set vert align (handle, edge) #set vert anchor (handle, edge) #set wrap(handle, wrap) #show backdrop (number) #show grid (handle, shown) #show map #show no value #show value (number) #slice child (handle, number) #slice collide (handle1, handle2) #slice collide point (handle, x, y) #slice contains (handle1, handle2) #slice edge x (handle, edge) #slice edge y (handle, edge) #slice is ellipse (handle) #slice is grid (handle) #slice is moving (handle) #slice is valid (id) #slice to back (handle) #slice to front (handle) #sort children (handle, wipe) #sprite frame count (handle) #sqrt (number) #stop slice (handle) #stop timer (id) #string to globals (ID, starting global, length) #number -- number #suspend catapillar #suspend map music #suspend NPCs #suspend NPC walls #suspend obstruction #suspend overlay #suspend random enemies #suspend random enemys #suspend timers #system day #system hour #system minute #system month #system second #system year #teleport to map (map, x, y) #trace value (expression, ...) #trim string (ID, start, length) #tweak palette (red, green, blue, first, last) #update palette #use item (item) #use item in slot(slot) #vert flip sprite (handle, flip) #wait for all #wait for camera #wait for NPC (who) #wait for slice (handle) #walk NPC (who, direction, distance) #walk NPC to X (who, X) #walk NPC to Y (who, Y) #write color (index, element, value) #write map block (x,y,value,layer) #write pass block (x,y,value) #value,xor,value #Y sort children (handle)