cardsStartingHP=20 redLibraryPos={14,13} blueLibraryPos={5,13} redHeartPos={13,8} blueHeartPos={6,8} redManaPos={12,13} blueManaPos={7,13} redTurnBrazier={13,13} blueTurnBrazier={6,13} redGraveyardPos={15,13} blueGraveyardPos={4,13} redMatPos={10,12} blueMatPos={9,12} redStack={11,12} blueStack={8,12} switchPos={10,13} maxCopiesOfEachCard=3 BLUETILE=166 REDTILE=95 HN_REVERSE_DAMAGE = HN_CHOKING HN_TRAMPLE = HN_REALLY_STONED HN_DIES_EOT = HN_JAILED HN_TOKEN = HN_STONED COUNTERSPELLS=false BCODE_HEARTHSTONE=0xb44e function load_instance_149(lvl, parent_lvl) load_map_149(lvl) end -- this function is called when the betting ring map is loaded -- spawn the umpire/judge and some other stuff -- judge actually stores all of the game variables in a serialized array called judge_vars. -- This allows for instancing (but since then other ways have been figured out in lua do handle instanced variables! but this is one way) function load_map_149(lvl, load_on_the_fly) local map=get_map_ptr(lvl) local judge=spawn_at(0x220,9,13,lvl) judge:set_name("Umpire") judge:set_align(ALIGN_GOOD) judge.talk_line="Say reset to restart the game. Say give to get a starter set of cards to play with." judge.heartbeat_func="judge_heartbeat" local judge_vars = { game_on=false } judge.ai_misc_str=pickle(judge_vars) -- turn braizer map:destroy_pile(blueTurnBrazier[1],blueTurnBrazier[2]) map:add_item(blueTurnBrazier[1],blueTurnBrazier[2],1,Item(0x51e)) -- unlit map:destroy_pile(redTurnBrazier[1],redTurnBrazier[2]) map:add_item(redTurnBrazier[1],redTurnBrazier[2],1,Item(0x51e)) -- unlit -- switch map:destroy_pile(switchPos[1],switchPos[2]) map:add_item(switchPos[1],switchPos[2],1,Item(0x51c)) end -- heartbeat funcs are called every 1 sec -- here judge just sees if a player leaves the betting ring function judge_heartbeat(m) local judge_vars=unpickle(m.ai_misc_str) -- if server_config:get("server_id")=="X" then return end if judge_vars ~=nil and judge_vars.game_on then -- make sure players are both in map! local p=get_player_ptr(find_player(judge_vars.redname)) if p==nil or p.map_level~=m.map_level then send_npc_reply(-1, "Red player has left the betting ring and is disqualified!", m) judge_vars.game_on=false judge_vars.redname="" m.ai_misc_str=pickle(judge_vars) if p~=nil then send_message(p.id, "You have been disqualified for leaving the betting ring!"); end end p=get_player_ptr(find_player(judge_vars.bluename)) if judge_vars.bluename~="" and (p==nil or p.map_level~=m.map_level) then send_npc_reply(-1, "Blue player has left the betting ring and is disqualified!", m) judge_vars.game_on=false judge_vars.bluename="" m.ai_misc_str=pickle(judge_vars) if p~=nil then send_message(p.id, "You have been disqualified for leaving the betting ring!"); end end end end -- called when the player on red mat says 'reset' to the judge -- tidies up the battlefield and spawns all the npc libs, graveyards, etc function cards_reset(npc, id) local judge, judge_vars=get_judge_and_vars(npc.map_level) local p1=get_sent_ptr_xyz(redMatPos[1],redMatPos[2],npc.map_level) local map=get_map_ptr(npc.map_level) local testmode=server_config:get("server_id")=="X" --if server_config:get("server_id")~="A" and server_config:get("server_id")~="X" then -- send_npc_reply(-1,"Alpha server only!",npc) -- return --end if p1~=nil then p1=get_player_ptr(p1.id) end if p1==nil then send_npc_reply(-1,"Need player standing on red mat to be Red player!",judge) return else judge_vars.redname=p1.name end local p2=get_sent_ptr_xyz(blueMatPos[1],blueMatPos[2],npc.map_level) if p2~=nil then p2=get_player_ptr(p2.id) end if p2==nil then send_npc_reply(-1,"Playing in single player mode!",judge) -- if not testmode then return end judge_vars.bluename="" else judge_vars.bluename=p2.name end -- only red can reset local p3=get_player_ptr(id) if p3.x~=redMatPos[1] or p3.y~=redMatPos[2] then send_npc_reply(-1,"Game can only be reset by the red player!",judge) return end -- libraries local m if get_monster_ptr_xyz(redLibraryPos[1],redLibraryPos[2],npc.map_level)==nil then m=spawn_at(0x361,redLibraryPos[1],redLibraryPos[2],npc.map_level,true) m.code=0x129 m:set_name("Red Library") mkGood(m) end if get_monster_ptr_xyz(blueLibraryPos[1],blueLibraryPos[2],npc.map_level)==nil then m=spawn_at(0x361,blueLibraryPos[1],blueLibraryPos[2],npc.map_level,true) m.code=0x129 m:set_name("Blue Library") mkGood(m) end -- graveyards m=get_monster_ptr_xyz(redGraveyardPos[1],redGraveyardPos[2],npc.map_level) if m==nil then m=spawn_at(0x361,redGraveyardPos[1],redGraveyardPos[2],npc.map_level,true) m.code=0x12d m:set_name("Red GY") m.talk_line="script_cards_graveyard_talk" mkGood(m) end delete_inventory(m.id) refresh_mob_name(m) m=get_monster_ptr_xyz(blueGraveyardPos[1],blueGraveyardPos[2],npc.map_level) if m==nil then m=spawn_at(0x361,blueGraveyardPos[1],blueGraveyardPos[2],npc.map_level,true) m.code=0x12d m:set_name("Blue GY") m.talk_line="script_cards_graveyard_talk" mkGood(m) end delete_inventory(m.id) refresh_mob_name(m) -- shuffle cards from inv into deck npcs local failmsg=" deck is invalid (or some other fail) - need exactly 30 cards, and no more than "..maxCopiesOfEachCard.." copies of each card. Go and put any excess cards in the bank!" local bluelib local rc, redlib = shuffle_card_inv_into_library(p1.id, "red") if rc then send_npc_reply(-1, "Red's"..failmsg, judge) return end if p2~=nil then rc, bluelib = shuffle_card_inv_into_library(p2.id, "blue") if rc then send_npc_reply(-1, "Blue's"..failmsg, judge) if not testmode then return end end end -- delete all mobs for _x=1,18 do for _y=3,16 do local m=get_monster_ptr_xyz(_x,_y,npc.map_level) if is_permanent_or_heart(m) and (m.code~=BCODE_HEARTHSTONE or (m.y~=redHeartPos[2] or m.x~=redHeartPos[1] and m.x~=blueHeartPos[1])) then m.death_func="" -- don't call any gy funcs m.time_alive=0 end end end -- restore hearts for i,mp in ipairs({blueHeartPos, redHeartPos}) do local m=get_monster_ptr_xyz(mp[1],mp[2],npc.map_level) if m==nil then m=spawn_at(0x361,mp[1],mp[2],npc.map_level) end m.code=BCODE_HEARTHSTONE m:set_align(ALIGN_NEUTRAL) m.hp=cardsStartingHP m:set_hp_max(m.hp) refresh_mob_name(m) end -- restore all mana for i,mp in ipairs({blueManaPos, redManaPos}) do local m=get_monster_ptr_xyz(mp[1],mp[2],npc.map_level) if m==nil then m=spawn_at(0x361,mp[1],mp[2],npc.map_level) end m.code=0x5f1 m:set_align(ALIGN_GOOD) m.hp=1 m:set_hp_max(m.hp) refresh_mob_name(m) end -- save the game info to the db here if p2~=nil then moa_mysql_query("insert into cardgame values (0, now(), '"..server_config:get("server_id").."','"..add_slashes(p1.account_name).."|"..add_slashes(p1.name).."','"..add_slashes(p2.account_name).."|"..add_slashes(p2.name).."','"..add_slashes(redlib).."','"..add_slashes(bluelib).."','' )") judge_vars.match_id=moa_mysql_get_last_insert_id() writelog2("match id="..judge_vars.match_id) end if p1~=nil then for i=1,3 do draw_card(p1.name, "red", npc.map_level) end end if p2~=nil then for i=1,3 do draw_card(p2.name, "blue", npc.map_level) end end map:set_item_code(switchPos[1],switchPos[2],Item(0x51c)) map:set_item_code(redTurnBrazier[1],redTurnBrazier[2],Item(0x10e)) map:set_item_code(blueTurnBrazier[1],blueTurnBrazier[2],Item(0x51e)) judge_vars.active_sorcery=false judge_vars.turn="red" judge_vars.curr_sel_mob_id=-1 judge_vars.game_on=true judge_vars.turn_number=0 judge_vars.auto_flip_from="" judge.ai_misc_str=pickle(judge_vars) update_everyones_fov(judge.map_level) send_npc_reply(-1,"Game reset! Game on!",judge) send_npc_reply(-1,"This is turn 0: if you don't like your hand you can get 1 free mulligan. If you want a mulligan talk to me, otherwise pull the lever.",judge) send_npc_reply(id,"Bye!",judge) writelog2("CARDS RESET") end -- called when player mulls function cards_mulligan(npc, id) local judge, judge_vars=get_judge_and_vars(npc.map_level) if judge_vars.turn_number~=0 then send_npc_reply(id,"You can only mulligan during turn 0!",judge) return end local p=get_player_ptr(id) local colour="" if p.name==judge_vars.redname then colour="red" end if p.name==judge_vars.bluename then colour="blue" end if colour=="" then send_npc_reply(id,"You're not even playing!",judge) return end if colour~=judge_vars.turn then send_npc_reply(id,"It's not your turn!",judge) return end local rc, lib = shuffle_card_inv_into_library(p.id, colour) for i=1,3 do draw_card(p.name, colour, p.map_level) end cards_switch(id,switchPos[1],switchPos[2],p.map_level,false) end -- this func handles all the clicks -- called whenever a player right clicks the screen & the clicked thing is a monster -- id is player id, x,y,z is click co-ords -- guaranteed by right_click (the calling func) that clicked thing is a monster function euo_cards_click(id,x,y,z) local map=get_map_ptr(z) local clicker=get_sent_ptr(id) local clicked_mob=get_monster_ptr_xyz(x,y,z) -- guaranteed to not be nil local clickedteamtile=map:get_tile(x,y) local judge=get_judge_and_vars(z) if not get_judge_var(judge,"game_on") then return 0; end if get_judge_var(judge,"turn")=="red" and clicker.name~=get_judge_var(judge,"redname") or get_judge_var(judge,"turn")=="blue" and clicker.name~=get_judge_var(judge,"bluename") and id~=judge.id then cms=get_side(clicked_mob) if clicked_mob.code==0x25a and (cms=="red" and clicker.name~=get_judge_var(judge,"redname") or cms=="blue" and clicker.name~=get_judge_var(judge,"bluename") ) then send_message(id,"You see a trap (not your turn).") else send_message(id,"You see ["..clicked_mob.ai_misc_str.."] (not your turn).") end return 1 end if clicked_mob.code==0x12d then script_cards_graveyard_talk(clicked_mob,id) return 1 end writelog2("clicked name="..clicked_mob.name.." id="..clicked_mob.id.." card="..clicked_mob.ai_misc_str) local myteamtile=BLUETILE if get_judge_var(judge,"turn")=="red" then myteamtile=REDTILE end local tgt=get_monster_ptr_xyz(x,y,z) if tgt:get_align()~=ALIGN_NEUTRAL then send_message(id,"Select a NEUTRAL ALIGNED target!") return 1 end local tgtcard=wl:get_card_info(tgt.ai_misc_str) -- card most recently clicked local attacker=get_monster_ptr(get_judge_var(judge,"curr_sel_mob_id")) -- prev clicked MOB/stack, not necesarily not nil -- do active spells here if get_judge_var(judge,"active_sorcery") and attacker~=nil then if attacker.id~=tgt.id then call("card_ability_"..prep_name_for_call(attacker.ai_misc_str),attacker,tgt) set_judge_var(judge,"active_sorcery",false) elseif tgtcard~=nil and tgtcard.typ==string.byte("a") then -- artifact clicked itself (cancel) set_judge_var(judge,"active_sorcery",false) send_npc_reply(-1,"Cancelled!", judge) else send_message(id,"I said select a target!") end return 1 end if clickedteamtile==myteamtile and tgt~=nil and tgt:get_health(HN_ASLEEP)~=0 then send_message(id,"["..tgt.ai_misc_str.."] is asleep / disabled / taken its turn, etc.") return 1 end -- clicked one of their guys if clickedteamtile~=myteamtile then if tgt.id>=100 and tgt:get_align()==ALIGN_NEUTRAL and (tgt.code==BCODE_HEARTHSTONE or tgtcard~=nil and tgtcard.typ==string.byte("c")) then if attacker~=nil then local attackercard=wl:get_card_info(attacker.ai_misc_str) if get_judge_var(judge,"auto_flip_from")~="" then send_message(id,"You can't attack during your mid turn response!") elseif attackercard~=nil and attackercard.typ==string.byte("c") and attackercard.subtyp~="wall" then local defenders,flyers,taunters=count_defenders(attacker.map_level,clickedteamtile) if tgt.code~=BCODE_HEARTHSTONE or (attacker:get_health(HN_TRANSPARENT)~=0 or defenders==0 or flyers==0 and (attackercard.flying or attacker:get_health(HN_FLYING)~=0)) then if tgtcard~=nil and (tgtcard.flying or tgt:get_health(HN_FLYING)~=0) and not attackercard.flying and attacker:get_health(HN_FLYING)==0 and defenders-flyers>0 then send_message(id,"Your non flying creature cannot attack a flying defender when there are other non-flying defenders!") elseif (tgt.code==BCODE_HEARTHSTONE or tgtcard~=nil and not tgtcard.taunt) and taunters>0 then send_message(id,"There are defeners with taunt, and they must be eliminated before other creatures can be attacked!") else tgtstr=tgt.ai_misc_str if tgt.code==BCODE_HEARTHSTONE then tgtstr="Red Hearthstone" if tgt.x==blueHeartPos[1] then tgtstr="Blue Hearthstone" end end send_npc_reply(-1,"Combat: ["..attacker.ai_misc_str.."] attacks ("..tgtstr..")", judge) if check_attack_triggers(attacker,attackercard,tgt)==false then local a_dmg=attacker:get_thaco() if attackercard.backstab and tgt:get_health(HN_ASLEEP)~=0 then a_dmg=a_dmg*2 end if tgtcard~=nil and tgtcard.dodge then --send_npc_reply(-1,"["..tgtcard.name.."] will dodge.", judge) a_dmg=0 end local tgtdied=false local first_stike_defense=tgt.ai_misc_str=="Wall of Swords" if first_stike_defense then send_npc_reply(-1,"Defender has first strike!",judge) local attacker_died=damage_card(attacker,tgt:get_thaco(),tgt) if not attacker_died then tgtdied=damage_card(tgt,a_dmg,attacker) end else if attackercard.first_strike then send_npc_reply(-1,"Attacker has first strike!",judge) end tgtdied=damage_card(tgt,a_dmg,attacker) -- args=target ptr, dmg, attacking ptr if tgt.code~=BCODE_HEARTHSTONE and (not attackercard.first_strike or not tgtdied) then damage_card(attacker,tgt:get_thaco(),tgt) end -- retaliate end if (attackercard.trample or attacker:get_health(HN_TRAMPLE)~=0) and tgtdied and tgt.hp<0 then -- get heart local heart=blueHeartPos if get_judge_var(judge,"turn")=="blue" then heart=redHeartPos end -- dmg it with dmg diff heart=get_monster_ptr_xyz(heart[1],heart[2],z) if heart~=nil then send_npc_reply(-1,(0-tgt.hp).." trample damage!",judge) damage_card(heart,0-tgt.hp,attacker) end end if attacker.hp>0 then if attackercard.vigilance then attacker:set_health(HN_ASLEEP,-2) else attacker:set_health(HN_ASLEEP,-1) end end end set_judge_var(judge,"curr_sel_mob_id",0) update_everyones_fov(z) end else send_message(id,"There are available defenders that need to be removed before you can attack the hearthstone!") end else send_message(id,"You can't attack with that non-creature or wall!") end end else send_message(id,"Invalid target!") end else -- clicked one of my guys if tgtcard~=nil and tgtcard.typ~=string.byte("c") and tgtcard.subtyp=="target" and tgt.id==get_judge_var(judge,"curr_sel_mob_id") then writelog2("double clicked my artifact...") send_npc_reply(-1, "["..tgt.ai_misc_str.."] selected ... choosing target ...", judge) set_judge_var(judge,"active_sorcery",true) send_message(id, "NOW SELECT A TARGET (for your artifact ability or spell) or click self to cancel") elseif tgtcard~=nil and tgtcard.typ~=string.byte("c") and tgtcard.subtyp=="self" and tgt.id==get_judge_var(judge,"curr_sel_mob_id") then writelog2("double clicked my single use artifact or spell on stack...") -- figure out best ui to do here send_npc_reply(-1, "["..tgt.ai_misc_str.."] activated.", judge) if tgtcard.typ==string.byte("a") then call("card_ability_self_"..prep_name_for_call(tgt.ai_misc_str), tgt, get_judge_var(judge,"turn"), z) else call("card_ability_"..prep_name_for_call(tgt.ai_misc_str), nil, get_judge_var(judge,"turn"), z) tgt.time_alive=0 end else local fov=false -- delete > from all mob names for _x=1,18 do for _y=3,16 do local m=get_monster_ptr_xyz(_x,_y,z) if is_permanent_or_heart(m) then if string.sub(m.name,1,1)=='>' then refresh_mob_name(m) fov=true end end end end -- highlight selected mob (ie add >) for _x=1,18 do for _y=3,16 do local m=get_monster_ptr_xyz(_x,_y,z) if is_permanent_or_heart(m) then if _x==x and _y==y and map:get_tile(_x,_y)==myteamtile then m:set_name(">"..get_cardmob_name(m)) make_players_forget_mob_name(m.id) fov=true set_judge_var(judge,"curr_sel_mob_id",m.id) writelog2("selected id="..m.id) send_message(id,"Selected ["..m.ai_misc_str.."]") if tgtcard~=nil and tgtcard.typ~=string.byte("c") and tgtcard.subtyp=="self" then send_message(id,"Now click again to use ability, or click something else to cancel.") end end end end end if fov then update_everyones_fov(z) end end end return 1 end -- called when the switch is pulled (or torch lit) which signifies end of turn function cards_switch(id,x,y,z,no_reset) if no_reset==nil then no_reset=false; end -- also if something on my stack when switch points my way, no-reset=true local map=get_map_ptr(z) local judge, judge_vars=get_judge_and_vars(z) if not judge_vars.game_on then send_message(id, "No active game under way! Pulling the switch does nothing.") return end local p=get_player_ptr(id) if p~=nil and not no_reset and not p:is_dm() and (judge_vars.turn=="red" and judge_vars.redname~=p.name or judge_vars.turn=="blue" and judge_vars.bluename~=p.name) then send_message(id,"Not your turn!") return end -- clear the stack -- chg this to: if this is new activ players stack, resovlve it, or force them to sel tgts, etc -- fix me --if judge_vars.active_sorcery then -- local m=get_monster_ptr(judge_vars.curr_sel_mob_id) -- if m~=nil then m.time_alive=0 end -- set_judge_var(judge,"active_sorcery",false) --end -- see if something on my stack -- note that because judge vars not updated yet we are checking the opposite stack local must_resolve=nil if p~=nil then if judge_vars.turn=="red" and judge_vars.redname==p.name then must_resolve=get_sent_ptr_xyz(blueStack[1],blueStack[2],z) end if judge_vars.turn=="blue" and judge_vars.bluename==p.name then must_resolve=get_sent_ptr_xyz(redStack[1],redStack[2],z) end if must_resolve~=nil then no_reset=true end end -- ths will force a no rest when flipping back to the primary turn holder if judge_vars.auto_flip_from~="" and judge_vars.auto_flip_from~=judge_vars.turn then no_reset=true set_judge_var(judge,"auto_flip_from","") end local sx,ex if judge_vars.turn=="red" then set_judge_var(judge,"turn","blue") map:set_item_code(redTurnBrazier[1],redTurnBrazier[2],Item(0x51e)) map:set_item_code(blueTurnBrazier[1],blueTurnBrazier[2],Item(0x10e)) map:set_item_code(switchPos[1],switchPos[2],Item(0x51b)) if no_reset and get_judge_var(judge,"auto_flip_from")=="" then send_npc_reply(-1,"Back to Blue ...", judge) elseif no_reset then send_npc_reply(-1,"Blue's opportunity to respond ...", judge) else send_npc_reply(-1,"Blue's turn! (turn "..judge_vars.turn_number..")", judge) end if not no_reset and judge_vars.turn_number>0 then draw_card(judge_vars.bluename, "blue", z) reset_and_bump_mana(judge_vars.turn_number,blueManaPos,z) end sx=1 ex=9 -- fix me when add more than 2 players! else set_judge_var(judge,"turn","red") if not no_reset then set_judge_var(judge,"turn_number",judge_vars.turn_number+1) end map:set_item_code(blueTurnBrazier[1],blueTurnBrazier[2],Item(0x51e)) map:set_item_code(redTurnBrazier[1],redTurnBrazier[2],Item(0x10e)) map:set_item_code(switchPos[1],switchPos[2],Item(0x51c)) if no_reset and get_judge_var(judge,"auto_flip_from")=="" then send_npc_reply(-1,"Back to Red ...", judge) elseif no_reset then send_npc_reply(-1,"Red's opportunity to respond ...", judge) else send_npc_reply(-1,"Red's turn! (turn "..get_judge_var(judge,"turn_number")..")", judge) end if not no_reset and judge_vars.turn_number>0 then draw_card(judge_vars.redname, "red", z) reset_and_bump_mana(get_judge_var(judge,"turn_number"),redManaPos,z) end sx=10 ex=18 end --update_everyones_fov(judge) set_judge_var(judge,"curr_sel_mob_id",-1) if not no_reset then -- reset the field for _x=1,18 do for _y=3,16 do local m=get_monster_ptr_xyz(_x,_y,z) if is_permanent_or_heart(m) then local sleep=m:get_health(HN_ASLEEP) if _x>=sx and _x<=ex then if sleep==1 then -- forced sleep thru turn m:set_health(HN_ASLEEP,-1) elseif sleep==-1 then m:set_health(HN_ASLEEP,0) end if m:get_health(HN_REVERSE_DAMAGE)~=0 then m:set_health(HN_REVERSE_DAMAGE,0) end end if sleep==-2 then m:set_health(HN_ASLEEP,0) end -- summoning sick reset if m:get_health(HN_DIES_EOT)~=0 then card_death_generic(m.x,m.y,m.map_level,m) m.time_alive=0 end -- killed at end of turn m:decrement_buffs() -- automate this!! m:dec_health(HN_FLYING) m:dec_health(HN_TRANSPARENT) m:dec_health(HN_TRAMPLE) m.thaco_bonus=0 if m:get_health(HN_REGENERATION)~=0 then m.hp=m.hp+1 end if m.hp>m:get_hp_max() then m.hp=m:get_hp_max() end if m:get_health(HN_POISONED)~=0 and (judge_vars.turn=="red" and _x<=9 or judge_vars.turn=="blue" and _x>=10) then m.hp=m.hp-1 if m.hp<1 then send_npc_reply(-1,m.ai_misc_str.." dies from poison damage!", judge) card_death_generic(m.x,m.y,m.map_level,m) m.time_alive=0 else send_npc_reply(-1,m.ai_misc_str.." takes 1 poison damage.", judge) end end m:dec_health(HN_POISONED) refresh_mob_name(m) end end end -- run _bot_ trigs -- bot0 runs first. put the newbie dungeon etc here. this is like upkeep for _x=1,18 do for _y=3,16 do local m=get_monster_ptr_xyz(_x,_y,z) if is_permanent(m) then call("card_BOT0_"..prep_name_for_call(m.ai_misc_str), m, get_judge_var(judge,"turn")) end end end -- put xenktar etc here - so bot summoned rats don't get pumped twice for _x=1,18 do for _y=3,16 do local m=get_monster_ptr_xyz(_x,_y,z) if is_permanent(m) then call("card_BOT1_"..prep_name_for_call(m.ai_misc_str), m, get_judge_var(judge,"turn")) end end end end if must_resolve~=nil then local card=wl:get_card_info(must_resolve.ai_misc_str) if card~=nil then if card.subtyp=="self" then call("card_ability_"..prep_name_for_call(must_resolve.ai_misc_str), nil, get_judge_var(judge,"turn"), z) must_resolve.time_alive=0 else must_resolve:set_name(">"..get_cardmob_name(must_resolve)) set_judge_var(judge,"curr_sel_mob_id",must_resolve.id) set_judge_var(judge,"active_sorcery",true) send_npc_reply(-1,"NOW SELECT A TARGET", judge) make_players_forget_mob_name(must_resolve.id) end end end simple_send_event(judge.id, EVENT_PARRIED) update_everyones_fov(z) -- this is the beginning of the AI that plays for blue -- it basically just calls bluebot_attacks_with_all_creatures() -- is there too much data being sent over network here? -- am getting SOCKET error 2 sending messages some times and fov is screwing up - -- at this point, if was regular turn, and no human opponent, and turn is blue, summon a random card/creature for all the mana i have if get_judge_var(judge,"turn")=="blue" and get_judge_var(judge,"bluename")=="" and not no_reset and must_resolve==nil then send_npc_reply(-1,"Playing for blue ...", judge) if judge_vars.turn_number>0 then local mana=get_mana(blueManaPos,z) local carditm=get_random_carditm_for_mana(mana,false) if carditm~=false then bless_item(carditm) use_811(-1,-1,false,carditm,0x811,0,0,z) end bluebot_attacks_with_all_creatures(z) end cards_switch(-1,x,y,z,false) end end -- use card -- called when player plays a card (which is item 0x811) -- name of item is the balrog card name -- most of the card logic is in cards_abilities.lua, with the relevant func determined by the card name function use_811 (id,tgt_id,alt,itm,bcode,x,y,z) local map=get_map_ptr(z) if not map:is_betting_ring() then send_message(id,"Usable only in the betting ring!") return end if not is_blessed(itm) then send_message(id,"Card must be in hand (ie blessed!)") return end local card=wl:get_card_info(wl:get_name(itm)) if card==nil then send_message(id,"Unknown card!") return end local judge, judge_vars=get_judge_and_vars(z) if judge_vars.turn_number<1 then send_message(id,"You can't play cards during turn 0 but you can ask the umpire for a mulligan!") return end -- is there a game running? if not judge_vars.game_on then send_message(id,"No active game under way!") return end -- check turn local p=get_player_ptr(id) if p~=nil and not p:is_dm() and (judge_vars.turn=="red" and judge_vars.redname~=p.name or judge_vars.turn=="blue" and judge_vars.bluename~=p.name) then send_message(id,"Not your turn!") return end -- active spell if judge_vars.active_sorcery then send_message(id,"Not now ... there is an active spell that needs resolving (look for the card icon!)") return end -- switch card type writelog2(card.name) if card==nil then writelog2("invalid card!") return end local mymana, spawnx, spawny spawnx,spawny=get_summon_location(card, judge_vars.turn, z) if judge_vars.turn=="red" then mymana=get_mana(redManaPos,z) end if judge_vars.turn=="blue" then mymana=get_mana(blueManaPos,z) end local cost=get_cost(card,judge_vars.turn,z) if mymana-cost<0 then send_message(id,"Not enough mana!") return end writelog2(string.format("card type = %d %c", card.typ, card.typ)) local n="NO OPPONENT" if p~=nil then n=p.name end if card.typ==string.byte("s") and card.subtyp=="trap" then send_npc_reply(-1,n.." plays a TRAP!", judge) else send_npc_reply(-1,n.." plays ["..card.name.."]", judge) end -- spell triggers if card.typ==string.byte("s") and check_played_sorcery_triggers(card.name,judge_vars.turn,z) then end -- look for counterspell trap if check_for_counterspell(card, z) then -- countered! else local counter_switch=false local spell_on_opponents_stack = (judge_vars.turn=="red" and get_sent_ptr_xyz(blueStack[1],blueStack[2],z)~=nil or judge_vars.turn=="blue" and get_sent_ptr_xyz(redStack[1],redStack[2],z)~=nil) if (not COUNTERSPELLS or spell_on_opponents_stack) and card.typ==string.byte("s") and card.subtyp=="self" then -- just execute ability no but otherwise it goes on stack call("card_ability_"..prep_name_for_call(card.name), nil, judge_vars.turn, z) local graveyard=get_graveyard_by_colour(judge_vars.turn, z) local bitm=Item(itm) remove_blessing(bitm) put_card_in_graveyard(graveyard, bitm) else -- summon a mob or arty -- also sorcs with targets go here local m local sp=get_sent_ptr_xyz(spawnx,spawny,z) if card.typ==string.byte("s") or sp==nil then -- this square needs to be clear for spells! -- the map now has barrier feat on it to keep it clear m=spawn_at(0x34b,spawnx,spawny,z,true) else m=spawn_near(0x361,spawnx,spawny,z,true) writelog2("had to use spawn near for "..spawnx..","..spawny) end if card.typ==string.byte("s") then if card.subtyp=="trap" then m.code=0x25a else m.code=0x811 end else m.code=card.code end set_monster_card_vars_and_do_trigs_and_fx(m, card.name, card.toughness, card.power, judge_vars.turn) if card.typ==string.byte("s") then -- if something on oppoenents stack then if COUNTERSPELLS and not spell_on_opponents_stack then counter_switch=true elseif card.subtyp=="target" then m:set_name(">"..get_cardmob_name(m)) set_judge_var(judge,"curr_sel_mob_id",m.id) set_judge_var(judge,"active_sorcery",true) send_npc_reply(-1,"NOW SELECT A TARGET", judge) make_players_forget_mob_name(m.id) end end end -- summon card end -- deduct mana decrease_mana_turn(cost,z,judge_vars.turn) remove_item(id,itm,1,true) remove_blessing(itm) give_item(id,itm,1,true) refresh_lib_name(judge_vars.turn,z) update_everyones_fov(z) if counter_switch then set_judge_var(judge,"auto_flip_from",judge_vars.turn) cards_switch(-1,switchPos[1],switchPos[2],z,true) -- auto flip, allow for counter end end -- AI mindlessly attacks with everything function bluebot_attacks_with_all_creatures(z) local judge=get_judge_and_vars(z) local sx,ex=get_sx_ex("blue") for _x=sx,ex do for _y=3,16 do local m=get_monster_ptr_xyz(_x,_y,z) if is_permanent(m) then local card=wl:get_card_info(m.ai_misc_str) if card~=nil and card.typ==string.byte("c") then local tx,ty=bluebot_find_target(z) euo_cards_click(judge.id,_x,_y,z) euo_cards_click(judge.id,tx,ty,z) for i=1,100000 do end end end end end end -- used by AI to select a target function bluebot_find_target(z) -- best targs in order (all unsleeping) -- taunt, non flyer, flyer, heart local taunter,nonflyer,flyer=nil,nil,nil local sx,ex=get_sx_ex("red") for _x=sx,ex do for _y=3,16 do local m=get_monster_ptr_xyz(_x,_y,z) if is_permanent(m) and m:get_health(HN_ASLEEP)==0 then local card=wl:get_card_info(m.ai_misc_str) if card~=nil and card.typ==string.byte("c") and not card.dodge then if card.taunt then taunter=m elseif card.flying or m:get_health(HN_FLYING)~=0 then flyer=m else nonflyer=m end end end end end if taunter~=nil then return taunter.x,taunter.y end if nonflyer~=nil then return nonflyer.x,nonflyer.y end if flyer then return flyer.x,flyer.y end return redHeartPos[1],redHeartPos[2] end