-- starter deck of cards npc reply func function cards_give(npc, id) --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 local cards={ "Fast Rat:3", "Lightning Strike:3", "Vector Bat:3", "Mongo the Mongbat:1", "Crimson Devil:1", "Green Dragon:1", "Diseased Zombie:2", "Deleted Hydra:2", "Baby Beholder:2", "Blueish Potion:2", "Purple Potion:2", "Half Orc Warrior:2", "Stone Golem:1", "Orange Potion:1", "Crouching Tiger:2", "Blood Spider:2", } local p=get_player_ptr(id) local judge, judge_vars = get_judge_and_vars(npc.map_level) if judge_vars.game_on and (judge_vars.bluename==p.name or judge_vars.redname==p.name) then send_npc_reply(id, "Not while you are playing a game!", npc) return end if get_player_item_qty(id, token_starter_cards)~=0 then send_npc_reply(id, "You can only get the starter set of cards once!", npc) return end for i,v in ipairs(cards) do local x=explode(':',v) local card=Item() card:setFromStr("811.."..add_us2(x[1])) give_item(id,card,x[2]) end send_npc_reply(id, "There you go!", npc) give_item(id,token_starter_cards,1,true) end function get_cardmob_name(m) if m.code==0xb44e then return "hp "..m.hp; end -- heart if m.code==0x5f1 then return "mana "..m.hp.."/"..m:get_hp_max(); end -- mana if m.code==0x811 then return m.ai_misc_str end if m.code==0x129 then local map=get_map_ptr(m.map_level) local t=map:get_tile(m.x, m.y) return cards_in_hand(t,m.map_level).."/"..cards_in_library(t,m.map_level) end if m.code==0x12d then -- graveyard return ""..get_item_basecode_qty(m.id,0x811,false) end local card=wl:get_card_info(m.ai_misc_str) if card~=nil then if card.typ==string.byte("a") then return m.ai_misc_str elseif card.typ==string.byte("s") and card.subtyp=="trap" then return "TRAP" end end local n=m:get_thaco().."/"..m.hp if m:get_health(HN_FLYING)~=0 then n=n.."^" end -- fix me automate this properly return n end function cards_in_hand(t,z) local judge=get_judge_and_vars(z) local pid if t==REDTILE then pid=find_player( get_judge_var(judge,"redname")) end if t==BLUETILE then pid=find_player( get_judge_var(judge,"bluename")) end if pid==-1 then return 0 end return get_item_basecode_qty(pid,0x811,true) end function cards_in_library(t,z) local judge=get_judge_and_vars(z) local lib if t==REDTILE then lib=get_monster_ptr_xyz(redLibraryPos[1],redLibraryPos[2],z) end if t==BLUETILE then lib=get_monster_ptr_xyz(blueLibraryPos[1],blueLibraryPos[2],z) end return get_item_basecode_qty(lib.id,0x811,false) end function refresh_mob_name(m) m=get_monster_ptr(m.id) local oldn=m.name m:set_name(get_cardmob_name(m)) if oldn~=m.name then make_players_forget_mob_name(m.id) end end function refresh_lib_name(side,z) local lib if side=="red" then lib=get_monster_ptr_xyz(redLibraryPos[1],redLibraryPos[2],z) end if side=="blue" then lib=get_monster_ptr_xyz(blueLibraryPos[1],blueLibraryPos[2],z) end if lib==nil then return end refresh_mob_name(lib) end function get_judge_and_vars(z) local judge = get_monster_ptr_xyz(9,13,z) if judge==nil then return nil,nil end local judge_vars=unpickle(judge.ai_misc_str) return judge, judge_vars end function set_judge_var(judge, k, v) local judge_vars=unpickle(judge.ai_misc_str) judge_vars[k]=v judge.ai_misc_str=pickle(judge_vars) end function get_judge_var(judge, k) local judge_vars=unpickle(judge.ai_misc_str) return judge_vars[k] end function shuffle(a) local rnd,trem,getn,ins = math.random,table.remove,table.getn,table.insert local r = {} while getn(a) > 0 do ins(r, trem(a, rnd(getn(a)))) end return r end function get_library_by_colour(colour,z) local lib if colour=="red" then lib=get_monster_ptr_xyz(redLibraryPos[1],redLibraryPos[2],z) else lib=get_monster_ptr_xyz(blueLibraryPos[1],blueLibraryPos[2],z) end if lib==nil then writelog2("DECK PTR FAIL!") end return lib end function get_graveyard_by_colour(colour,z) local gy if colour=="red" then gy=get_monster_ptr_xyz(redGraveyardPos[1],redGraveyardPos[2],z) else gy=get_monster_ptr_xyz(blueGraveyardPos[1],blueGraveyardPos[2],z) end if gy==nil then writelog2("GY PTR FAIL!") end return gy end -- return true if fail function shuffle_card_inv_into_library(id, colour) writelog2("shuffle id="..id.." colour="..colour) local p=get_player_ptr(id) local lib=get_library_by_colour(colour,p.map_level) -- deck mob if lib==nil or lib.id<100 then writelog2("DECK PTR FAIL") return true end delete_inventory(lib.id) local d={} while true do card=get_item_basecode(id, 0x811) if card==Item(0) then break; end q=remove_item(id,card,-1,true) -- you have to delete it or this loops forever remove_blessing(card) remove_curse(card) for i=1,q do table.insert(d,card) end end d=shuffle(d) local cards={} local cnt=0 local maxcopyfail=false for i,v in ipairs(d) do local n=wl:get_name(v) if wl:get_card_info(n)~=nil then lib:give_item(v,1) give_item(id,v,1,true) -- give card back cnt=cnt+1 if array_key_exists(n,cards) and cards[n]>=maxCopiesOfEachCard then maxcopyfail=true end if not array_key_exists(n,cards) then cards[n]=1 else cards[n]=cards[n]+1 end else send_message(id,"Deleted invalid card with name /"..n.."/ !") end end local deckstr="" for name,cnt in pairs(cards) do if deckstr~="" then deckstr=deckstr.."|" end deckstr=deckstr..cnt.."x "..name end send_message(id,"You have "..cnt.." cards.") if maxcopyfail then send_message(id,"You have more than "..maxCopiesOfEachCard.." copies of some cards!"); end if not p:is_dm() and (cnt~=30 or maxcopyfail) then return true end return false, deckstr end function draw_card(name, colour, z) local p=get_player_ptr(find_player(name)) local judge=get_judge_and_vars(z) if p==nil or p.map_level~=z then send_npc_reply(-1, colour.." player not found, or disqualified!", judge) return end local lib=get_library_by_colour(colour,p.map_level) if lib==nil then writelog2("DECK not found in draw card!"); return; end local c=lib:delete_first_item() if c~=Item(0) then send_npc_reply(-1, p.name.." draws a card.", judge) remove_item(p.id,c,1,true) bless_item(c) give_item(p.id, c) refresh_mob_name(lib) else send_npc_reply(-1, p.name.."'s library is empty!", judge) send_message(p.id,"Your library is empty!") end end function reset_and_bump_mana(turn_num,mp,z) local m=get_monster_ptr_xyz(mp[1],mp[2],z) if turn_num%2==0 then m:set_hp_max(m:get_hp_max()+1) end m.hp=m:get_hp_max() refresh_mob_name(m) end function get_mana(mp,z) local m=get_monster_ptr_xyz(mp[1],mp[2],z) if m==nil then return 0 end return m.hp end function decrease_mana(cost,mp,z) local m=get_monster_ptr_xyz(mp[1],mp[2],z) m.hp=m.hp-cost -- just make sure it doesn't go below 0 HP! if m.hp<0 then writelog2("warning! mana xtal went below 1 hp! (setting to 0, was mp="..m.hp) m.hp=0 end refresh_mob_name(m) update_everyones_fov(m) end function decrease_mana_turn(cost,z,turn) if turn=="red" then decrease_mana(cost,redManaPos,z) end if turn=="blue" then decrease_mana(cost,blueManaPos,z) end end function damage_card(tgt,dmg,attacker) -- return true if tgt died local judge=get_judge_and_vars(tgt.map_level) tgt=get_monster_ptr(tgt.id) if tgt==nil then writelog2("invalid target damage card") return false end if dmg>0 then if attacker~=nil then local _dmg=call("card_hit_"..prep_name_for_call(attacker.ai_misc_str),attacker,tgt,dmg) if _dmg ~=nil then dmg=_dmg; end end -- look for heart taking dmg if dmg>0 and tgt.code==0xb44e then dmg=check_for_heart_damage_trigger(tgt,dmg,attacker) end if dmg>0 then local oldhp=tgt.hp hurt(tgt.id,dmg,"x") local dmg_dealt=oldhp-tgt.hp if tgt.hp<0 then dmg_dealt=oldhp end simple_send_event(tgt.id,EVENT_HIT) simple_send_event(tgt.id,EVENT_DAMAGE_NUMBER,dmg) if attacker~=nil then local c=wl:get_card_info(attacker.ai_misc_str) if c~=nil and c.vampyric and dmg_dealt>0 then local map=get_map_ptr(attacker.map_level) local tile=map:get_tile(attacker.x, attacker.y) if tile==REDTILE then heal_heart(redHeartPos, tgt.map_level, dmg_dealt) elseif tile==BLUETILE then heal_heart(blueHeartPos, tgt.map_level, dmg_dealt) end end end end end local tgtcardname=tgt.ai_misc_str local rc=false if tgtcardname=="" then tgtcardname=monsters:get_name(tgt, false) end -- at this point if hearthstone tgtcardname is just hearthstone if tgt.hp<1 then send_npc_reply(-1,tgtcardname.." died!", judge) -- look for death trig if tgtcardname~="" then call("card_death_"..prep_name_for_call(tgtcardname),tgt.x,tgt.y,tgt.map_level,tgt) -- call the generic card death func card_death_generic(tgt.x,tgt.y,tgt.map_level,tgt) end rc=true -- look for heart death if tgt.code==0xb44e then local p if tgt.x==redHeartPos[1] then send_npc_reply(-1,"BLUE WINS!", judge) p=get_player_ptr(find_player(get_judge_var(judge,"bluename"))) elseif tgt.x==blueHeartPos[1] then send_npc_reply(-1,"RED WINS!", judge) p=get_player_ptr(find_player(get_judge_var(judge,"redname"))) end if p~=nil and get_judge_var(judge,"bluename")~="" then moa_mysql_query("update cardgame set winner='"..add_slashes(p.account_name.."|"..p.name).."' where nr="..get_judge_var(judge,"match_id")) end set_judge_var(judge,"game_on",false) end else if tgtcardname=="hearthstone" then tgtcardname=ucwords(get_side(tgt)).."'s Hearthstone" end send_npc_reply(-1,tgtcardname.." takes "..dmg.." damage.", judge) refresh_mob_name(tgt) end return rc end function prep_name_for_call(n) n=add_us2(n) n=string.gsub(n,",","") n=string.gsub(n,"'","") n=string.gsub(n,"-","_") return n end function count_defenders(z,tile) local defs,flyers,taunters=0,0,0 local map=get_map_ptr(z) for _x=1,18 do for _y=3,16 do local m=get_monster_ptr_xyz(_x,_y,z) if is_permanent(m) and tile==map:get_tile(_x,_y) 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") then if not card.dodge then defs=defs+1 end if card.flying or m:get_health(HN_FLYING)~=0 then flyers=flyers+1 end if card.taunt then taunters=taunters+1 end end end end end return defs,flyers,taunters end function heal_heart(h, z, amt) local m=get_monster_ptr_xyz(h[1],h[2],z) local colour="Red" if h[1]<10 then colour="Blue" end if m~=nil then m.hp=m.hp+amt if m.hp>m:get_hp_max() then m:set_hp_max(m.hp) end refresh_mob_name(m) local judge=get_judge_and_vars(z) send_npc_reply(-1, colour.."'s heart is gains "..amt.." HP.", judge) end end -- sees if mob is not null and is a card but not heart function is_permanent(m) return m~=nil and m:get_align()==ALIGN_NEUTRAL and m.ai_misc_str~="" end function is_heart(m) return m~=nil and m:get_align()==ALIGN_NEUTRAL and m.code==0xb44e end function is_permanent_or_heart(m) return m~=nil and m:get_align()==ALIGN_NEUTRAL end function otherside(side) if side=="red" then return "blue" end if side=="blue" then return "red" end return "" end function get_sx_ex(side) local sx,ex=1,9 if side=="red" then sx,ex=10,18 end return sx,ex end function get_side(m) local map=get_map_ptr(m.map_level) local t=map:get_tile(m.x, m.y) if t==BLUETILE then return "blue" end if t==REDTILE then return "red" end return "" end function have_card_on_battlefield(name,side,z) local sx,ex=get_sx_ex(side) 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.name==name then return m end end end end return nil end -- same as above but returns an array function get_cards_on_battlefield(name,side,z) local sx,ex=get_sx_ex(side) local rc={} 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.name==name then table.insert(rc,m) end end end end return rc end -- move this into abilities function get_cost(card,turn,z) -- this just applies discount to potions if have alchemy bench local cost=card.cost if string.find(card.name , "Potion")~=nil and have_card_on_battlefield("Alchemy Bench",turn,z)~=nil then cost=cost-1 if cost<0 then cost=0 end end if card.typ==string.byte("c") and string.find(card.subtyp , "demon")~=nil and have_card_on_battlefield("Demonic Altar",turn,z)~=nil then cost=cost-1 if cost<0 then cost=0 end end if card.typ==string.byte("s") and have_card_on_battlefield("Neophyte Wizard",turn,z)~=nil then cost=cost-1 if cost<0 then cost=0 end end return cost end function set_monster_card_vars_and_do_trigs_and_fx(m, cardname, hp, as, owner_colour) local card=wl:get_card_info(cardname) local judge, judge_vars=get_judge_and_vars(m.map_level) if hp<1 then hp=1 end m.ai_misc_str=cardname m:set_species_name(cardname) m:set_align(ALIGN_NEUTRAL) m:set_hp_max(hp) m.hp=hp m:set_thaco(as) if card~=nil and card.typ~=string.byte("c") then m.quest_target=true --artifact/spell, so vog and find_npc doesn't hit it elseif card~=nil and card.typ==string.byte("c") then m:set_health(HN_ASLEEP,-1) end if card~=nil and card.stealth then m:set_health(HN_TRANSPARENT,-1) end if card~=nil and card.regeneration then m:set_health(HN_REGENERATION ,-1) end m:set_name(get_cardmob_name(m)) if owner_colour~=nil then writelog2("set_monster_card_vars_and_do_trigs_and_fx"..">"..owner_colour) m.death_func="cards_death_func_"..owner_colour end if card~=nil and card.typ==string.byte("c") then if card.haste then m:set_health(HN_ASLEEP,0) else m:set_health(HN_ASLEEP,-2) -- summoning sick, -2 means just my turn end end if card~=nil and card.typ~=string.byte("s") then simple_send_event(m.id,EVENT_MAGIC,0x17,m.x,m.y) -- set_judge_var(judge,"active_sorcery",false) call("card_ETB_"..prep_name_for_call(m.ai_misc_str), m, judge_vars.turn) card_etb_generic(m, judge_vars.turn) -- now, go and trigger every other card with a 'when something else etb' for _x=1,18 do for _y=3,16 do local _m=get_monster_ptr_xyz(_x,_y,m.map_level) if is_permanent(_m) then call("card_ETB_other_"..prep_name_for_call(_m.ai_misc_str), _m, m, judge_vars.turn) end end end else simple_send_event(m.id,EVENT_MAGIC,0x6,m.x,m.y) end end function get_random_carditm_for_mana(mana,exactmana) if mana>7 then mana=7 end local candidates={} for line in io.lines("dat/cards.txt") do line=trim2(line) if string.sub(line,1,1)=='"' then line=string.sub(line,2,-1) end if string.sub(line,1,1)~="#" then local x=explode("\t",line) if string.sub(x[1],-1)=='"' then x[1]=string.sub(x[1],1,-2) end local cardmana=tonumber(x[3]) if (exactmana and cardmana==mana or not exactmana and cardmana<=mana) and x[2]=="c" and x[7]~="t" then local c=Item(0) c:setFromStr("811.."..add_us2(x[1])) table.insert(candidates,c) end end end return get_random_element(candidates) end function trap_sound(m) simple_send_event(m.id,EVENT_MAGIC,0xa0,m.x,m.y) end function script_cards_graveyard_talk(gy, id) local str=get_mob_inv_string(gy) gy:set_name("Graveyard") send_npc_reply(id,"-------------------", gy) if str=="" then send_npc_reply(id,"Empty!", gy) else local inv=explode("|",str) local n=gy.name for k,v in pairs(inv) do local x=explode(" ", v) itm=Item() itm:setFromStr(x[1]) if get_base_code(itm)==0x811 then send_npc_reply(id,"["..string.sub(wl:get_full_name(itm),0,-8).."] "..x[2], gy) end end end gy:set_name(n) end function get_summon_location(card, turn, z) local spawny=math.random(7,11) local spawnx if turn=="red" then spawnx=11 if card.typ==string.byte("s") and card.subtyp=="target" then spawnx=redStack[1] spawny=redStack[2] elseif card.typ==string.byte("a") then spawnx=13 spawny=redHeartPos[2] -- this will get adjusted end end if turn=="blue" then spawnx=8 if card.typ==string.byte("s") and card.subtyp=="target" then spawnx=blueStack[1] spawny=blueStack[2] elseif card.typ==string.byte("a") then spawnx=6 spawny=blueHeartPos[2] end end -- adjust spawn y until get free square if not spell on stack if card.typ~=string.byte("s") then local cnt=0 while cnt<99 do local m=get_sent_ptr_xyz(spawnx,spawny,z) if m==nil then break end cnt=cnt+1 spawny=math.random(spawny-1,spawny+1) if spawny>=11 or spawny<=2 then spawny=6 end end -- there is still a spawn near down below end return spawnx, spawny end function num_creatures_left(z) local defs=0 local map=get_map_ptr(z) for _x=1,18 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") and m.hp>0 then defs=defs+1 end end end end return defs end function get_random_creature(z,ignore_creature) local map=get_map_ptr(z) local _x,_y while true do _x=math.random(1,18) _y=math.random(3,16) local m=get_monster_ptr_xyz(_x,_y,z) if m~=nil and is_permanent(m) then local card=wl:get_card_info(m.ai_misc_str) if card~=nil and card.typ==string.byte("c") and m.hp>0 and (ignore_creature==nil or m.id~=ignore_creature.id) then return m end end end return nil end function spawn_token_helper(code,x,y,z,as,hp,cardname) -- this shouldn't req the mob code and doesnt work with spawning item coded mobs anyway if NO_SPAWNING then return end local m=spawn_near(code,x,y,z,true) if m==nil then writelog2("spawn token failed") return nil else m:set_health(HN_TOKEN,1) -- token set_monster_card_vars_and_do_trigs_and_fx(m, cardname, hp, as) return m end end function is_my_turn(tgt, turn) local map=get_map_ptr(tgt.map_level) local t=map:get_tile(tgt.x, tgt.y) return t==REDTILE and turn=="red" or t==BLUETILE and turn=="blue" end function heal_helper(healval,tgt) tgt.hp=tgt.hp+healval if tgt.hp>tgt:get_hp_max() then tgt.hp=tgt:get_hp_max() end local judge=get_judge_and_vars(tgt.map_level) send_npc_reply(-1, monsters:get_name(tgt, false).." healed!", judge) refresh_mob_name(tgt) simple_send_event(tgt.id,EVENT_MAGIC,0x2,tgt.x,tgt.y) update_everyones_fov(tgt) end function burn_helper(reqdmg, cardmob, tgt) local tgtcard=wl:get_card_info(tgt.ai_misc_str) local dmg=0 if tgt.code==0xb44e or tgtcard~=nil and tgtcard.typ==string.byte("c") then dmg=reqdmg end damage_card(tgt,dmg,cardmob) cardmob.time_alive=1 end function discard_card(side, z) local judge, judge_vars=get_judge_and_vars(z) local p if side=="red" then p=get_player_ptr(find_player(judge_vars.redname)) end if side=="blue" then p=get_player_ptr(find_player(judge_vars.bluename)) end if p~=nil then -- get random blessed card in hand local itm=get_random_blessed_card(p.id) if itm~=Item(0) then send_npc_reply(-1, p.name.." ("..side..") discards ["..wl:get_name(itm).."] at random!", judge) remove_item(p.id,itm,1,true) remove_blessing(itm) give_item(p.id,itm,1,true) refresh_lib_name(side,z) local graveyard=get_graveyard_by_colour(side, z) graveyard:give_item(itm,1) refresh_mob_name(graveyard) end end end function pump_subtype(tgt,subtype,as,hp) -- writelog2(debug.traceback()) local card=wl:get_card_info(tgt.ai_misc_str) if card~=nil and card.typ==string.byte("c") and string.find(to_lower(card.subtyp), subtype)~=nil then tgt.thaco_bonus=tgt.thaco_bonus+as tgt.hp=tgt.hp+hp refresh_mob_name(tgt) end end function lord_effect_pump_subtype(args, subtype, as, hp, hn) local cardmob,turn=unpack(args) local map=get_map_ptr(cardmob.map_level) local t=map:get_tile(cardmob.x, cardmob.y) for _x=1,18 do for _y=3,16 do local m=get_monster_ptr_xyz(_x,_y,cardmob.map_level) if is_permanent(m) and map:get_tile(_x, _y)==t then pump_subtype(m,subtype,as,hp) if hn~=nil then m:set_health(hn,1) end end end end end function spawn_sorcery(cardmob, card_to_cast) local judge,judge_vars=get_judge_and_vars(cardmob.map_level) local map=get_map_ptr(cardmob.map_level) local t=map:get_tile(cardmob.x, cardmob.y) local myturn=judge_vars.turn=="red" and t==REDTILE or judge_vars.turn=="blue" and t==BLUETILE local x=redStack[1] if t==BLUETILE then x=blueStack[1] end local m if myturn then m=spawn_at(0x361,x,redStack[2],cardmob.map_level,true) -- put on my stack else m=spawn_near(0x361,x,redHeartPos[2],cardmob.map_level,true) -- put in my field because not my turn end m.code=0x811 m.ai_misc_str=card_to_cast m:set_species_name(m.ai_misc_str) m:set_align(ALIGN_NEUTRAL) m.hp=1 m:set_hp_max(m.hp) simple_send_event(m.id,EVENT_MAGIC,0x17,m.x,m.y) if myturn 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) else m:set_name(get_cardmob_name(m)) end end -- refactor this to work with proper separate args + diff mana levels function mana_rock(args, mana) -- give 1 mana if mana==nil then mana=1 end local cardmob,turn,z=unpack(args) local mp=blueManaPos if turn=="red" then mp=redManaPos end local m=get_monster_ptr_xyz(mp[1],mp[2],z) m.hp=m.hp+mana refresh_mob_name(m) cardmob:set_health(HN_ASLEEP,-1) refresh_mob_name(cardmob) update_everyones_fov(m) end function get_ownerid_and_mana(cardmob) local judge, judge_vars=get_judge_and_vars(cardmob.map_level) local mymana,pid if judge_vars.turn=="red" then mymana=get_mana(redManaPos,cardmob.map_level) pid=find_player(judge_vars.redname) else mymana=get_mana(blueManaPos,cardmob.map_level) pid=find_player(judge_vars.bluename) end return pid,mymana end -- TRAP TRIGGERS function check_attack_triggers(attacker,attackercard,tgt) -- return true of attacker was removed -- weird how the order of these is checked: what if have both? only one will trigger -- they should probably trigger in order of physically closest to the attacker local judge=get_judge_and_vars(attacker.map_level) local bouncer=have_card_on_battlefield("Bouncer",get_side(tgt),attacker.map_level) if bouncer~=nil and bouncer.time_alive<0 then send_npc_reply(-1,"[Bouncer] triggers and ("..attacker.ai_misc_str..") is unsummoned.",judge) card_ability_Unsummon({nil,attacker}) trap_sound(bouncer) bouncer.time_alive=0 return true end local caltrops=have_card_on_battlefield("Caltrops",get_side(tgt),attacker.map_level) if caltrops~=nil and caltrops.time_alive<0 and not (attackercard.flying or attacker:get_health(HN_FLYING)~=0) then send_npc_reply(-1,"[Caltrops] triggers and ("..attacker.ai_misc_str..") takes 1 damage.",judge) local died=damage_card(attacker,2,nil) trap_sound(caltrops) caltrops.time_alive=0 if died then return true end end if not attackercard.flying and attacker:get_health(HN_FLYING)==0 then local molluscs=get_cards_on_battlefield("Dangerous Mollusc",get_side(tgt),attacker.map_level) for idx,m in ipairs(molluscs) do send_npc_reply(-1,"[Dangerous Mollusc] damages ("..attacker.ai_misc_str..") for 1 damage.",judge) local died=damage_card(attacker,1,nil) if died then return true end end end if caltrops~=nil and caltrops.time_alive<0 and not (attackercard.flying or attacker:get_health(HN_FLYING)~=0) then send_npc_reply(-1,"[Caltrops] triggers and ("..attacker.ai_misc_str..") takes 2 damage.",judge) local died=damage_card(attacker,2,nil) trap_sound(caltrops) caltrops.time_alive=0 if died then return true end end local purple=have_card_on_battlefield("Delayed Blast Purple",get_side(tgt),attacker.map_level) if purple~=nil and purple.time_alive<0 and tgt.code~=0xb44e then send_npc_reply(-1,"[Delayed Blast Purple] triggers and ("..tgt.ai_misc_str..") gains +2/+0 till end of turn.",judge) tgt.thaco_bonus=tgt.thaco_bonus+2 trap_sound(purple) purple.time_alive=0 end return false end function check_for_counterspell(card, z) local judge, judge_vars=get_judge_and_vars(z) local counterspell=have_card_on_battlefield("Counterspell",otherside(judge_vars.turn),z) local scatter=have_card_on_battlefield("Essence Dispersion",otherside(judge_vars.turn),z) if card.typ==string.byte("s") and counterspell~=nil and counterspell.time_alive<0 then send_npc_reply(-1,"[Counterspell] triggers and ("..card.name..") is countered.",judge) trap_sound(counterspell) counterspell.time_alive=0 return true elseif card.typ==string.byte("c") and scatter~=nil and scatter.time_alive<0 then send_npc_reply(-1,"[Essence Dispersion] triggers and ("..card.name..") is countered.",judge) trap_sound(scatter) scatter.time_alive=0 return true end return false end function check_for_heart_damage_trigger(tgt,dmg,attacker) -- return dmg to inflict to tgt -- this assumes tgt is a heart! local z=tgt.map_level local judge, judge_vars=get_judge_and_vars(z) local eye=have_card_on_battlefield("Eye for an Eye",get_side(tgt),z) if eye~=nil and eye.time_alive<0 then local oppheart if get_side(eye)=="blue" then oppheart=get_monster_ptr_xyz(redHeartPos[1],redHeartPos[2],z) else oppheart=get_monster_ptr_xyz(blueHeartPos[1],blueHeartPos[2],z) end send_npc_reply(-1,"[Eye for an Eye] triggers and ("..ucwords(get_side(oppheart)).."'s Hearthstone) takes "..dmg.." damage.", judge) trap_sound(eye) eye.time_alive=0 if damage_card(oppheart,dmg,eye) then return 0 end -- attacker's heart died, so don't do dmg to tgt heart end return dmg end function check_played_sorcery_triggers(cardname, turn, z) local fov=false local pools=get_cards_on_battlefield("Enchanted Clay Pool",turn,z) for idx,m in ipairs(pools) do spawn_token_helper(0x256,m.x,m.y,z,1,1,"Clay Golem") fov=true end -- hybrid drakes -- this should like be more generic somehow local drakes=get_cards_on_battlefield("Hybrid Drake",turn,z) for idx,m in ipairs(drakes) do m:set_thaco(m:get_thaco()+1) refresh_mob_name(m) fov=true end if string.find(cardname , "Potion")~=nil then local recycs=get_cards_on_battlefield("Recycling Centre",turn,z) for idx,m in ipairs(recycs) do local m=spawn_token_helper(0x200,m.x,m.y,z,1,1,"Empty Flask") if m~=nil then m.code=0x14f end end end if fov then update_everyones_fov(z) end -- needed? untested end function check_for_sacrifice_triggers(turn,sacd_card_name,sacx,sacy,z) local cw=get_cards_on_battlefield("Crypt Wizard",turn,z) for idx,m in ipairs(cw) do -- spawn a zombie token spawn_token_helper(0x22a,sacx,sacy,z,2,2,"Zombie") end local vd=get_cards_on_battlefield("Void Demon",turn,z) for idx,m in ipairs(vd) do m.hp=m:get_hp_max() m:set_thaco(m:get_thaco()+1) refresh_mob_name(m) end end function select_random_card_from_graveyard_or_lib(gy,typ,subtype) -- pass nil to type for any -- will return false if no matching card found if gy==nil then return false end local allcards={} local cardsByType={} local cardsBySubtype={} local str=get_mob_inv_string(gy) local inv=explode("|",str) for k,v in pairs(inv) do local x=explode(" ", v) local itm=Item() itm:setFromStr(x[1]) if get_base_code(itm)==0x811 then local card=wl:get_card_info(wl:get_name(itm)) if card~=nil then -- save card into cart type array if cardsByType[card.typ]==nil then cardsByType[card.typ]={} end table.insert(cardsByType[card.typ], card) -- save all card subtypes into subtype array -- this potion subtype is a total hack and a bit sad if subtype=="potion" and string.find(card.name , "Potion")~=nil then if cardsBySubtype["potion"]==nil then cardsBySubtype["potion"]={} end table.insert(cardsBySubtype["potion"], card) end -- normal subtypes if card.subtyp~="" then local x=explode(",",card.subtyp) for k2,st in pairs(x) do st=trim2(st) if cardsBySubtype[st]==nil then cardsBySubtype[st]={} end table.insert(cardsBySubtype[st], card) end end -- save card into all cards array table.insert(allcards, card) end end end if typ==nil then return get_random_element(allcards) end if subtype==nil then return get_random_element(cardsByType[typ]) end return get_random_element(cardsBySubtype[subtype]) end function get_current_cards_player_id(z) local judge, judge_vars=get_judge_and_vars(z) local pid=-1 if judge_vars.turn=="red" then pid=find_player(judge_vars.redname) elseif judge_vars.turn=="blue" then pid=find_player(judge_vars.bluename) end return pid end function get_current_cards_player_gy(z) local judge, judge_vars=get_judge_and_vars(z) local gy if judge_vars.turn=="red" then gy=get_monster_ptr_xyz(redGraveyardPos[1], redGraveyardPos[2], z) elseif judge_vars.turn=="blue" then gy=get_monster_ptr_xyz(blueGraveyardPos[1], blueGraveyardPos[2], z) end return gy end -- these are called by death_func of the permanent function cards_death_func_red(m) permanent_card_removed_from_battlefield(m,"red") end function cards_death_func_blue(m) permanent_card_removed_from_battlefield(m,"blue") end function permanent_card_removed_from_battlefield(m, owner_colour) if m:get_health(HN_TOKEN)~=0 then return end -- don't put tokens in gy writelog2("into gy "..m.ai_misc_str) local carditm=Item() -- get gy local gy=get_graveyard_by_colour(owner_colour, m.map_level) carditm:setFromStr("811.."..add_us2(m.ai_misc_str)) put_card_in_graveyard(gy,carditm) end function put_card_in_graveyard(graveyard,itm) graveyard:give_item(itm,1) refresh_mob_name(graveyard) update_everyones_fov(graveyard) end function spawn_artifact(turn,z,name,code) if true or not have_card_on_battlefield(name,turn,z) then local x,y=get_summon_location(wl:get_card_info(name), turn, z) local m=spawn_token_helper(0x200,x,y,z,1,1,name) m.code=code end end