diff options
Diffstat (limited to 'src/char.moon')
| -rw-r--r-- | src/char.moon | 307 |
1 files changed, 307 insertions, 0 deletions
diff --git a/src/char.moon b/src/char.moon new file mode 100644 index 0000000..5e1a35c --- /dev/null +++ b/src/char.moon @@ -0,0 +1,307 @@ + +util = require "util" +broadphase = require "broadphase" +main = require "main" +constrain = require "constrain" +color = require "color" +room = require "room" +import LobbyRoom from room +ability_reg = require "ability_reg" + + +mod = ... +mod.characters = {} +mod.classes = {} +require "char_tank" +require "char_mage" +require "char_theif" +require "char_fool" +require "char_jugg" +mod.class_order = { + "Tumbler", + "Fire Breather", + "Juggler", + "Troubador", + "Juggernaut" +} +mod.class_order_rev = {} +for k,v in ipairs(mod.class_order) + mod.class_order_rev[v] = k +print("After requireing characters, mod.classes was",mod.classes) +mod.enemies = {} +--require "e_rat" +require "e_bethany" +require "e_ruminating_randy" +require "e_mopey_marvin" +require "e_sullen_salley" +require "e_child" +print("After requireing rat, mod.enemies was",mod.enemies) +--print("test") +--[[Stores a single input, and the time it was inputed]] +class KeyInput + new:(key = "<input>") => + @time = 0 + @key = key + @value = false + +--print "test" + +class AnimFrame + new:(anim,interupt,mode) => + @anim = anim + @interupt = interupt + @mode = mode + +class ActionInput + new:(action = "<input>") => + @time = 0 + @action = action + +mod.sprite_direction_co = () => + return () -> + while true + @stop_anim(@sprites.right) + @stop_anim(@sprites.left) + @stop_anim(@sprites.stop_right) + @stop_anim(@sprites.stop_left) + @stop_anim(@sprites.falling_left) + @stop_anim(@sprites.falling_right) + for input in *@inputs + if @velocity.x > 0.01 + @set_anim(@sprites.right,1,"loop") + break + elseif @velocity.x < -0.01 + @set_anim(@sprites.left,1,"loop") + break + coroutine.yield! + +mod.can_die_co = () => + return () -> + while not @dead + coroutine.yield! + + for k,v in pairs @sprites + if k ~= "idle" + @stop_anim(v) + if @sprites.die + @set_anim(@sprites.die,5) + coroutine.yield(true) + +mod.make_animate = (c) -> + assertf(c.sprites ~= nil, "Tried to animate something that had no .sprites: %q", c.__class.__name) + assertf(c.sprites.idle ~= nil and #c.sprites.idle > 0, "Tried to animate something without a .idle animation: %q", c.__class.__name) + c.anim_stack = {AnimFrame(c.sprites.idle,0,"loop")} + c.anim = c.sprites.idle + c.keyframe = 0 + c.animrate = c.animrate or 1 + c.anim_interupt = 0 + c.set_anim = (self,tbl,interupt,mode) -> + if type(tbl) ~= "table" + error("Tried to set anim to something that was not a table!",2) + if #tbl == 0 + error("Tried to set anim to an empty table",2) + if interupt > @anim_interupt + table.insert(@anim_stack,AnimFrame(tbl,interupt,mode)) + @anim = @anim_stack[#@anim_stack].anim + @anim_interupt = interupt + + c.stop_anim = (self,tbl,err_if_unable=false) -> + anim_found = false + for k,v in pairs @anim_stack + if v.anim == tbl + --print("Found anim to remove") + anim_found = true + table.remove(@anim_stack,k) + break + if err_if_unable + assertf(anim_found, "Could not find animation to remove") + @anim = @anim_stack[#@anim_stack].anim + @anim_interupt = @anim_stack[#@anim_stack].interupt + + c.node\action(coroutine.create(() -> + while not c.dead + c.keyframe = math.floor(am.current_time()*c.animrate) % #c.anim + spritename = c.anim[c.keyframe + 1] + assert(spritename, "Failed to find an appropriate image to draw.") + --print("Setting:",spritename) + c.node("sprite").source = spritename + coroutine.yield! + --we are dead + keyframe_0 = am.current_time() + while c.keyframe < #c.anim - 1 + c.keyframe = math.floor((am.current_time! - keyframe_0)*c.animrate) + assert(c.anim[c.keyframe + 1], "Failed to find an appropriate image to draw.") + c.node("sprite").source = c.anim[c.keyframe + 1] + coroutine.yield! + c\remove() + coroutine.yield(true) + )) + +mod.inherited = {} +hp_bar_width = 20 +--[[The character, extended to make both players and ai]] +class Character + @classes = {} + @players = {} -- players singleton, [peerid] = Character + new:(uname, data, charclass) => + assert(charclass, "Charclass may not be nil") + @uname = uname or false + @data = data or { + status: "active", + location: -1, + position: charclass.default_position + } + @class = charclass + assert(@class.name, "Character classes must have a name") + @calc_class_values! + @node = am.group! + + --print("Creating character!",uname,data,charclass) + @node\append(am.translate(0,0)\tag("char_translate")^ am.sprite(@class.sprite,color.white,"center","bottom")\tag("char_sprite")) + print("A character has been created!") + print(debug.traceback!) + --Draw healthbar + healthbar_trans = am.translate(0,60) + healthbar_left = am.sprite("data/bar_left.png", color.white,"left","center")\tag("hp_l") + healthbar_right = am.sprite("data/bar_right.png", color.white, "right","center")\tag("hp_r") + healthbar_bar = am.sprite("data/bar_mid.png", color.white,"left","center")\tag("hp_b") + healthbar_fill = am.sprite("data/bar_fill.png", color.white,"left","center")\tag("hp_f") + healthbar_scale = am.scale(hp_bar_width,1) + healthbar_fill_scale = am.scale(hp_bar_width + 1,1)\tag("hp_fill_scale") + healthbar_trans\append(am.translate(-hp_bar_width,0)^ healthbar_left) + healthbar_trans\append(am.translate(hp_bar_width,0)^ healthbar_right) + healthbar_trans\append(am.translate(-hp_bar_width/2,0)^ healthbar_scale^ healthbar_bar) + healthbar_trans\append(am.translate((-hp_bar_width/2) - 1,0)^ healthbar_fill_scale^ healthbar_fill) + @.node("char_sprite")\append(healthbar_trans) + --End draw healthbar + assert(@.__class.draw,"Characters must have a draw() method") + table.insert(mod.characters,@) + constrain(@,"set anim", (self,value) -> + assertf(type(value) == "table", "Tried to set anim on %q to something other than a table (%q)",@, type(value)) + assert(#value > 0, "Tried to set animation for char to something with 0 frames!") + ) + assert(@.__class != Character,"Character class must be subclassed") + --main.root("world_characters")\append(@node) + + __tostring: () => + return string.format( + "<%s, %s> at (%d)", + @.__class.__name, + (@class and @class.name or "no class"), + ( @data and @data.position or -1) + ) + + @__inherited: (c) => + assert(c, "Inheritance must exist") + assert(c.__name, "Inherited class must have a .__name") + @@.classes[c.__name] = c + mod.inherited[c.__name] = c + + calc_class_values: () => + for k,v in pairs(@class) + if k\match("^default") + field = k\match("^default_(.*)") + if type(v) == "function" + @data[field] = v! + else + @data[field] = v + + set_field: (name, value) => + assert(@data[name], "Field must exist to be set") + @data[name] = value + print("my data table is:",@data) + if name == "hp" + perc = (@data.hp / @data.maxhp) * 20 + @.node("hp_fill_scale").x = perc + + serialize: () => + print("Serializing char:",@) + print("Name:", @@__name) + print("uname:",@uname) + print("data:",@data) + data_abilities = {} + for i,ability in pairs(@data.abilities) + data_abilities[i] = ability.__name + data_copy = table.shallow_copy(@data) + data_copy.abilities = data_abilities + print("class.name:",@class.name) + ret = am.to_json({name:@@__name, uname:@uname, data:data_copy, class:@class.name}) + print("Ret is:",ret) + ret + + deserialize: (data) -> + print("Deserializing character") + tbl = am.parse_json(data) + if mod.classes[tbl.class] + data_abilities = {} + for i, ability_name in pairs(tbl.data.abilities) + data_abilities[i] = ability_reg[ability_name] + tbl.data.abilities = data_abilities + return mod.inherited[tbl.name](tbl.uname, tbl.data, mod.classes[tbl.class]) + elseif mod.enemies[tbl.class] + e = mod.Enemy(tbl.data, mod.enemies[tbl.class]) + e.uname = tbl.uname + return e + + + draw:(screenpos) => + print("draw") + remove: () => + @node\remove_all! + die: () => + @dead = true + print(@,"is dieing, node is",@.node,"and color is",color) + @.node("char_sprite")\append(am.line(vec2(-10,-10),vec2(10,10),5,color.bright)) + @.node("char_sprite")\append(am.line(vec2(10,-10),vec2(-10,10),5,color.bright)) + enter_room: (room) => + @room = room + print("Character",@,"entered room",room) + @.node("char_translate").y = room.floor_y + if room.__class == LobbyRoom + print("Class was lobbyRoom") + rng_x = math.random(-(main.width/2), (main.width/2)) + print("RNG x:",rng_x) + @.node("char_translate").x = rng_x + else + print("Class was not LobbyRoom") + x_pos = @room\player_location_of(@data.position) + print("Got x pos for",@,x_pos) + @.node("char_translate").x = x_pos + math.random(-15,15) --some random variance to stop stacking + set_class: (newclass) => + assert(newclass, "Cannot set a class to nil") + @class = newclass + @calc_class_values! + @.node("char_sprite").source = newclass.sprite + + set_position: (pos) => + @data.position = pos + + set_location: (loc) => + @data.location = loc + +mod.enemy_counter = 0 +class Enemy extends Character + new: (data, eclass) => + super(eclass.name .. ":" .. tostring(mod.enemy_counter), data, eclass) + mod.enemy_counter += 1 + nwuname: (uname, data, eclass) -> + @(data, eclass) + + mod.enemy_counter += 1 + __tostring: () => + return string.format("<%s> at (%d)",@uname, @data.position or 0) + + enter_room: (room) => --overload character's to get enemy locations + print("Character",@,"entered room",room) + @room = room + @.node("char_translate").y = @room.floor_y + @.node("char_translate").x = @room\enemy_location_of(@data.position) + + select_action: () => + return @class.select_action(@) + +mod["Character"] = Character +mod["KeyInput"] = KeyInput +mod["Enemy"] = Enemy +--Things that extend the character class +mod |
