Browse files

Add more spells.

  • Loading branch information...
1 parent 593498b commit 1c9731c7d46f717a7160c4c3232a1d75a1484dde @sharpobject committed May 3, 2012
Showing with 392 additions and 16 deletions.
  1. +61 −4 buff.lua
  2. +33 −1 engine.lua
  3. +3 −0 errors.txt
  4. +7 −7 skills.lua
  5. +288 −4 spells.lua
View
65 buff.lua
@@ -1,20 +1,71 @@
-Buff = class(function(self, player)
+GlobalBuff = class(function(self, player)
self.game = player.game
self.field = {[player] = {}, [player.opponent]={}}
self.hand = {[player] = {}, [player.opponent]={}}
self.deck = {[player] = {}, [player.opponent]={}}
end)
-function Buff:apply()
+function GlobalBuff:apply()
self.game:apply_buff(self)
end
-local maids = arr_to_set({200012, 200082, 200148, 200446, 300019, 300020,
+OnePlayerBuff = class(function(self, player)
+ self.player = player
+ end)
+
+function OnePlayerBuff:apply()
+ local gb = GlobalBuff()
+ for k,v in pairs(self) do
+ if k~= "player" then
+ gb.field[self.player][k]=v
+ end
+ end
+ gb:apply()
+end
+
+OneBuff = class(function(self, player, idx, buff)
+ self.player = player
+ self.idx = idx
+ self.buff = buff
+ end)
+
+function OneBuff:apply()
+ local gb = GlobalBuff()
+ gb.field[self.player][self.idx] = self.buff
+ gb:apply()
+end
+
+local groups = {}
+groups.maid = arr_to_set({200012, 200082, 200148, 200446, 300019, 300020,
300021, 300022, 300023, 300024, 300025, 300026,
300033, 300034, 300117, 300118, 300120, 300147,
300177, 300183, 300184, 300212, 300214, 300215,
300239})
+groups.sita = arr_to_set({100001, 100010, 100015, 100020, 100025, 100036,
+ 100050, 100054, 100090, 100102, 100108, 100124, 100140,
+ 100147, 110018, 110114, 110215, 200239, 300111, 300210,
+ 300320, 300321, 300332, 300427, 300433, 300496, 300533})
+
+groups.cook_club = arr_to_set({110105, 300001, 300002, 300003, 300004, 300005,
+ 300006, 300007, 300008, 300112, 300140, 300245, 300247, 300280,
+ 300400, 300415, 300416, 300417, 300463, 300464, 300509, 300520})
+
+groups.luthica = arr_to_set({100003, 100012, 100017, 100022, 100027, 100038,
+ 100052, 100056, 100092, 100104, 100110, 100126, 100142, 100149,
+ 110020, 110116, 110216, 200061, 200245, 300226, 300324, 300325,
+ 300334, 300429, 300437, 300498, 300535})
+
+groups.knight = arr_to_set({100043, 100067, 100119, 100123, 110051, 110059,
+ 110136, 110151, 110156, 110162, 110244, 120017, 200027, 200271,
+ 200421, 300037, 300038, 300039, 300040, 300041, 300042, 300043,
+ 300044, 300046, 300096, 300122, 300129, 300155, 300158, 300159,
+ 300160, 300189, 300192, 300221, 300224, 300259, 300261, 300265,
+ 300266, 300289, 300290, 300294, 300310, 300311, 300334, 300343,
+ 300345, 300366, 300397, 300405, 300422, 300423, 300438, 300439,
+ 300454, 300455, 300456, 300457, 300468, 300469, 300481, 300482,
+ 300514, 300516, 300526, 300527, 300528})
+
pred = {}
pred.faction = {}
for _,v in ipairs({"V","A","D","C","N"}) do
@@ -29,4 +80,10 @@ for _,v in ipairs({"size","atk","def","sta"}) do
local stat=v
pred[v] = function(card) return card[stat] or -9000 end
end
-pred.maid = function(card) return maids[card.id] end
+for v in pairs(groups) do
+ local name = v
+ pred[v] = function(card) return groups[name][card.id] end
+end
+
+pred.t = function() return true end
+pred.f = function() return false end
View
34 engine.lua
@@ -1,3 +1,5 @@
+local max = math.max
+
Card = class(function(self, id, upgrade_lvl)
self.upgrade_lvl = upgrade_lvl or 0
for k,v in pairs(id_to_canonical_card[id]) do
@@ -113,11 +115,17 @@ end
-- discards the card at index n
function Player:hand_to_grave(n)
self.grave[#self.grave + 1] = self.hand[n]
+ self.grave[#self.grave]:reset()
for i=n,5 do
self.hand[i] = self.hand[i+1]
end
end
+function Player:field_to_bottom_deck(n)
+ self:to_bottom_deck(self.field[n])
+ self.field[n] = nil
+end
+
function Player:field_to_grave(n)
self.grave[#self.grave + 1] = self.field[n]
self.grave[#self.grave]:reset()
@@ -139,7 +147,20 @@ function Player:field_size()
return ret
end
+function Player:ncards_in_field()
+ local ret = 0
+ for i=1,5 do
+ if self.field[i] then
+ ret = ret + 1
+ end
+ end
+ return ret
+end
+
function Player:hand_idxs_with_preds(preds)
+ if type(preds) ~= "table" then
+ preds = {preds}
+ end
local ret = {}
for i=1,5 do
if self.hand[i] then
@@ -405,17 +426,28 @@ end
}
function Game:apply_buff(buff)
+ local anything_happened = false
for _,zone in ipairs({"field", "hand", "deck"}) do
for player,idx_to_effect in pairs(buff[zone]) do
for idx,effects in pairs(idx_to_effect) do
for stat,effect in pairs(effects) do
+ anything_happened = true
local which, howmuch = unpack(effect)
+ if which == "-" and stat == "size" then
+ howmux = max(player[zone][idx].size-1, howmuch)
+ end
+ if which == "=" and stat == "size" then
+ howmuch = max(1,howmuch)
+ end
buff_effects[which](player[zone][idx],stat,howmuch)
end
end
end
end
- self:clean_dead_followers()
+ if anything_happened then
+ -- TODO: animation
+ self:clean_dead_followers()
+ end
end
function Game:run()
View
3 errors.txt
@@ -1,2 +1,5 @@
+Heartless blow cannot hit the same follower twice if there are other valid choices.
+Balance does not specify whether it rounds life up or down. It rounds up. It also has text that would suggest it can send cards from both fields to the grave, when it cannot.
+Rumored Order does not specify which largest follower it targets.
Vampiric Rites reads "All allied followers get size=1 and atk=1/sta=1...", but does not increase the atk of followers with less than 1 atk. It does not specify that the first of the smallest darklore followers is the one chosen for the buff.
Entry denied reads "One allied follower is deactivated." It does not specify that the first follower is chosen.
View
14 skills.lua
@@ -30,7 +30,7 @@ skill_func = {
[1007] = function(player)
local target_idx = uniformly(player:field_idxs_with_preds({pred.maid,pred.follower}))
if target_idx then
- local buff = Buff(player)
+ local buff = GlobalBuff(player)
buff.field[player][target_idx] = {atk={"+",1}, sta={"+",1}}
buff:apply()
end
@@ -41,15 +41,15 @@ end,
local spell_idx = player:hand_idxs_with_preds({pred.spell})[1]
if spell_idx then
player:hand_to_grave(spell_idx)
- local buff = Buff(player)
+ local buff = GlobalBuff(player)
buff.field[player][my_idx] = {atk={"+",2}}
buff:apply()
end
end,
-- mop maid, mop slash
[1009] = function(player, my_idx)
- local buff = Buff(player)
+ local buff = GlobalBuff(player)
local idxs = player:field_idxs_with_preds({pred.follower})
for _,idx in ipairs(idxs) do
if math.abs(my_idx - idx) <= 1 then
@@ -62,7 +62,7 @@ end,
-- aristocrat girl, noblesse
[1010] = function(player, my_idx, my_card, other_idx, other_card)
if other_card.def >= 2 then
- local buff = Buff(player)
+ local buff = GlobalBuff(player)
buff.field[player.opponent][other_idx] = {sta={"-",3}}
buff:apply()
end
@@ -72,22 +72,22 @@ end,
[1011] = function(player)
local target_idx = uniformly(player.opponent:field_idxs_with_preds({pred.follower}))
if target_idx then
- local buff = Buff(player)
+ local buff = GlobalBuff(player)
buff.field[player.opponent][target_idx] = {atk={"-",1}}
buff:apply()
end
end,
--senpai maid, i'll try my best
[1012] = function(player, my_idx)
- local buff = Buff(player)
+ local buff = GlobalBuff(player)
buff.field[player][my_idx] = {atk={"+",1}, sta={"+",2}}
buff:apply()
end,
--striker, fireball!
[1013] = function(player, my_idx, my_card, other_idx)
- local buff = Buff(player)
+ local buff = GlobalBuff(player)
buff.field[player.opponent][other_idx] = {sta={"-",1}}
buff:apply()
end,
View
292 spells.lua
@@ -1,9 +1,184 @@
-local floor,ceil = math.floor, math.ceil
+local floor,ceil,min,max = math.floor, math.ceil, math.min, math.max
+local abs = math.abs
+
+local new_student_orientation = function(player, my_idx, my_card)
+ local target_idxs = shuffle(player:field_idxs_with_preds({pred.faction[my_card.faction]}))
+ local buff = OnePlayerBuff(player)
+ for i=1,2 do
+ if target_idxs[i] then
+ buff[target_idxs[i]] = {atk={"+",2},sta={"+",2}}
+ end
+ end
+ buff:apply()
+end
spell_func = {
+-- heartless blow
+[200001] = function(player)
+ local target_idxs = shuffle(player.opponent:field_idxs_with_preds({pred.follower}))
+ if target_idxs[1] then
+ OneBuff(player.opponent, target_idxs[1], {sta={"-",4}}):apply()
+ end
+ if pred.sita(player.character) then
+ if target_idxs[2] then
+ target_idxs[1] = target_idxs[1]
+ end
+ if player.opponent.field[target_idxs[1]] then
+ OneBuff(player.opponent, target_idxs[1], {sta={"-",2}}):apply()
+ end
+ end
+end,
+
+-- new student orientation
+[200002] = new_student_orientation,
+
+-- cooking failure
+[200003] = function(player)
+ if #player.field_idxs_with_preds({pred.cook_club}) then
+ local target_idxs = shuffle(player.field_idxs_with_preds({pred.follower, pred.faction.V}))
+ local buff = OnePlayerBuff(player)
+ for i=1,min(2,#target_idxs) do
+ buff[target_idxs[i]] = {atk={"+",1},def={"+",1},sta={"+",2},size={"+",1}}
+ end
+ buff:apply()
+ end
+end,
+
+-- ward rupture
+[200004] = function(player)
+ local card, other_card = player.field[3], player.opponent.field[3]
+ if card and other_card and pred.faction.V(card) and pred.follower(card) then
+ local amount = abs(card.size - other.size)
+ OneBuff(player, 3, {atk={"+",amount},sta={"+",amount}}):apply()
+ end
+end,
+
+-- new recipe
+[200005] = function(player)
+ OneBuff(player,0,{life={"+",min(5,10-player:field_size())}}):apply()
+end,
+
+-- shrink
+[200006] = function(player)
+ local target_idx = player.opponent:field_idxs_with_most_and_preds(
+ pred.size, {pred.follower})[1]
+ if target_idx then
+ local card = player.opponent.field[target_idx]
+ OneBuff(player.opponent,target_idx,{sta={"=",floor(card.sta/2)},
+ atk={"=",floor(card.atk/2)},def={"=",floor(card.def/2)},
+ size={"=",floor(card.size/2)}}):apply()
+ end
+end,
+
+-- balance
+[200007] = function(player)
+ if abs(player.character.life - player.opponent.character.life) <= 25 then
+ local buff = GlobalBuff()
+ local new_life = ceil((player.character.life + player.opponent.character.life)/2)
+ buff.field[player][0] = {life={"=",new_life}}
+ buff.field[player.opponent][0] = {life={"=",new_life}}
+ buff:apply()
+ end
+ local more_stuff,less_stuff = player, player.opponent
+ if less_stuff:ncards_in_field() > more_stuff:ncards_in_field() then
+ more_stuff,less_stuff = less_stuff,more_stuff
+ end
+ while less_stuff:ncards_in_field() < more_stuff:ncards_in_field() do
+ more_stuff:field_to_grave(more_stuff:field_idxs_with_preds({})[1])
+ end
+ local hand_pred = preds.t
+ if pred.faction.V(player.character) then
+ hand_pred = preds.follower
+ end
+ for i=1,#player.hand do
+ while player.hand[i] and hand_pred(player.hand[i]) do
+ player:hand_to_grave(i)
+ end
+ end
+end,
+
+-- rumored order
+[200008] = function(player)
+ local target_idx = player:field_idxs_with_most_and_preds(pred.size,
+ {pred.faction.V, pred.follower})[1]
+ if target_idx then
+ OneBuff(player,target_idx,{size={"-",2},sta={"+",2}}):apply()
+ end
+end,
+
+-- omnivore
+[200009] = function(player)
+ local target_idxs = shuffle(player:field_idxs_with_preds(pred.follower))
+ local sizes = {}
+ local buff_amount = 1
+ for i=1,#player.hand do
+ if not sizes[player.hand[i].size] then
+ sizes[player.hand[i].size] = true
+ buff_amount = buff_amount + 1
+ end
+ end
+ if #target_idxs then
+ local buff = OnePlayerBuff()
+ for i=1,min(#target_idxs,2) do
+ buff[target_idxs[i]] = {sta={"+",buff_amount}}
+ end
+ buff:apply()
+ end
+end,
+
+-- volcano
+[200010] = function(player)
+ local target_idx = uniformly(player.opponent:field_idxs_with_preds(pred.follower))
+ if target_idx then
+ local x = #player:hand_idxs_with_preds(pred.faction.V)
+ OneBuff(player.opponent, target_idx, {atk={"-",x},def={"-",x},sta={"-",x}}):apply()
+ end
+end,
+
+-- accident
+[200011] = function(player)
+ local debuff_amount = #player:field_idxs_with_preds({pred.maid,pred.follower})
+ local target_idxs = player.opponent:field_idxs_with_preds(pred.follower)
+ local buff = OnePlayerBuff(player.opponent)
+ for i=1,min(2,#target_idxs) do
+ buff[target_idxs[i]] = {atk={"-",debuff_amount},sta={"-",debuff_amount}}
+ end
+ buff:apply()
+end,
+
+-- new maid training
+[200012] = new_student_orientation,
+
+-- she did it
+[200013] = function(player)
+ if #player:field_idxs_with_preds({pred.maid,pred.follower}) then
+ local buff = OnePlayerBuff(player)
+ local target_idxs = player:field_idxs_with_preds(pred.follower)
+ local reduced_amount = 0
+ for _,idx in ipairs(target_idxs) do
+ reduced_amount = reduced_amount + player.field[idx].size
+ buff[idx] = {size={"=",1}}
+ end
+ buff:apply()
+ OneBuff(player,uniformly(target_idxs),{size={"+",reduced_amount},
+ sta={"+",floor(reduced_amount/2)}}):apply()
+ end
+end,
+
+-- noble sacrifice
+[200014] = function(player)
+ local target_idx = player:field_idxs_with_most_and_preds(pred.size,
+ {pred.follower, pred.faction.A})[1]
+ if target_idx then
+ local life_gain = player.field[target_idx].size*2
+ player:field_to_grave(target_idx)
+ OneBuff(player,0,{life={"+",life_gain}}):apply()
+ end
+end,
+
-- tighten security
[200015] = function(player)
- local buff = Buff(player)
+ local buff = GlobalBuff(player)
local target_idx = player:field_idxs_with_preds({pred.faction.A, pred.follower})[1]
local how_much = #(player:hand_idxs_with_preds({pred.faction.A}))
if target_idx then
@@ -12,10 +187,20 @@ spell_func = {
end
end,
+-- bondage
+[200016] = function(player)
+ local buff = OnePlayerBuff(player.opponent)
+ local target_idxs = player.opponent:field_idxs_with_preds(pred.follower)
+ for i=1,min(3,target_idxs) do
+ buff[target_idxs[i]] = {size={"+",1}}
+ end
+ buff:apply()
+end,
+
-- curse
[200017] = function(player)
if player.character.faction == "A" then
- local debuff = Buff(player)
+ local debuff = GlobalBuff(player)
local tar1, tar2 = unpack(shuffled(
player.opponent:field_idxs_with_preds({pred.follower})))
for _,idx in ipairs({tar1,tar2}) do
@@ -27,6 +212,62 @@ end,
end
end,
+-- swap spell
+[200018] = function(player)
+ local card = player.field[3]
+ local idx = player.opponent:field_idxs_with_preds(pred.follower)
+ if card and idx then
+ local other_card = player.opponent.field[idx]
+ local buff = GlobalBuff(player)
+ buff.field[player][3],buff.field[player.opponent][idx] = {},{}
+ for _,stat in ipairs({"atk","def","sta","size"}) do
+ buff.field[player][3][stat] = {"=",other_card[stat]}
+ buff.field[player.opponent][idx][stat] = {"=",card[stat]}
+ end
+ buff:apply()
+ end
+end,
+
+-- mass recall
+[200019] = function(player)
+ for i=1,5 do
+ if player.opponent.field[i] and player.opponent.field[i].size <= 3 then
+ player.opponent:field_to_grave(i)
+ end
+ if player.field[i] and player.field[i].faction ~= "A" then
+ player:field_to_grave(i)
+ end
+ end
+end,
+
+-- forced entry
+[200020] = function(player)
+ if player.field[3] and player.opponent.field[3] then
+ if player.field[3].size < player.opponent.field[3].size then
+ player:destroy(3)
+ elseif player.field[3].size > player.opponent.field[3].size then
+ player.opponent:destroy(3)
+ else
+ player.opponent:field_to_grave(3)
+ end
+ end
+end,
+
+-- saint's blessing
+[200021] = function(player)
+ local target_idxs = player:field_idxs_with_preds(pred.knight)
+ local buff = OnePlayerBuff(player)
+ for _,idx in ipairs(target_idxs) do
+ buff[idx] = {sta={"+",3}}
+ if preds.luthica(player.field(0)) then
+ buff[idx].atk = {"+",3}
+ end
+ end
+end,
+
+-- close encounter
+[200022] = new_student_orientation,
+
-- entry denied
[200023] = function(player)
local my_idx = player:field_idxs_with_preds({pred.follower})[1]
@@ -41,6 +282,11 @@ end,
end
end,
+-- healing magic
+[200024] = function(player)
+ OneBuff(player, 0, {life = {"+", #player.hand}}):apply()
+end,
+
-- sky surprise
[200025] = function(player)
local old_idx = player:get_follower_idxs()[1]
@@ -55,10 +301,48 @@ end,
end
end,
+-- meadow leisure
+[200026] = function(player)
+ local target_idx = uniformly(player:field_idxs_with_preds(pred.follower))
+ if target_idx then
+ local ncards = player:ncards_in_field()
+ OneBuff(player, target_idx, {atk={"+",ncards-1},sta={"+",ncards+1}}):apply()
+ end
+end,
+
+-- knight's letter
+[200027] = function(player)
+ if player:ncards_in_field() == player.opponent:ncards_in_field() then
+ local target_idxs = shuffle(player.opponent:field_idxs_with_preds())
+ for i=1,min(2,#target_idxs) do
+ player.opponent:field_to_bottom_deck(target_idxs[i])
+ end
+ end
+end,
+
+-- shield break
+[200028] = function(player)
+ local target_idx = player.opponent:field_idxs_with_most_and_preds(pred.def,pred.follower)[1]
+ if target_idx then
+ local def = player.opponent.field[target_idx].def
+ if def > 0 then
+ OneBuff(player.opponent,target_idx,{def={"-",2*def}})
+ end
+ end
+end,
+
+-- sentry's testimony
+[200029] = function()
+
+end,
+
+-- blood reversal
+[200032] = new_student_orientation,
+
-- vampiric rites
[200033] = function(player)
local idxs = player:get_follower_idxs()
- local reduced_atk, reduced_sta, debuff, buff = 0, 0, Buff(player), Buff(player)
+ local reduced_atk, reduced_sta, debuff, buff = 0, 0, GlobalBuff(player), GlobalBuff(player)
local buff_stats = {sta={"+",0}, atk={"+",0}, size={"+",0}}
for _,idx in ipairs(idxs) do
local card = player.field[idx]

0 comments on commit 1c9731c

Please sign in to comment.