# # Star Dartle 2000 # #----------------------------------------------------------------------- # Globals and consts global variable(1, play zone) global variable(2, player) global variable(3, ticks) global variable(4, escapes) global variable(5, waves) define constant(30, second) #----------------------------------------------------------------------- # Init plotscript, new game, begin init game init mission main loop end script, init game, begin play song(0) suspend player set slice visible(lookup slice(sl:maproot), false) variable(col) col := load slice collection(0) play zone := lookup slice(sli:play zone, col) rev up starfield end script, init mission, begin player := create player ship() put at player start(player) waves := create wave manager level 1() end #----------------------------------------------------------------------- # Game loop script, main loop, begin while(true) do( ticks += 1 do controls do updates wait(1) ) end script, do controls, begin variable(sl) sl := player if(keyval(key:up)) then(push force y(sl, -2)) if(keyval(key:down)) then(push force y(sl, 2)) if(keyval(key:left)) then(push force x(sl, -2)) if(keyval(key:right)) then(push force x(sl, 2)) do debug keys end script, do debug keys, begin if(keyval(key:e) > 1) then( put random enemy(create blue enemy()) ) end script, do updates, begin update starfield for each obj(@increment age) check for enemies hitting player check for bullets hitting enemies for each obj(@run update callback) for each obj(@apply force) for each obj(@apply friction) for each obj(@run animation callback) for each obj(@delete stuff) end script, delete stuff, sl, begin if(get delete me(sl)) then( free slice(sl) ) end #----------------------------------------------------------------------- # Player Ship script, create player ship, begin variable(sl) sl := load walkabout sprite(1) make obj(sl, 4) set update callback(sl, @player ship update) set animation callback(sl, @animate tilt and afterburner) set attack callback(sl, @player attack by hp) set death callback(sl, @default player death callback) exit returning(sl) end script, player ship update, sl, begin run attack callback(sl) keep obj onscreen(sl) end define constant(4, max weapon level) script, player attack by hp, sl, begin switch(get hp(sl)) do( case(0) case(1) player attack 1(sl) case(2) player attack 2(sl) case(3) player attack 3(sl) case(4) player attack 4(sl) ) end script, raise player weapon level, sl, begin variable(hp) hp := get hp(sl) hp := small(hp + 1, max weapon level) set hp(sl, hp) end script, player attack 1, sl, begin # Damage output 2 per second if(once every(sl, second / 2)) then( variable(b) b := create weak bullet() put at obj(b, sl) ) end script, player attack 2, sl, begin # Damage output 3 per second if(once every(sl, second / 3)) then( variable(b) b := create weak bullet() put at obj(b, sl) variable(c) c := get bullet counter(sl) c := (c + 1) ,mod, 2 set bullet counter(sl, c) switch(c) do( case(0) push force y(b, -3) case(1) push force y(b, 3) ) ) end script, player attack 3, sl, begin # Damage output 5 per second if(alternate(sl, second / 2)) then( if(once every(sl, second / 10)) then( variable(b) b := create weak bullet() put at obj(b, sl) ) ) end script, player attack 4, sl, begin # Damage output 7 per second if(once every(sl, second / 7)) then( variable(b) b := create null bullet() put at obj(b, sl) variable(c) c := get bullet counter(sl) c := (c + 1) ,mod, 8 set bullet counter(sl, c) move slice to(b, slice x(b) + 320, slice y(b) + 30 * (abs(c -- 4) -- 2), second) ) end script, create weak bullet, begin variable(sl) sl := create rect(6, 1) set rect border(sl, border:none) set rect bg col(sl, 15) make bullet(sl, 8) set update callback(sl, @weak bullet update) exit returning(sl) end script, weak bullet update, sl, begin set force x(sl, 8) remove if offscreen(sl) end script, create null bullet, begin variable(sl) sl := create container(6, 1) add walkabout pic(sl, 13) make bullet(sl, 8) set update callback(sl, @null bullet update) set animation callback(sl, @null bullet animate) exit returning(sl) end script, null bullet animate, sl, begin variable(pic) pic := get pic(sl) loop frame(pic, 0, 7, 0) end script, null bullet update, sl, begin remove if offscreen(sl) end #----------------------------------------------------------------------- # Damage script, bullet collides with enemy, b, e, begin run collision callback(b, e) end script, enemy collides with player, e, p, begin run collision callback(e, p) end script, default bullet collide, b, e, begin inflict damage(e, get damage(b)) set delete me(b, true) end script, default enemy collide, e, p, begin inflict damage(p, get damage(e)) end script, inflict damage, sl, dmg, begin variable(hp) hp := get hp(sl) hp -= dmg set hp(sl, hp) if(hp <= 0) then( object dies(sl) ) end script, object dies, obj, begin run death callback(obj) end script, default enemy death callback, e, begin put at obj(create explosion(), e) if(random percent(20)) then( put at obj(create powerup(), e) ) set delete me(e, true) end script, default player death callback, p, begin put at obj(create explosion(), p) set delete me(p, true) game over end #----------------------------------------------------------------------- # Power-Ups script, create powerup, begin variable(sl) sl := create container(10, 10) make obj(sl) add walkabout pic(sl, 14) add text overlay(sl, $0="") set update callback(sl, @powerup update) set animation callback(sl, @powerup animate) exit returning(sl) end script, powerup update, sl, begin set force x(sl, -1) if(circle collide(player, sl)) then( raise player weapon level(player) set delete me(sl, true) ) remove if offscreen(sl) end script, powerup animate, sl, begin variable(pic) pic := get pic(sl) loop frame(pic, 0, 7, second / 5) if(once every(sl, second / 3)) then( variable(txt, c) $0=" WEAPON+ + +" txt := get text overlay(sl) c := get counter(sl) $1=" " replace char(1, 1, ascii from string(0, c + 1)) set slice text(txt, 1) c := (c + 1) ,mod, string length(0) set counter(sl, c) ) end #----------------------------------------------------------------------- # Enemies script, create walkabout enemy, sprite, update callback, max speed, begin variable(sl) sl := load walkabout sprite(sprite) make enemy(sl, max speed) set update callback(sl, update callback) exit returning(sl) end script, create small enemy enemy, sprite, update callback, max speed, begin variable(sl) sl := load small enemy sprite(sprite) make enemy(sl, max speed) set update callback(sl, update callback) exit returning(sl) end script, create blue enemy, begin variable(sl) sl := create walkabout enemy(2, @mindless enemy update, 2) exit returning(sl) end script, mindless enemy update, sl, begin push force x(sl, get max force(sl) * -1) keep onscreen vertically(sl) check for escape(sl) end script, create green enemy, begin variable(sl) sl := create walkabout enemy(4, @serpentine enemy update, 2) exit returning(sl) end script, serpentine enemy update, sl, begin if(just once(sl)) then( set age(sl, second / 4) ) if(alternate(sl, second / 2)) then( push force y(sl, -2, 4) )else( push force y(sl, 2, 4) ) push force x(sl, get max force(sl) * -1) keep onscreen vertically(sl) check for escape(sl) end script, create red enemy, begin variable(sl) sl := create walkabout enemy(3, @diagonal enemy update, 2) exit returning(sl) end script, diagonal enemy update, sl, begin if(just once(sl)) then( variable(dest y, screen h) screen h := slice height(play zone) if(slice y(sl) < screen h / 2) then( dest y := screen h )else( dest y := 0 ) move slice to(sl, -40, dest y, second * 4) ) keep onscreen vertically(sl) check for escape(sl) end script, create small asteroid enemy, begin variable(sl) sl := create small enemy enemy(0, @asteroid enemy update, 1) set hp(sl, 5) exit returning(sl) end script, asteroid enemy update, sl, begin push force x(sl, get max force(sl) * -1) keep onscreen vertically(sl) check for escape(sl) end #----------------------------------------------------------------------- # Effects script, create explosion, begin variable(sl) sl := load walkabout sprite(11) make obj(sl, 0) set animation callback(sl, @explosion animate) exit returning(sl) end script, explosion animate, sl, begin if(frame to last(sl, 0, 7)) then( set delete me(sl, true) ) end #----------------------------------------------------------------------- # Waves script, create wave manager level 1, begin variable(sl) sl := create container(0,0) make obj(sl, 0) set update callback(sl, @wave manager level 1 update) exit returning(sl) ) script, wave manager level 1 update, sl, begin if(just once(sl)) then( create spaced quad wave(@create small asteroid enemy) ) if(once every(sl, second * 5)) then( variable(count) count := increment counter(sl) switch(count) do( case(1) create random quad wave(@create blue enemy) case(2) create random quad wave(@create red enemy) case(3) create center quad wave(@create green enemy) case(4) create spaced quad wave(@create blue enemy) case(5) create spaced tri wave(@create green enemy) case(else) set counter(sl, 0) ) ) end script, create random quad wave, ammo, begin variable(sl) sl := create container(0,0) make obj(sl, 0) set update callback(sl, @random quad wave update) set ammo creator(sl, ammo) exit returning(sl) end script, random quad wave update, sl, begin if(just once(sl)) then( put random enemy(sl) ) if(once every(sl, second * 2 / 3)) then( put at obj(run ammo creator(sl), sl) if(increment counter(sl) >= 4) then( set delete me(sl, true) ) ) end script, create center quad wave, ammo, begin variable(sl) sl := create container(0,0) make obj(sl, 0) set update callback(sl, @center quad wave update) set ammo creator(sl, ammo) exit returning(sl) end script, center quad wave update, sl, begin if(just once(sl)) then( put center enemy(sl) ) if(once every(sl, second * 2 / 3)) then( put at obj(run ammo creator(sl), sl) if(increment counter(sl) >= 4) then( set delete me(sl, true) ) ) end script, create spaced tri wave, ammo, begin variable(sl) sl := create container(0,0) make obj(sl, 0) set counter(sl, 3) set update callback(sl, @spaced n wave update) set ammo creator(sl, ammo) exit returning(sl) end script, create spaced quad wave, ammo, begin variable(sl) sl := create container(0,0) make obj(sl, 0) set counter(sl, 4) set update callback(sl, @spaced n wave update) set ammo creator(sl, ammo) exit returning(sl) end script, spaced n wave update, sl, begin if(just once(sl)) then( variable(i, c) c := get counter(sl) for(i, 0, c -- 1) do( put spaced enemy(run ammo creator(sl), i, c) ) ) set delete me(sl, true) end #----------------------------------------------------------------------- # Putting Ships script, put at player start, sl, begin set slice x(sl, slice width(sl) * -1) set slice y(sl, slice height(play zone) / 2) set force x(sl, 10) end script, put at obj, sl, obj, begin set slice edge x(sl, edge:center, slice edge x(obj, edge:center)) set slice edge y(sl, edge:center, slice edge y(obj, edge:center)) end script, put random enemy, sl, begin set slice edge x(sl, edge:left, slice width(play zone)) variable(h) h := slice height(sl) / 2 set slice y(sl, random(h, slice height(play zone) -- h)) end script, put center enemy, sl, begin set slice edge x(sl, edge:left, slice width(play zone)) set slice edge y(sl, edge:center, slice height(play zone) / 2) end script, put spaced enemy, sl, i, total, begin set slice edge x(sl, edge:left, slice width(play zone)) variable(n) n := slice height(play zone) / (total + 1) set slice edge y(sl, edge:center, n + n * i) end #----------------------------------------------------------------------- # Iteration script, for each obj, callback, begin variable(sl, next) sl := first child(play zone) while(sl) do( next := next sibling(sl) if(get slice lookup(sl) == sli:obj) then( run script by id(callback, sl) ) sl := next ) end script, check for bullets hitting enemies, begin variable(b, next b) b := first child(play zone) while(b) do( next b := next sibling(b) if(get slice lookup(b) == sli:obj) then( if(get is bullet(b)) then( variable(e, next e) e := first child(play zone) while(e) do( next e := next sibling(e) if(get slice lookup(e) == sli:obj) then( if(get is enemy(e)) then( if(slice collide(b, e)) then( bullet collides with enemy(b, e) ) ) ) e := next e ) ) ) b := next b ) end script, check for enemies hitting player, begin variable(e, next e) e := first child(play zone) while(e) do( next e := next sibling(e) if(get slice lookup(e) == sli:obj) then( if(get is enemy(e)) then( if(circle collide(player, e)) then( enemy collides with player(e, player) ) ) ) e := next e ) end #----------------------------------------------------------------------- # Starfield script, rev up starfield, begin variable(i) for(i, 0, slice width(play zone) / 2) do( update starfield ) end script, update starfield, begin variable(star zone) star zone := lookup slice(sli:star zone, play zone) variable(star, next star) star := first child(star zone) while(star) do( next star := next sibling(star) set slice x(star, slice x(star) -- 1) set rect bg col(star, 16 + random(0, 6) * 16) if(slice x(star) < 0) then(free slice(star)) star := next star ) if(random percent(10)) then( star := create rect(1, 1) set slice lookup(star, sli:star) set parent(star, star zone) set slice x(star, slice width(star zone)) set slice y(star, random(0, slice height(star zone))) set rect border(star, border: none) ) end #----------------------------------------------------------------------- # Force and friction script, push force x, sl, amount, max=0, begin variable(v) v := get force x(sl) v += amount if(max == 0) then( max := get max force(sl) ) if(v > max) then(v := max) if(v < max * -1) then(v := max * -1) set force x(sl, v) end script, push force y, sl, amount, max=0, begin variable(v) v := get force y(sl) v += amount if(max == 0) then( max := get max force(sl) ) if(v > max) then(v := max) if(v < max * -1) then(v := max * -1) set force y(sl, v) end script, apply force, sl, begin set slice x(sl, slice x(sl) + get force x(sl)) set slice y(sl, slice y(sl) + get force y(sl)) end script, apply friction, sl, begin variable(v) v := get force x(sl) v -= sign(v) set force x(sl, v) v := get force y(sl) v -= sign(v) set force y(sl, v) end script, keep obj onscreen, sl, begin if(slice edge x(sl, edge:left) < 0) then( set force x(sl, large(get force x(sl), 0)) ) if(slice edge x(sl, edge:right) > slice width(play zone)) then( set force x(sl, small(get force x(sl), 0)) ) if(slice edge y(sl, edge:top) < 0) then( set force y(sl, large(get force y(sl), 0)) ) if(slice edge y(sl, edge:bottom) > slice height(play zone)) then( set force y(sl, small(get force y(sl), 0)) ) end script, keep onscreen vertically, sl, begin if(slice edge y(sl, edge:top) < 0) then( set force y(sl, large(get force y(sl), 0)) ) if(slice edge y(sl, edge:bottom) > slice height(play zone)) then( set force y(sl, small(get force y(sl), 0)) ) end script, check for escape, sl, begin if(slice edge x(sl, edge:right) < 0) then( escapes += 1 show string(string sprintf(0, $1="Escapes:%d", escapes)) set delete me(sl, true) ) end script, remove if offscreen, sl, begin if(not(slice collide(sl, play zone))) then( set delete me(sl, true) ) end #----------------------------------------------------------------------- # Animation script, loop frame, sl, first, last, tickmod=1, begin variable(fr) if(tickmod > 0 && (ticks ,mod, tickmod) <> 0) then(exit script) fr := get sprite frame(sl) fr += 1 if(fr < first) then(fr := first) if(fr > last) then(fr := first) set sprite frame(sl, fr) end script, frame to last, sl, first, last, tickmod=1, begin # Returns true if the frame has reached the last if(tickmod > 0 && ticks ,mod, tickmod <> 0) then(exit script) variable(fr) fr := get sprite frame(sl) fr += 1 if(fr < first) then(fr := first) if(fr > last) then(fr := last) set sprite frame(sl, fr) exit returning(fr == last) end script, animate tilt and afterburner, sl, begin animate tilt(sl) animate afterburner(sl) end script, animate tilt, sl, begin variable(fy) fy := get force y(sl) variable(frame) frame := 0 if(fy > 0) then(frame := 1) if(fy < 0) then(frame := 2) set sprite frame(sl, frame) end script, animate afterburner, sl, begin variable(fx, a, max) fx := get force x(sl) a := lookup slice(sli:afterburn, sl) if(a) then( if(fx <= 0) then( free slice(a) a := 0 ) )else( if(fx > 0) then( a := create afterburn(sl) ) ) if(a) then( max := get max force(sl) if(fx > max / 2) then( loop frame(a, 2, 5) )else( loop frame(a, 0, 1) ) ) end script, create afterburn, sl, begin variable(a) a := load walkabout sprite(9) set slice lookup(a, sli:afterburn) center slice(a) set parent(a, sl) set slice x(a, slice width(sl) * -1) end script, add walkabout pic, sl, pic id, begin variable(pic) pic := load walkabout sprite(pic id) set parent(pic, sl) set slice lookup(pic, sli:pic) center slice(pic) end script, get pic, sl, begin exit returning(lookup slice(sli:pic, sl)) end script, add text overlay, sl, str id, begin variable(txt) txt := create text set slice text(txt, str id) set outline(txt, true) set parent(txt, sl) set slice lookup(txt, sli:text) center slice(txt) end script, get text overlay, sl, begin exit returning(lookup slice(sli:text, sl)) end #----------------------------------------------------------------------- # Metadata # Primary meta slice sli:meta # x = force x # y = force y # height = max force # width = animation callback # top padding = update callback # right padding = age # bottom padding = counter # left padding = ammo creator # extra 0 = metadata bits # extra 1 = # extra 2 = # # Secondary meta slice (first child) # x = attack callback # y = bullet counter # height = collision callback # width = death callback # top padding = damage # right padding = hp # bottom padding = # left padding = # extra 0 = # extra 1 = # extra 2 = script, make enemy, sl, maxforce=2, begin make obj(sl, maxforce) set is enemy(sl, true) if(slice is sprite(sl)) then( horiz flip sprite(sl, true) ) set collision callback(sl, @default enemy collide) set death callback(sl, @default enemy death callback) exit returning(sl) end script, make bullet, sl, maxforce=2, begin make obj(sl, maxforce) set is bullet(sl, true) set collision callback(sl, @default bullet collide) exit returning(sl) end script, make obj, sl, maxforce=2, begin add meta(sl) set slice lookup(sl, sli:obj) set parent(sl, play zone) set horiz anchor(sl, edge:center) set vert anchor(sl, edge:center) set max force(sl, maxforce) set damage(sl, 1) set hp(sl, 1) end script, add meta, sl, begin variable(m) m := create container(0, 0) set slice lookup(m, sli:meta) set parent(m, sl) set slice visible(m, false) variable(m2) m2 := create container(0, 0) set parent(m2, m) end script, set force x, sl, v, begin variable(m) m := lookup slice(sli:meta, sl) set slice x(m, v) end script, get force x, sl, begin variable(m) m := lookup slice(sli:meta, sl) exit returning(slice x(m)) end script, set force y, sl, v, begin variable(m) m := lookup slice(sli:meta, sl) set slice y(m, v) end script, get force y, sl, begin variable(m) m := lookup slice(sli:meta, sl) exit returning(slice y(m)) end script, set max force, sl, v, begin variable(m) m := lookup slice(sli:meta, sl) set slice height(m, v) end script, get max force, sl, begin variable(m) m := lookup slice(sli:meta, sl) exit returning(slice height(m)) end script, set animation callback, sl, callback, begin variable(m) m := lookup slice(sli:meta, sl) set slice width(m, callback) end script, run animation callback, sl, begin variable(m, cb) m := lookup slice(sli:meta, sl) cb := slice width(m) if(cb) then( run script by id(cb, sl) ) end script, set update callback, sl, callback, begin variable(m) m := lookup slice(sli:meta, sl) set top padding(m, callback) end script, run update callback, sl, begin variable(m, cb) m := lookup slice(sli:meta, sl) cb := get top padding(m) if(cb) then( run script by id(cb, sl) ) end script, set age, sl, v, begin variable(m) m := lookup slice(sli:meta, sl) set right padding(m, v) end script, get age, sl, begin variable(m) m := lookup slice(sli:meta, sl) exit returning(get right padding(m)) end script, set counter, sl, v, begin variable(m) m := lookup slice(sli:meta, sl) set bottom padding(m, v) end script, get counter, sl, begin variable(m) m := lookup slice(sli:meta, sl) exit returning(get bottom padding(m)) end script, set ammo creator, sl, v, begin variable(m) m := lookup slice(sli:meta, sl) set left padding(m, v) end script, run ammo creator, sl, begin variable(m, cb) m := lookup slice(sli:meta, sl) cb := get left padding(m) if(cb) then( exit returning(run script by id(cb, sl)) ) exit returning(0) end script, set attack callback, sl, v, begin variable(m) m := first child(lookup slice(sli:meta, sl)) set slice x(m, v) end script, run attack callback, sl, begin variable(m, cb) m := first child(lookup slice(sli:meta, sl)) cb := slice x(m) if(cb) then( exit returning(run script by id(cb, sl)) ) exit returning(0) end script, set bullet counter, sl, v, begin variable(m) m := first child(lookup slice(sli:meta, sl)) set slice y(m, v) end script, get bullet counter, sl, begin variable(m) m := first child(lookup slice(sli:meta, sl)) exit returning(slice y(m)) end script, set collision callback, sl, v, begin variable(m) m := first child(lookup slice(sli:meta, sl)) set slice height(m, v) end script, run collision callback, sl, other, begin variable(m, cb) m := first child(lookup slice(sli:meta, sl)) cb := slice height(m) if(cb) then( exit returning(run script by id(cb, sl, other)) ) exit returning(0) end script, set death callback, sl, v, begin variable(m) m := first child(lookup slice(sli:meta, sl)) set slice width(m, v) end script, run death callback, sl, begin variable(m, cb) m := first child(lookup slice(sli:meta, sl)) cb := slice width(m) if(cb) then( exit returning(run script by id(cb, sl)) ) exit returning(0) end script, set damage, sl, v, begin variable(m) m := first child(lookup slice(sli:meta, sl)) set top padding(m, v) end script, get damage, sl, begin variable(m) m := first child(lookup slice(sli:meta, sl)) exit returning(get top padding(m)) end script, set hp, sl, v, begin variable(m) m := first child(lookup slice(sli:meta, sl)) set right padding(m, v) end script, get hp, sl, begin variable(m) m := first child(lookup slice(sli:meta, sl)) exit returning(get right padding(m)) end #----------------------------------------------------------------------- # Metadata util script, increment age, sl, begin variable(m) m := lookup slice(sli:meta, sl) set right padding(m, get right padding(m) + 1) end script, increment counter, sl, begin variable(m, v) m := lookup slice(sli:meta, sl) v := get bottom padding(m) + 1 set bottom padding(m, v) exit returning(v) end script, once every, sl, ticknum, begin exit returning(get age(sl) ,mod, ticknum == 0) end script, alternate, sl, ticknum, begin exit returning(get age(sl) / ticknum ,mod, 2) end script, just once, sl, begin if(not(get just once(sl))) then( set just once(sl, true) exit returning(true) ) exit returning(false) end #----------------------------------------------------------------------- # Metadata bits script, get exbit, sl, bit, begin variable(m, n) m := lookup slice(sli:meta, sl) n := get slice extra(m, extra 0) if(n,and,2^bit) then(exit returning(true)) exit returning(false) end script, set exbit, sl, bit, value=1, begin variable(m, n) m := lookup slice(sli:meta, sl) n := get slice extra(m, extra 0) if(value) then(n := n, or, 2^bit) else(n := n, and, (-1, xor, 2^bit)) set slice extra(m, extra 0, n) end script, get delete me, sl ( exit returning(get exbit(sl, 1)) ) script, set delete me, sl, value ( set exbit(sl, 1, value) ) script, get is enemy, sl ( exit returning(get exbit(sl, 2)) ) script, set is enemy, sl, value ( set exbit(sl, 2, value) ) script, get is bullet, sl ( exit returning(get exbit(sl, 3)) ) script, set is bullet, sl, value ( set exbit(sl, 3, value) ) script, get just once, sl ( exit returning(get exbit(sl, 4)) ) script, set just once, sl, value ( set exbit(sl, 4, value) ) #----------------------------------------------------------------------- # Util script, random percent, p, begin exit returning(random(1, 100) <= p) end script, small, v1, v2, begin if(v1 >> v2) then(exit returning(v2)) exit returning(v1) end script, large, v1, v2, begin if(v1 << v2) then(exit returning(v2)) exit returning(v1) end script, circle collide, s1, s2, begin if(slice collide(s1, s2)) then( variable(r1, r2) r1 := slice width(s1) / 2 r2 := slice width(s2) / 2 variable(a, b, c) a := slice edge x(s1, edge:center) -- slice edge x(s2, edge:center) b := slice edge y(s1, edge:center) -- slice edge y(s2, edge:center) c := r1 + r2 if(a^2 + b^2 < c^2) then( exit returning(true) ) ) exit returning(false) end