Skip to content

Instantly share code, notes, and snippets.

@Tarmean
Last active March 10, 2018 22:09
Show Gist options
  • Select an option

  • Save Tarmean/d1ae6d095a0d6014c52496a82c26b923 to your computer and use it in GitHub Desktop.

Select an option

Save Tarmean/d1ae6d095a0d6014c52496a82c26b923 to your computer and use it in GitHub Desktop.
Prime_Punchmech.PathSize = INT_MAX
Prime_Punchmech.Damage = 1
-- statemachine for the conga
local Tracked = {}
local ST_ACTIVE = 0 -- in the conga
local ST_DROPPED = 1 -- fell into a hole
local ST_PUSHED = 2 -- run into an immovable obstacle, acts as an immovable obstacle itself now
local ST_PAUSED = 3 -- temporarily paused until the conga catches up
function Prime_Punchmech:GetSkillEffect(p1, p2)
local ret = SkillEffect()
local dir = GetDirection(p2 - p1)
local dirv = DIR_VECTORS[dir]
local final_state = Tracked:New(p1, dirv):GetPositions(self.PathSize)
for i = #final_state, 1, -1 do
local p = final_state[i]
DoAction(p, ret)
end
for i = 0, p1:Manhattan(final_state[1].pos)-1 do
ret:AddBounce(p1 + DIR_VECTORS[dir]*i, -3)
local damage = SpaceDamage(p1 + DIR_VECTORS[dir]*i, 0)
damage.sItem = "Item_Mine"
damage.sAnimation = "exploout0_"..(dir)%4
ret:AddDamage(damage)
ret:AddDelay(0.06)
end
for _, p in ipairs(final_state) do
ret:AddBounce(p.pos, -5)
ret:AddEmitter(p.pos, "Emitter_Burst")
end
for _, p in ipairs(final_state.obstacles) do
ret:AddBounce(p, -6)
local s = SpaceDamage(p, 1)
s.sScript = "this is a test"
ret:AddDamage(s)
end
ret:AddBoardShake(0.5)
ret:AddSound("/impact/generic/explosion")
return ret
end
function DoAction(p, ret)
if p.state == ST_DROPPED then
-- this abuses a bug in the preview code
-- the preview shows the unit dieing from DAMAGE_DEATH, the execution shows the unit diving charging to its death
ret:AddCharge(p.path, NO_DELAY)
local damage = SpaceDamage(p.orig_pos, DAMAGE_DEATH)
ret:AddDamage(damage)
else
-- we do the damage at orig_pos because WEIRD THINGS happen to the preview if we damage at pos.
-- this sucks because fires and smoke icons are visible when we suppress them
local damage = SpaceDamage(p.orig_pos, 1)
damage.sImageMark = "combat/arrow_hit.png"
if not Board:IsFire(p.orig_pos) then
damage.iFire = EFFECT_REMOVE
end
if not Board:IsSmoke(p.orig_pos) then
damage.iSmoke = EFFECT_REMOVE
end
damage.iTerrain = Board:GetTerrain(p.orig_pos)
ret:AddDamage(damage)
ret:AddCharge(p.path, NO_DELAY)
end
end
function Tracked:GetPositions(left)
while left > 0 and not self:Done() do
self:Setup()
for i = #self, 1, -1 do
local pawn = self[i]
if self:Interacts(pawn) then
local next_pos = pawn.pos + self.dirv
local succ = self:GetKnown(next_pos)
local next_pawn = self:GetUnknown(next_pos)
local invalid_terr = self:CheckTerrain(pawn.pathprof, next_pos)
if succ then
if succ.state == ST_PAUSED then
break
else
pawn.state = ST_PUSHED
end
elseif next_pawn then
break
elseif invalid_terr == TERR_COLLISION then
pawn.state = ST_PUSHED
elseif invalid_terr == TERR_DROPPED then
pawn.state = ST_DROPPED
end
if pawn.state ~= ST_PUSHED then
pawn.pos = next_pos
pawn.path:push_back(next_pos)
end
if pawn.state == ST_DROPPED then
break
end
end
if i == 1 then
left = left - 1
end
end
end
return self
end
Tracked.__index = Tracked
function Tracked:New(p0, dirv)
local o = {}
setmetatable(o, self)
o[1] = mkMarker(Board:GetPawn(p0))
o.obstacles = {}
o.dirv = dirv
return o
end
function Tracked:Interacts(p)
return p.state == ST_ACTIVE-- and (self:Alive(p) or p.id == self[1].id)
end
function Tracked:Alive(p)
return (p.state ~= ST_DROPPED) and not p.dead
end
function Tracked:Done()
local pred = function(p)
return not self:Interacts(p)
end
local all_stopped = all(self, pred)
return all_stopped or self:CheckTerrain(self[1].pathprof, self[1].pos + self.dirv)
end
function Tracked:GetKnown(p)
return findBy(self, function(x) return (x.pos == p) and self:Alive(x) end)
end
function Tracked:GetUnknown(p)
local board_pawn = Board:GetPawn(p)
return board_pawn and self:Unknown(board_pawn) and board_pawn
end
function Tracked:Unknown(pawn)
local id = pawn:GetId()
return all(self, function(p) return p.id ~= id end)
end
function Tracked:Get(p)
local r = self:GetKnown(p)
if r then
return r
end
r = self:GetUnknown(p)
if r then
r = mkMarker(r)
self[#self+1] = r
return r
end
return nil
end
-- called whenever the conga changes
function Tracked:Setup()
for _,v in ipairs(self) do
if v.state == ST_ACTIVE then
v.state = ST_PAUSED
end
end
local current = self[1]
while current do
if current.state == ST_PAUSED then
current.state = ST_ACTIVE
end
current = self:Get(current.pos + self.dirv)
end
end
function all(ls, pred)
for _, y in ipairs(ls) do
if not pred(y) then
return false
end
end
return true
end
function findBy(ls, pred)
for _, y in ipairs(ls) do
if pred(y) then
return y
end
end
return nil
end
function mkMarker(pawn)
local list = PointList()
local pos = pawn:GetSpace()
list:push_back(pos)
local state = pawn:IsGuarding() and ST_PUSHED or ST_ACTIVE
local dead = pawn:GetHealth() <= 1
-- TODO: don't hardcode 1 damage
local o = { pos = pos, dead = dead, orig_pos = pos, id = pawn:GetId(), pathprof = pawn:GetPathProf(), state = state, path = list}
return o
end
TERR_COLLISION = 1
TERR_DROPPED = 2
-- for some reason these are missing lua side
local PATH_FLIER = 1
local PATH_LEAPER = 6
INVALID_TERRAINS =
{ [PATH_FLIER] = -- 1
{ [TERRAIN_BUILDING] = TERR_COLLISION
, [TERRAIN_MOUNTAIN] = TERR_COLLISION
}
, [PATH_GROUND] = -- 0
{ [TERRAIN_BUILDING] = TERR_COLLISION
, [TERRAIN_MOUNTAIN] = TERR_COLLISION
, [TERRAIN_ACID] = TERR_DROPPED
, [TERRAIN_HOLE] = TERR_DROPPED
, [TERRAIN_LAVA] = TERR_DROPPED
, [TERRAIN_WATER] = TERR_DROPPED
}
, [PATH_LEAPER] = -- 6
{ [TERRAIN_BUILDING] = TERR_COLLISION
, [TERRAIN_MOUNTAIN] = TERR_COLLISION
, [TERRAIN_ACID] = TERR_DROPPED
, [TERRAIN_HOLE] = TERR_DROPPED
, [TERRAIN_LAVA] = TERR_DROPPED
, [TERRAIN_WATER] = TERR_DROPPED
}
, [PATH_MASSIVE] = -- 2
{ [TERRAIN_BUILDING] = TERR_COLLISION
, [TERRAIN_MOUNTAIN] = TERR_COLLISION
, [TERRAIN_HOLE] = TERR_COLLISION
}
, [PATH_PHASING] = {} -- 9
, [PATH_PROJECTILE] = -- 3
{ [TERRAIN_BUILDING] = TERR_COLLISION
, [TERRAIN_MOUNTAIN] = TERR_COLLISION
}
, [PATH_ROADRUNNER] = -- 4
{ [TERRAIN_BUILDING] = TERR_COLLISION
, [TERRAIN_MOUNTAIN] = TERR_COLLISION
, [TERRAIN_ACID] = TERR_DROPPED
, [TERRAIN_HOLE] = TERR_DROPPED
, [TERRAIN_LAVA] = TERR_DROPPED
, [TERRAIN_WATER] = TERR_DROPPED
}
}
function Tracked:CheckTerrain(path, pos)
local result = InvalidTerrain(path, pos)
if result == TERR_COLLISION then
self.obstacles[#self.obstacles+1] = pos
end
return result
end
function InvalidTerrain(pathtype, pos)
local pathtype = pathtype % 16
if not Board:IsValid(pos) then
return TERR_COLLISION
end
local table = INVALID_TERRAINS[pathtype]
if not table then
-- log.error("invalid pathtype: " .. pathtype .. "! ")
table = INVALID_TERRAINS[PATH_GROUND]
end
local terr = Board:GetTerrain(pos)
return table[terr]
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment