aboutsummaryrefslogtreecommitdiff
path: root/src/world.moon
diff options
context:
space:
mode:
Diffstat (limited to 'src/world.moon')
-rw-r--r--src/world.moon368
1 files changed, 368 insertions, 0 deletions
diff --git a/src/world.moon b/src/world.moon
new file mode 100644
index 0000000..c7b106c
--- /dev/null
+++ b/src/world.moon
@@ -0,0 +1,368 @@
+-- Handles singleton logic
+
+mod = ...
+connect = require "connect"
+lobby = require "lobby"
+joined = require "joined"
+party = require "party"
+char = require "char"
+import Character from char
+import Enemy from char
+import Party from party
+player = require "player"
+import RemotePlayer from player
+import LocalPlayer from player
+main = require "main"
+room = require "room"
+import Room from room
+import LobbyRoom from room
+ui = require "ui"
+ability = require "ability_reg"
+
+class Server
+ new:() =>
+ @server = true
+ @client = false
+ am.eval_js(connect)
+ am.eval_js(lobby)
+ @lobby_id = am.eval_js("GLOBAL.lobby_id")
+ @game_state = "lobby" --lobby, room_entry, room_players, room_battle_animate, victory, camp_entry, camp_players_animate, defeat, done
+ @game_state_extra = 0
+ @players = {} --[peer_id] = tbl
+ @set_actions = {} --[peer_id] = "name"
+ @player_party = nil -- the party, created at campaign start
+ @host = nil --who is the lobby host, with the power to start the game?
+ @enemy_party = nil -- The enemy party
+ @updates = {}
+ @dead_players = {} --[peer_id] = true
+ @cr = 1
+ player_joined:(msg)=>
+ peer = msg.peer
+ @players[peer] = RemotePlayer(peer,nil,char.classes.Tumbler)
+ am.eval_js(string.format("GLOBAL.broadcast(%q)",am.to_json({msg:"info_player_joined",uname:peer,class:"Tumbler"})))
+ if @host == nil
+ @host = peer
+ request_class_change:(msg)=>
+ if @game_state == "lobby"
+ if @players[msg.peer]
+ @players[msg.peer]\set_class(char.classes[msg.class])
+ else
+ @players[msg.peer] = RemotePlayer(msg.peer,nil,char.classes[msg.class])
+ am.eval_js(string.format("GLOBAL.send_message(%q,%q)",msg.peer,am.to_json({msg: "confirm_class_change", class: msg.class})))
+ am.eval_js(string.format("GLOBAL.broadcast(%q)",am.to_json({msg:"info_class_change",uname:msg.peer,class:msg.class})))
+ else
+ am.eval_js(string.format("GLOBAL.send_message(%q,%q)",msg.peer,am.to_json({msg: "deny_class_change", class:@players[msg.peer].class})))
+ request_campaign_start:(msg)=>
+ if msg.peer == @host and @game_state == "lobby"
+ @player_party = Party!
+ --Set everyone's position, hp, ect.
+ for _, chartbl in pairs(@players)
+ chartbl.position = chartbl.class.default_position
+ chartbl.hp = chartbl.class.default_hp
+ @player_party\add_member(chartbl)
+ @campaign_start!
+ am.eval_js(string.format("GLOBAL.broadcast(%q)",am.to_json({msg:"info_campaign_start",time_ref:@player_start_time})))
+ campaign_start: =>
+ @game_state = "room_entry"
+ @player_start_time = am.eval_js("new Date().getTime()")
+ room = Room.generate(@cr)
+ @room = room
+ @enemy_party = @generate_enemies!
+ @enemy_party\set_room(room)
+ @player_party\set_room(room)
+ am.eval_js(string.format("GLOBAL.broadcast(%q)",am.to_json({
+ msg: "info_enemy_party",
+ data: @enemy_party\serialize!
+ })))
+ room\distribute_party(@player_party,@enemy_party)
+ am.eval_js(string.format("GLOBAL.broadcast(%q)",am.to_json({msg:"info_room",data:room\serialize!,time_ref:@player_start_time})))
+ @game_state = "room_players"
+
+ request_player_list:(msg)=>
+ player_ser = {}
+ for peerid, player in pairs(@players)
+ player_ser[peerid] = player\serialize!
+ am.eval_js(string.format("GLOBAL.broadcast(%q)",am.to_json({msg:"respond_player_list", data:player_ser})))
+ set_action: (msg)=>
+ if @game_state == "room_players"
+ if not @dead_players[msg.peer]
+ @set_actions[msg.peer] = ability[msg.action]
+ update:() =>
+ msg = am.eval_js("GLOBAL.get_message()")
+ if msg != nil
+ if msg.msg == "data"
+ info = am.parse_json(msg.data)
+ info.peer = msg.peer -- server messages have an extra "peer" field that the client didn't add.
+ if @[info.msg]
+ @[info.msg](@,info)
+ else
+ print("Failed to find server message handler:",msg,"no handler",info.msg)
+ else
+ print("Msg was nil")
+ --actual game loop
+ if @game_state == "room_players"
+ if am.eval_js("new Date().getTime()") > @player_start_time + 6000
+ --Generate some random actions from npcs
+ npc_actions = {}
+ used_actions = {}
+ party_index = {}
+ character_index = {}
+ for uname, npc in pairs(@enemy_party.members)
+ npc_actions[uname] = npc\select_action!
+ table.insert(used_actions, npc_actions[uname])
+ party_index[npc_actions[uname]] = @enemy_party
+ character_index[npc_actions[uname]] = npc
+ total_actions = {}
+ for k,v in pairs(npc_actions)
+ total_actions[k] = v.__name
+ for k,v in pairs(@set_actions)
+ total_actions[k] = v.__name
+ table.insert(used_actions, v)
+ party_index[v] = @player_party
+ character_index[v] = @player_party\member(k)
+ --Lock in actions, and send it back out (500 ms)
+ table.sort(used_actions, (a,b) ->
+ a.speed < b.speed
+ )
+ -- actually do the actions
+ for k,v in ipairs(used_actions)
+ tchar = character_index[v]
+ v.__class.use(@,party_index[v],tchar)
+ am.eval_js(string.format("GLOBAL.broadcast(%q)",am.to_json({
+ msg:"info_actions",
+ data: total_actions
+ })))
+ --sort by speed and apply
+ @game_state = "room_battle_animate"
+ @set_actions = {}
+ if @game_state == "room_battle_animate" --only exists for 1 tick, calc dammge, check if room is done, check if we're defeated, ect.
+ @calculate_damage
+ @player_start_time = am.eval_js("new Date().getTime()")+500 --500 ms for animations
+ @game_state = "room_players"
+ am.eval_js(string.format("GLOBAL.broadcast(%q)",am.to_json({
+ msg:"info_timeref",
+ time_ref:@player_start_time
+ })))
+ dead_characters = {}
+ for uname, char in pairs(@player_party.members)
+ if char.data.hp <= 0
+ table.insert(dead_characters,uname)
+ char\die!
+ @player_party\remove_member(char)
+ @dead_players[uname] = true
+ for uname, char in pairs(@enemy_party.members)
+ if char.data.hp <= 0
+ table.insert(dead_characters,uname)
+ char\die!
+ @enemy_party\remove_member(char)
+ am.eval_js(string.format("GLOBAL.broadcast(%q)",am.to_json({
+ msg:"info_deaths",
+ data:dead_characters
+ })))
+ if @player_party\nmembers! == 0
+ @game_state = "defeat"
+ elseif @enemy_party\nmembers! == 0
+ am.eval_js(string.format("GLOBAL.broadcast(%q)",am.to_json({
+ msg:"info_loot"
+ time_ref:@player_start_time
+ --Don't actually do loot, just go to the next room
+ })))
+ @player_start_time = am.eval_js("new Date().getTime()")
+ @game_state = "victory"
+ if @game_state == "defeat"
+ am.eval_js(string.format("GLOBAL.broadcast(%q)",am.to_json({
+ msg:"info_defeat"
+ })))
+ @game_state = "done"
+ if @game_state == "victory"
+ if am.eval_js("new Date().getTime()") > @player_start_time + 6000 -- a few seconds for victory! (and animations)
+ @cr += 1
+ @campaign_start!
+
+ calculate_dammage:() =>
+ print("calculating dammage...")
+
+ generate_enemies:() =>
+ enemies = {}
+ tcr = @cr
+ possible_enemies = {}
+ for k,v in pairs(char.enemies)
+ table.insert(possible_enemies,v)
+ enemy_party = Party!
+ while tcr > 0 and #possible_enemies > 0
+ filtered_enemies = {}
+ for _, enemy in pairs(possible_enemies)
+ if enemy.cr <= tcr
+ table.insert(filtered_enemies,enemy)
+ table.shuffle(filtered_enemies)
+ rng_enemy = table.remove(filtered_enemies)
+ tcr = tcr - rng_enemy.cr
+ enemy_party\add_member(Enemy(nil,rng_enemy))
+ enemy_party
+
+class World
+ new:() =>
+ @client = true
+ @server = false
+ am.eval_js(connect)
+ @players = {}
+ @player_party = Party!
+ @enemy_party = nil
+ main.root("world_characters")\append(@player_party.node)
+ @parties = {@player_party}
+ @node = am.group!
+ @node\append(@player_party.node)
+ @node\action(coroutine.create(()->
+ while true
+ coroutine.yield!
+ ))
+ @localplayer = nil
+ join:(id) =>
+ am.eval_js(joined)
+ am.eval_js("CLIENT.join('" .. id .. "');")
+ client_open:() =>
+ am.eval_js("CLIENT.open")
+ client_id:() =>
+ am.eval_js("CLIENT.peer")
+ confirm_class_change: (msg) =>
+ @localplayer\set_class(char.classes[msg.class])
+ deny_class_change: (msg) =>
+ @localplayer\set_class(char.classes[msg.class])
+ respond_player_list: (msg) =>
+ for peerid, chardata in pairs(msg.data)
+ if not @player_party\member(peerid)
+ if peerid == am.eval_js("CLIENT.peer._id")
+ @localplayer = Character.deserialize(chardata)
+ @player_party\add_member(@localplayer)
+ @localplayer\enter_room(@player_party.room)
+ else
+ newplayer = Character.deserialize(chardata)
+ @player_party\add_member(newplayer)
+ newplayer\enter_room(@player_party.room)
+ else
+ print("Do nothing...")
+ info_class_change: (msg) =>
+ if msg.uname == @localplayer.uname
+ return
+ if not @player_party\member(msg.uname)
+ @player_party\add_member(Character.deserialize(msg.class))
+ else
+ @player_party\member(msg.uname)\set_class(char.classes[msg.class])
+ info_player_joined: (msg) =>
+ if msg.uname == am.eval_js("CLIENT.peer._id")
+ if @localplayer != nil
+ return
+ @localplayer = LocalPlayer(msg.uname, {}, char.classes[msg.class])
+ @player_party\add_member(@localplayer)
+ @localplayer\enter_room(@player_party.room)
+ elseif not @player_party\member(msg.uname)
+ newplayer = RemotePlayer(msg.uname, nil, char.classes[msg.class])
+ @player_party\add_member(newplayer)
+ newplayer\enter_room(@player_party.room)
+ else
+ print("Do nothing")
+ info_campaign_start: (msg) =>
+ lobby_menu = require "lobby_menu"
+ create_party_menu = require "create_party_menu"
+ if create_party_menu.loaded
+ create_party_menu.unload!
+ if lobby_menu.loaded
+ lobby_menu.unload!
+ battle_menu = require "battle_menu"
+ battle_menu.load!
+ ui.fadeout!
+ @time_ref = msg.time_ref
+ info_room: (msg) =>
+ @room = Room.deserialize(msg.data)
+ @time_ref = msg.time_ref
+ @set_room(@room)
+ battle_menu = require "battle_menu"
+ battle_menu.victory = false
+ main.root\remove("infocard")
+ info_timeref: (msg) =>
+ main.root\remove("infocard")
+ @time_ref = msg.time_ref
+ info_enemy_party: (msg) =>
+ if @enemy_party
+ @node\remove(@enemy_party.rnode)
+ @enemy_party = Party.deserialize(msg.data)
+ @enemy_party\set_room(@room)
+ if @room.__class != LobbyRoom
+ @enemy_party\set_room(@room)
+ battle_menu = require "battle_menu"
+ battle_menu.victory = false
+ main.root\remove("infocard")
+ --@node\append(@enemy_party.node)
+ info_defeat: (msg) =>
+ battle_menu = require("battle_menu")
+ defeat_menu = require("defeat_menu")
+ table.insert(main.action_queue,{battle_menu.unload, {}})
+ table.insert(main.action_queue,{defeat_menu.load,{}})
+ info_loot: (msg) =>
+ @time_ref = msg.time_ref
+ battle_menu = require "battle_menu"
+ battle_menu.victory = true
+ main.root\remove("infocard")
+ info_updates: (msg) =>
+ for uname, updated in pairs(msg.data)
+ tchar = @player_party\member(uname) or @enemy_party\member(uname)
+ for k,v in pairs(updated)
+ tchar.data[k] = v
+ info_deaths: (msg) =>
+ for _, uname in pairs(msg.data)
+ if @player_party\member(uname)
+ tchar = @player_party\member(uname)
+ tchar\die!
+ @player_party\remove_member(tchar)
+ elseif @enemy_party\member(uname)
+ tchar = @enemy_party\member(uname)
+ tchar\die!
+ @enemy_party\remove_member(tchar)
+ info_actions: (msg) =>
+ for uname, action_name in pairs(msg.data)
+ action = ability[action_name]
+ if @player_party\member(uname)
+ action.use(@,@player_party,@player_party\member(uname))
+ ui.battle_log(string.format("%s used %s",@player_party\member(uname).class.name,action.text))
+ elseif @enemy_party\member(uname)
+ action.use(@,@enemy_party,@enemy_party\member(uname))
+ ui.battle_log(string.format("%s used %s",uname,action.text))
+ main.root\remove("infocard")
+ update: () =>
+ msg = am.eval_js("CLIENT.get()")
+ if msg != nil
+ info = am.parse_json(msg)
+ if @[info.msg]
+ @[info.msg](@,info)
+ else
+ print("Failed to find client message handler", info)
+ set_local: (player) =>
+ @localplayer = player
+ @player_party\add_member(player)
+ @localplayer\enter_room(@player_party.room)
+ set_room: (room) =>
+ @room = room
+ assert(@room, "cannot set a nil room")
+ assert(@room.load, "rooms must have a .load")
+ if @player_party.room
+ @player_party.room\unload!
+ --@node\remove(@player_party.room.node)
+ @room\load!
+ --@node\append(room.node)
+ @player_party\set_room(room)
+ if @enemy_party
+ if @enemy_party.room
+ @enemy_party.room\unload!
+ @enemy_party\set_room(@room)
+ --new_rat = Enemy(nil,char.enemies.Rat)
+ if @enemy_party
+ --@enemy_party\add_member(new_rat)
+ --@enemy_party\set_room(room)
+ @node\append(@enemy_party.rnode)
+ load: () =>
+ main.root("world_characters")\append(@node)
+
+
+mod["World"] = World
+mod["Server"] = Server
+mod