-
-
Save AndreiRudenko/a3f62fd84140cb83780a05572fb8bf7e to your computer and use it in GitHub Desktop.
Ludum Dare 41 source code for TIC-80 game, written in wren language
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// author: Andrei Rudenko | |
// desc: ld41 | |
// script: wren | |
import "random" for Random | |
class Maths { | |
static clamp(value, a, b) { ( value < a ) ? a : ( ( value > b ) ? b : value ) } | |
static sign( x ) { (x >= 0) ? 1 : -1 } | |
static ispow2(n) { (n & (n - 1)) == 0 } | |
static mod(a,b) { | |
var r = a % b | |
return r < 0 ? r + b : r | |
} | |
} | |
class Utils { | |
static list_remove(l,v){ | |
for (i in 0...l.count) { | |
if (l[i] == v) { | |
l.removeAt(i) | |
return true | |
} | |
} | |
return false | |
} | |
static list_has(l,v){ | |
for (o in l) { | |
if (o == v) return true | |
} | |
return false | |
} | |
} | |
class Timer { | |
static time(){ 0} | |
static init(){ | |
__timers = [] | |
} | |
static add(t){ | |
__timers.add(t) | |
return t | |
} | |
static remove(t){ | |
var ot = null | |
for (i in 0...__timers.count) { | |
if (ot == __timers[i]) { | |
__timers.removeAt(i) | |
break | |
} | |
} | |
} | |
static schedule(tl){ schedule_from(0, tl, null) } | |
static schedule(tl, cb){ schedule_from(0, tl, cb) } | |
static schedule_from(ct, tl){ schedule_from(ct, tl, null) } | |
static schedule_from(ct, tl, cb){ | |
var t = Timer.new() | |
t.start_from(ct, tl, cb) | |
return t | |
} | |
static update(dt){ | |
for (t in __timers) { | |
if (t.active && !t.finished && t.time_limit >= 0){ | |
t.update(dt) | |
} | |
} | |
} | |
time_limit { _time_limit } | |
time_limit=(v) { _time_limit = v } | |
loops { _loops } | |
loops=(v) { _loops = v } | |
active { _active } | |
active=(v) { _active = v } | |
elapsed_time { _time } | |
elapsed_time=(v) { _time = v } | |
use_timescale { _use_ts } | |
use_timescale=(v) { _use_ts = v } | |
finished { _finished } | |
elapsed_loops { _loops_counter } | |
time_left { _time_limit - _time } | |
loops_left { _loops - _loops_counter } | |
progress { (_time_limit > 0) ? (_time / _time_limit) : 0 } | |
construct new(){ | |
_time = 0 | |
_time_limit = 0 | |
_start_time = 0 | |
_loops = 0 | |
_loops_counter = 0 | |
_inarray = false | |
_active = true | |
_use_ts = true | |
_finished = false | |
} | |
start(tl) { start_from(0, tl, null) } | |
start(tl, cb) { start_from(0, tl, cb) } | |
start_from(st, tl) { start_from(st, tl, null) } | |
start_from(st, tl, cb) { | |
stop(false) | |
if (!_inarray) { | |
Timer.add(this) | |
_inarray = true | |
} | |
_active = true | |
_finished = false | |
if(cb != null){ | |
_oncomplete = cb | |
} | |
_time_limit = tl.abs | |
_start_time = (_time_limit..st).min | |
_time = _start_time | |
_loops = 1 | |
_loops_counter = 0 | |
return this | |
} | |
reset() { reset(-1) } | |
reset(newtime) { | |
if (newtime >= 0) { | |
time_limit = newtime | |
} | |
finished = false | |
_time = 0 // _start_time ? | |
// loops = 1 | |
_loops_counter = 0 | |
return this | |
} | |
repeat() { repeat(0) } | |
repeat(t) { | |
loops = t.abs | |
return this | |
} | |
stop() { stop(true) } | |
stop(finish) { | |
if(!_finished) { | |
_finished = true | |
_active = false | |
if (_inarray){ | |
Timer.remove(this) | |
_inarray = false | |
} | |
if (finish && _oncomplete != null) { | |
_oncomplete.call() | |
} | |
} | |
} | |
oncomplete(cb){ | |
_oncomplete = cb | |
return this | |
} | |
onrepeat(cb){ | |
_onrepeat = cb | |
return this | |
} | |
onupdate(cb){ | |
_onupdate = cb | |
return this | |
} | |
update(dt){ | |
if (_use_ts) dt = dt * Game.timescale | |
_time = _time + dt | |
if (_onupdate != null) _onupdate.call() | |
while (!_finished && _time_limit < _time) { | |
_loops_counter = _loops_counter + 1 | |
if (_loops > 0 && (_loops_counter >= _loops)) { | |
stop() | |
break | |
} | |
_time = _time - _time_limit | |
if (_onrepeat != null) _onrepeat.call() | |
} | |
} | |
} | |
class Text { | |
x { _x } | |
y { _y } | |
scale { _sc } | |
color { _clr } | |
text { _txt } | |
x=(v) { _x=v } | |
y=(v) { _y=v } | |
scale=(v) { _sc=v } | |
color=(v) { _clr=v } | |
text=(v) { _txt=v } | |
construct new(txt,x,y,clr,sc) { | |
_txt = txt | |
_x = x | |
_y = y | |
_sc = sc | |
_clr = clr | |
} | |
draw() { | |
TIC.print(_txt,_x,_y,_clr,false,_sc) | |
} | |
} | |
class Words { | |
static init(){ | |
__used = [] | |
__words = [] | |
// 2 letter words | |
__words.add([ | |
"AA", "AB", "AD", "AE", "AG", "AH", "AI", "AL", "AM", "AN", "AR", "AS", "AT", "AW", "AX", "AY", "BA", "BE", "BI", "BO", "BY", "DE", "DO", "ED", | |
"EF", "EH", "EL", "EM", "EN", "ER", "ES", "ET", "EX", "FA", "FE", "GO", "HA", "HE", "HI", "HM", "HO", "ID", "IF", "IN", "IS", "IT", "JO", "KA", | |
"KI", "LA", "LI", "LO", "MA", "ME", "MI", "MM", "MO", "MU", "MY", "NA", "NE", "NO", "NU", "OD", "OE", "OF", "OH", "OI", "OM", "ON", "OP", "OR", | |
"OS", "OW", "OX", "OY", "PA", "PE", "PI", "QI", "RE", "SH", "SI", "SO", "TA", "TI", "TO", "UH", "UM", "UN", "UP", "US", "UT", "WE", "WO", "XI", | |
"XU", "YA", "YE", "YO", "ZA" | |
]) | |
// 3 letter words | |
__words.add([ | |
"AID","AIM","AIR","AWE","FIT", | |
"FTW","FUN","GOD","HOT","JOY", | |
"NEW","OMG","PEP","VIM","VOW", | |
"WIN","WON","WOW","YAY","YEA", | |
"YEN","YES" | |
]) | |
// 4 letter words | |
__words.add([ | |
"ABLE", "AMIN", "AWED", "BEST", "BRIO", | |
"CALM", "CARE", "COOL", "CUTE", "DOPE", | |
"DUTY", "EASE", "EASY", "FAIR", "FAME", | |
"FINE", "FLOW", "FOOD", "FREE", "GIFT", | |
"GIVE", "GLAD", "GLOW", "GOOD", "GROW", | |
"HALO", "HELP", "HERO", "HOLY", "HOPE", | |
"HUGE", "IDEA", "JOKE", "JUST", "KEEN", | |
"KIND", "KISS", "LIFE", "LIKE", "LIVE", | |
"LOVE", "LUCK", "MANY", "MILD", "MORE", | |
"NEAT", "NICE", "OPEN", "PLAY", "PURE", | |
"REAL", "REST", "RIPE", "SAFE", "SAVE", | |
"SEXY", "SOUL", "SWAG", "TACT", "TEAM", | |
"TIME", "TRUE", "VERY", "WARM", "WELL", | |
"WILL", "WISE", "YEAH", "ZANY", "ZEAL", | |
"ZEST", "ZING" | |
]) | |
// 5 letter words | |
__words.add([ | |
"ADORE", "AGILE", "AGREE", "ALERT", "ALIVE", | |
"ALLOW", "ALOHA", "AMAZE", "AMITY", "AMPLE", | |
"AMPLY", "AMUSE", "ANGEL", "ARDOR", "AWARE", | |
"BLESS", "BLISS", "BLOOM", "BONUS", "CHAMP", | |
"CHARM", "CLEAN", "CLEAR", "DANDY", "DREAM", | |
"DRIVE", "EAGER", "ENJOY", "EXTRA", "FAITH", | |
"FANCY", "FOCUS", "GIDDY", "GIGIL", "GLORY", | |
"GRACE", "GRAND", "GREAT", "GUIDE", "HAPPY", | |
"HEART", "HELLO", "HONOR", "HUMAN", "HUMOR", | |
"INNER", "JOLLY", "KALON", "KILIG", "LAUGH", | |
"LEARN", "LIGHT", "LOGIC", "LOYAL", "LUCKY", | |
"MAGIC", "MAJOR", "MENCH", "MERCY", "MERIT", | |
"MOVED", "NOBLE", "ORDER", "PEACE", "PIOUS", | |
"POWER", "PRIDE", "PROTO", "PROUD", "QUIET", | |
"READY", "RELAX", "RENEW", "SCOPE", "SERVE", | |
"SHINE", "SKILL", "SLEEP", "SMART", "SMILE", | |
"SPACE", "SPARK", "START", "STILL", "STUDY", | |
"STYLE", "SWEET", "TEACH", "TEMUL", "THANK", | |
"TOUCH", "TRUST", "TRUTH", "UNITY", "VALID", | |
"VALUE", "VIGOR", "WATER", "WHOLE", "WORTH", | |
"YEARN", "YOUNG", "YOUTH", "YUGEN", "YUMMY", | |
"ZAPPY", "ZESTY", "ZIPPY" | |
]) | |
} | |
static is_used(i) { | |
return Utils.list_has(__used, i) | |
} | |
static clear_used(){ | |
__used = [] | |
} | |
static get_word(l) { | |
return __words[l-2] | |
} | |
static get_random(l) { | |
var words = __words[l-2] | |
var r = Game.random.int(0,words.count) | |
if (is_used(r)) { | |
return Words.get_random(l) | |
} else { | |
__used.add(r) | |
return words[r] | |
} | |
} | |
static to_array(word){ | |
var arr = [] | |
for (l in word) { | |
arr.add(Letters.to_id(l)) | |
} | |
return arr | |
} | |
} | |
class Letters { | |
static init() { | |
__used = [] | |
} | |
static is_used(i) { | |
return Utils.list_has(__used, i) | |
} | |
static clear_used(){ | |
__used = [] | |
} | |
static get_random() { | |
if (__used.count == 26) Fiber.abort("we dont have any letters anymore") | |
var r = Game.random.int(1,27) | |
if (is_used(r)) { | |
return Letters.get_random() | |
} else { | |
__used.add(r) | |
return r | |
} | |
} | |
static to_id(i){ | |
if(i == "A") { | |
return 1 | |
} else if(i == "B") { | |
return 2 | |
} else if(i == "C") { | |
return 3 | |
} else if(i == "D") { | |
return 4 | |
} else if(i == "E") { | |
return 5 | |
} else if(i == "F") { | |
return 6 | |
} else if(i == "G") { | |
return 7 | |
} else if(i == "H") { | |
return 8 | |
} else if(i == "I") { | |
return 9 | |
} else if(i == "J") { | |
return 10 | |
} else if(i == "K") { | |
return 11 | |
} else if(i == "L") { | |
return 12 | |
} else if(i == "M") { | |
return 13 | |
} else if(i == "N") { | |
return 14 | |
} else if(i == "O") { | |
return 15 | |
} else if(i == "P") { | |
return 16 | |
} else if(i == "Q") { | |
return 17 | |
} else if(i == "R") { | |
return 18 | |
} else if(i == "S") { | |
return 19 | |
} else if(i == "T") { | |
return 20 | |
} else if(i == "U") { | |
return 21 | |
} else if(i == "V") { | |
return 22 | |
} else if(i == "W") { | |
return 23 | |
} else if(i == "X") { | |
return 24 | |
} else if(i == "Y") { | |
return 25 | |
} else if(i == "Z") { | |
return 26 | |
} | |
} | |
static from_id(i) { | |
if(i == 1) { | |
return "A" | |
} else if(i == 2) { | |
return "B" | |
} else if(i == 3) { | |
return "C" | |
} else if(i == 4) { | |
return "D" | |
} else if(i == 5) { | |
return "E" | |
} else if(i == 6) { | |
return "F" | |
} else if(i == 7) { | |
return "G" | |
} else if(i == 8) { | |
return "H" | |
} else if(i == 9) { | |
return "I" | |
} else if(i == 10) { | |
return "J" | |
} else if(i == 11) { | |
return "K" | |
} else if(i == 12) { | |
return "L" | |
} else if(i == 13) { | |
return "M" | |
} else if(i == 14) { | |
return "N" | |
} else if(i == 15) { | |
return "O" | |
} else if(i == 16) { | |
return "P" | |
} else if(i == 17) { | |
return "Q" | |
} else if(i == 18) { | |
return "R" | |
} else if(i == 19) { | |
return "S" | |
} else if(i == 20) { | |
return "T" | |
} else if(i == 21) { | |
return "U" | |
} else if(i == 22) { | |
return "V" | |
} else if(i == 23) { | |
return "W" | |
} else if(i == 24) { | |
return "X" | |
} else if(i == 25) { | |
return "Y" | |
} else if(i == 26) { | |
return "Z" | |
} | |
} | |
} | |
class Key { | |
static callback { __cb } | |
static callback=(v) { __cb=v } | |
static init() { | |
__cb = null | |
__last_pressed = [] | |
} | |
static clear_pressed() { | |
__last_pressed = [] | |
} | |
static update() { | |
for (i in 1...27) { | |
if (TIC.key(i) && Utils.list_has(__last_pressed,i)) { | |
return | |
} else if (TIC.key(i)) { | |
if (__cb != null) { | |
__cb.call(i) | |
__last_pressed.add(i) | |
} | |
return | |
} | |
} | |
clear_pressed() | |
} | |
} | |
class Point { | |
x { _x } | |
y { _y } | |
x=(v) { _x=v } | |
y=(v) { _y=v } | |
construct new(x,y) { | |
_x = x | |
_y = y | |
} | |
} | |
class Food is Point { | |
construct new(x,y) { super(x,y) } | |
draw() { | |
TIC.rect(x*8, y*8, 8, 8, 2) | |
} | |
} | |
class Direction { | |
static up { __up } | |
static down { __down } | |
static left { __left } | |
static right { __right } | |
static up_id { 1 } | |
static right_id { 2 } | |
static down_id { 4 } | |
static left_id { 8 } | |
static init() { | |
__up = Direction.new(1,Point.new(0,-1)) | |
__down = Direction.new(2,Point.new(0,1)) | |
__left = Direction.new(4,Point.new(-1,0)) | |
__right = Direction.new(8,Point.new(1,0)) | |
} | |
static get(d) { | |
if (d == 1) { | |
return __up | |
}else if (d == 2) { | |
return __right | |
}else if (d == 4) { | |
return __down | |
}else if (d == 8) { | |
return __left | |
} | |
} | |
id { _id } | |
vec { _vec } | |
letters { _letters } | |
construct new(id,vec) { | |
_id = id | |
_vec = vec | |
_letters = [] | |
_matched = [] | |
} | |
set_letters(l) { | |
_letters = l | |
} | |
match_letter(id) { | |
if (_letters.count > 0) { | |
return _letters[0] == id | |
} | |
return false | |
} | |
remove_letter(id) { | |
return Utils.list_remove(_letters, id) | |
} | |
pressed() { | |
for (k in _letters) { | |
if (TIC.key(k)){ | |
return true | |
} | |
} | |
return false | |
} | |
} | |
class BodyPart is Point { | |
tid { _tid } | |
tid=(v) { _tid=v } | |
construct new(tid,x,y) { | |
super(x,y) | |
_tid = tid | |
} | |
draw() { | |
} | |
} | |
class Snake { | |
head { _body[_body.count-1] } | |
neck { _body[_body.count-2] } | |
tail { _body[0] } | |
body { _body } | |
construct new(d,x,y) { | |
_body = [] | |
if (d == 0) { | |
_body.add(BodyPart.new(0,x,y+2)) | |
_body.add(BodyPart.new(0,x,y+1)) | |
_body.add(BodyPart.new(0,x,y)) | |
_next_dir = Direction.up | |
} else if (d == 1) { | |
_body.add(BodyPart.new(0,x-2,y)) | |
_body.add(BodyPart.new(0,x-1,y)) | |
_body.add(BodyPart.new(0,x,y)) | |
_next_dir = Direction.right | |
} else if (d == 2) { | |
_body.add(BodyPart.new(0,x,y-2)) | |
_body.add(BodyPart.new(0,x,y-1)) | |
_body.add(BodyPart.new(0,x,y)) | |
_next_dir = Direction.down | |
} else if (d == 3) { | |
_body.add(BodyPart.new(0,x+2,y)) | |
_body.add(BodyPart.new(0,x+1,y)) | |
_body.add(BodyPart.new(0,x,y)) | |
_next_dir = Direction.left | |
} | |
switch_dir() | |
_can_switch = true | |
Timer.schedule(1,Fn.new { | |
Key.callback = Fn.new {|i| | |
onkeypressed(i) | |
} | |
}) | |
} | |
switch_dir() { | |
if (_next_dir == Direction.left || _next_dir == Direction.right) { | |
var arr1 = [] | |
var arr2 = [] | |
if (Game.diff > 1) { | |
var w1 = Words.get_random(Game.diff) | |
var w2 = Words.get_random(Game.diff) | |
arr1 = Words.to_array(w1) | |
arr2 = Words.to_array(w2) | |
} else { | |
arr1.add(Letters.get_random()) | |
arr2.add(Letters.get_random()) | |
} | |
Direction.up.set_letters(arr1) | |
Direction.down.set_letters(arr2) | |
_canmovedirs = [Direction.up,Direction.down] | |
} else { | |
var arr1 = [] | |
var arr2 = [] | |
if (Game.diff > 1) { | |
var w1 = Words.get_random(Game.diff) | |
var w2 = Words.get_random(Game.diff) | |
arr1 = Words.to_array(w1) | |
arr2 = Words.to_array(w2) | |
} else { | |
arr1.add(Letters.get_random()) | |
arr2.add(Letters.get_random()) | |
} | |
Direction.right.set_letters(arr1) | |
Direction.left.set_letters(arr2) | |
_canmovedirs = [Direction.right,Direction.left] | |
} | |
Words.clear_used() | |
Letters.clear_used() | |
} | |
get_tid(t,x,y) { | |
if (x == 0) { | |
if (y > 0) { | |
t = t | 0x00000001 | |
} else { | |
t = t | 0x00000008 | |
} | |
} else if (y == 0) { | |
if (x > 0) { | |
t = t | 0x00000002 | |
} else { | |
t = t | 0x00000004 | |
} | |
} | |
return t | |
} | |
draw() { | |
var rp = Game.lvl*30 * 8 | |
var b = null | |
var nb = null | |
var pb = null | |
var tex = 16 | |
var dx = 0 | |
var dy = 0 | |
var t_ = 0 | |
for (i in 1..._body.count-1) { | |
pb = _body[i-1] | |
nb = _body[i+1] | |
b = _body[i] | |
tex = 32 | |
t_ = 0 | |
dx = b.x - pb.x | |
dy = b.y - pb.y | |
t_ = get_tid(t_,dx,dy) | |
dx = b.x - nb.x | |
dy = b.y - nb.y | |
t_ = get_tid(t_,dx,dy) | |
TIC.spr(tex+t_, b.x*8-rp, b.y*8, 0,1) | |
} | |
b = neck | |
var rot = 0 | |
if (head.x < b.x) { | |
rot = 3 | |
} else if (head.x > b.x) { | |
rot = 1 | |
} else if (head.y > b.y) { | |
rot = 2 | |
} | |
TIC.spr(tex+1, head.x*8-rp, head.y*8, 0,1,0,rot) | |
b = _body[1] | |
rot = 0 | |
if (tail.x < b.x) { | |
rot = 3 | |
} else if (tail.x > b.x) { | |
rot = 1 | |
} else if (tail.y > b.y) { | |
rot = 2 | |
} | |
TIC.spr(tex, tail.x*8-rp, tail.y*8, 0,1,0,rot) | |
var lt = "" | |
for (dir in _canmovedirs) { | |
if (dir.letters.count > 0) { | |
for (l in dir.letters) { | |
lt = lt + Letters.from_id(l) | |
} | |
if (dir.id == 4) { | |
TIC.print(lt, (head.x+dir.vec.x)*8+1-(dir.letters.count-1)*6-rp, (head.y+dir.vec.y)*8+2, 0,true) | |
TIC.print(lt, (head.x+dir.vec.x)*8+1-(dir.letters.count-1)*6-rp, (head.y+dir.vec.y)*8+1, 2,true) | |
} else { | |
TIC.print(lt, (head.x+dir.vec.x)*8+1-rp, (head.y+dir.vec.y)*8+2, 0,true) | |
TIC.print(lt, (head.x+dir.vec.x)*8+1-rp, (head.y+dir.vec.y)*8+1, 2,true) | |
} | |
} | |
lt = "" | |
} | |
} | |
got_food(d) { | |
if (head.x+d.x != Game.food.x || head.y+d.y != Game.food.y) return false | |
return true | |
} | |
move() { | |
if (!_can_switch) { | |
switch_dir() | |
_can_switch = true | |
} | |
var nx = head.x + _next_dir.vec.x | |
var ny = head.y + _next_dir.vec.y | |
if (TIC.mget(nx,ny) == 1) { | |
Game.fsm.set("gameover") | |
TIC.sfx(34,20,-1,3,15) | |
} | |
if (got_food(_next_dir.vec)) { | |
_body.add(BodyPart.new(0,Game.food.x,Game.food.y)) | |
Game.spawn_food() | |
Game.add_score() | |
TIC.sfx(32,40,-1,3,15) | |
} else { | |
var t = tail | |
_body.removeAt(0) | |
t.x = head.x + _next_dir.vec.x | |
t.y = head.y + _next_dir.vec.y | |
_body.add(t) | |
} | |
} | |
turn(dir) { | |
_next_dir = dir | |
switch_dir() | |
} | |
update() { | |
} | |
onkeypressed(i) { | |
if (!_can_switch) return | |
var was_removed = false | |
for (dir in _canmovedirs) { | |
if (dir.match_letter(i)) { | |
TIC.sfx(33,40,-1,2,15) | |
dir.remove_letter(i) | |
if (dir.letters.count == 0) { | |
turn(dir) | |
return | |
} | |
was_removed = true | |
} | |
} | |
if (was_removed) return | |
_can_switch = false | |
for (dir in _canmovedirs) { | |
dir.set_letters([]) | |
} | |
} | |
} | |
class FSM { | |
current { _current } | |
states { _states } | |
construct new() { | |
_states = {} | |
} | |
add(s) { | |
if (_states.containsKey(s.name)) { | |
Fiber.abort("state with name: %(s.name) already exists") | |
} | |
_states[s.name] = s | |
s.init() | |
} | |
remove(n) { | |
var s = _states[n] | |
if (s != null) { | |
if (_current == s) { | |
_current.onleave(null) | |
_current = null | |
} | |
_states.remove(n) | |
} | |
} | |
set(n) {set(n,null,null)} | |
set(n,ed) {set(n,ed,null)} | |
set(n,ed,ld) { | |
var s = _states[n] | |
if (s != null) { | |
if (_current != null) { | |
_current.onleave(ld) | |
} | |
s.onenter(ed) | |
_current = s | |
} | |
} | |
update(dt){ | |
if (_current != null) { | |
_current.update(dt) | |
} | |
} | |
draw() { | |
if (_current != null) { | |
_current.draw() | |
} | |
} | |
} | |
class State { | |
name { _name } | |
construct new(n) { | |
_name = n | |
} | |
init() { } | |
onenter(d) { } | |
onleave(d) { } | |
update(dt) { } | |
draw() { } | |
} | |
class PlayState is State { | |
construct new() { | |
super("play") | |
} | |
init(){ | |
_remap = Fn.new { |i, x, y| | |
if (i >=11 && i < 16) { | |
return 0 | |
} | |
return i | |
} | |
} | |
onenter(d) { | |
_t = 0 | |
Game.score = 0 | |
Game.speed = 2 | |
Game.snake = null | |
Game.food = null | |
var n = false | |
var lidx = Game.lvl*30 | |
for (y in 0...17) { | |
for (x in lidx...lidx+30) { | |
n = TIC.mget(x,y) | |
// TIC.trace(n) | |
if (n == 12) { | |
Game.snake = Snake.new(0,x,y) | |
} else if (n == 13) { | |
TIC.trace("SPAWN") | |
Game.snake = Snake.new(1,x,y) | |
} else if (n == 14) { | |
Game.snake = Snake.new(2,x,y) | |
} else if (n == 15) { | |
Game.snake = Snake.new(3,x,y) | |
} | |
} | |
} | |
Game.spawn_food() | |
} | |
onleave(d) { | |
} | |
update(dt) { | |
if (TIC.keyp(27)) { // 0 | |
Game.fsm.set("menu") | |
return | |
} | |
_t = _t+1 | |
if (Game.snake != null) { | |
Game.snake.update() | |
if (_t%(60/Game.speed).floor == 0) { | |
Game.snake.move() | |
} | |
} | |
} | |
draw() { | |
TIC.map(Game.lvl * 30, 0, 30, 17, 0, 0, 0, 1, _remap) | |
if (Game.food != null) { | |
TIC.spr(2, Game.food.x*8-(Game.lvl*30*8), Game.food.y*8, 0) | |
} | |
if (Game.snake != null) { | |
Game.snake.draw() | |
} | |
TIC.print("SCORE: %(Game.score)", 190, 1, 2) | |
} | |
} | |
class GameOverState is State { | |
construct new() { | |
super("gameover") | |
} | |
onenter(d){ | |
_texts = [] | |
_complete = false | |
if (Game.score >= 20) { | |
_main = Text.new("LEVEL COMPLETE",64,28,1,2) | |
_complete = true | |
} else { | |
_main = Text.new("GAME OVER",64,28,1,2) | |
} | |
_score = Text.new("score: %(Game.score)",90,50,1,1) | |
_time = Text.new("time: %(0)",90,60,1,1) | |
_playtext = Text.new("press z to play next",62,100,1,1) | |
_menutext = Text.new("press x exit to menu",62,110,1,1) | |
_texts.add(_main) | |
_texts.add(_time) | |
_texts.add(_score) | |
_texts.add(_playtext) | |
_texts.add(_menutext) | |
} | |
update(dt) { | |
if(TIC.btnp(4)) { // z | |
if (_complete) { | |
Game.lvl = Game.lvl + 1 | |
if(Game.lvl > 2){ | |
Game.lvl = 0 | |
Game.diff = Game.diff + 1 | |
if (Game.diff > 5) { | |
Game.diff = 5 | |
} | |
} | |
} | |
Game.fsm.set("play") | |
} else if(TIC.btnp(5)) { // z | |
Game.fsm.set("menu") | |
} | |
} | |
draw() { | |
for (t in _texts) { | |
t.draw() | |
} | |
} | |
} | |
class MenuState is State { | |
construct new() { | |
super("menu") | |
} | |
init(){ | |
_sel = 0 | |
_title = Text.new("TSNAKE",84,40,5,2) | |
_s = Text.new(">",78,80,2,1) | |
_p1 = Text.new("play",88,80,2,1) | |
_diff = Text.new("difficulty 1",88,90,2,1) | |
_lvltxt = Text.new("level %(Game.lvl)",88,100,2,1) | |
_mustxt = Text.new("music %(Game.music ? "on" : "off")",88,110,2,1) | |
} | |
onenter(d){ | |
upd_diff() | |
upd_lvl() | |
upd_mus() | |
if (Game.music) { | |
// TIC.music(3) | |
} | |
} | |
upd_diff() { | |
_diff.text = "difficulty %(Game.diff)" | |
} | |
upd_lvl() { | |
_lvltxt.text = "level %(Game.lvl)" | |
} | |
upd_mus() { | |
_mustxt.text = "music %(Game.music ? "on" : "off")" | |
} | |
update(dt) { | |
if(TIC.keyp(50) || TIC.btnp(4)) { // z | |
Game.fsm.set("play") | |
} | |
if(TIC.btnp(0)) { | |
_sel = Maths.mod(_sel-1, 4) | |
_s.y = 80 + _sel*10 | |
} else if(TIC.btnp(1)) { | |
_sel = (_sel+1)%4 | |
_s.y = 80 + _sel*10 | |
} else if(TIC.btnp(2)) { | |
if (_sel == 1) { | |
Game.diff = Game.diff - 1 | |
if (Game.diff < 1) { | |
Game.diff = 1 | |
} | |
upd_diff() | |
} else if (_sel == 2) { | |
Game.lvl = Game.lvl - 1 | |
if (Game.lvl < 0) Game.lvl = 0 | |
upd_lvl() | |
} else if (_sel == 3) { | |
Game.music = false | |
upd_mus() | |
} | |
} else if(TIC.btnp(3)) { | |
if (_sel == 1) { | |
Game.diff = Game.diff + 1 | |
if (Game.diff > 5) { | |
Game.diff = 5 | |
} | |
upd_diff() | |
} else if (_sel == 2) { | |
Game.lvl = Game.lvl + 1 | |
if (Game.lvl > 2) Game.lvl = 2 | |
upd_lvl() | |
} else if (_sel == 3) { | |
Game.music = true | |
upd_mus() | |
} | |
} | |
} | |
draw() { | |
_title.color = 3 | |
_title.y = 41 | |
_title.draw() | |
_title.color = 2 | |
_title.y = 40 | |
_title.draw() | |
_title.color = 1 | |
_title.y = 39 | |
_title.draw() | |
_s.draw() | |
_p1.draw() | |
_lvltxt.draw() | |
_diff.draw() | |
_mustxt.draw() | |
} | |
} | |
class Game is TIC { | |
static diff { __diff } | |
static diff=(v) { __diff=v } | |
static speed { __speed } | |
static speed=(v) { __speed=v } | |
static food { __food } | |
static food=(v) { __food=v } | |
static snake { __snake } | |
static snake=(v) { __snake=v } | |
static random { __rnd } | |
static timescale { __ts } | |
static timescale=(v) { __ts=v } | |
static fsm { __fsm } | |
static score { __score } | |
static score=(v) { __score=v } | |
static lvl { __lvl } | |
static lvl=(v) { __lvl=v } | |
static music { __music } | |
static music=(v) { __music=v } | |
construct new(){ | |
Timer.init() | |
Key.init() | |
Words.init() | |
Letters.init() | |
Direction.init() | |
__diff = 1 | |
__speed = 2 | |
_t = 0 | |
__lvl = 0 | |
__score = 0 | |
__ts = 1 | |
__music = false | |
__rnd = Random.new() | |
_lastdir = 2 | |
__fsm = FSM.new() | |
__fsm.add(GameOverState.new()) | |
__fsm.add(MenuState.new()) | |
__fsm.add(PlayState.new()) | |
__fsm.set("menu") | |
} | |
static spawn_food() { | |
var np = Point.new(__rnd.int(1,28)+Game.lvl*30,__rnd.int(1,15)) | |
if (TIC.mget(np.x, np.y) == 1) { | |
spawn_food() | |
return | |
} | |
for (b in __snake.body) { | |
if(b.x == np.x && b.y == np.y){ | |
spawn_food() | |
return | |
} | |
} | |
__food = np | |
} | |
static add_score() { | |
__score = __score + 1 | |
if (__score%5 == 0) { | |
__speed = __speed + 1 | |
} | |
} | |
TIC(){ | |
Key.update() | |
__fsm.update(_dt) | |
Timer.update(1/60) | |
TIC.cls(0) | |
__fsm.draw() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment