-- Projectile: moves in a straight line, damages opponents on contact Projectile = {} Projectile.__index = Projectile function Projectile:new(sprite, combatant, config) self = setmetatable({}, Projectile) self.sprite = sprite self.combatant = combatant self.context = combatant.context self.x = config.x or 0 self.y = config.y or 0 self.dirX = config.dirX or 1 self.dirY = config.dirY or 0 self.speed = config.speed or 250 self.power = config.power or 1 self.alive = true self.width = self.sprite.width self.height = self.sprite.height return self end function Projectile:update(dt) self.x = self.x + self.dirX * self.speed * dt self.y = self.y + self.dirY * self.speed * dt -- Off screen if self.x < -20 or self.x > Config.ROOM_W + 20 or self.y < -20 or self.y > Config.ROOM_H + 20 then self.alive = false return end -- Wall collision local cx = math.floor(self.x + self.width / 2) local cy = math.floor(self.y + self.height / 2) if self:isSolid(cx, cy) then ParticlePlayer:play("arrow_wall", cx, cy, { duration = 0.3 }) self.alive = false return end -- Only hit opposing team local opponents = Utils.filterCombatantsByOpposingTeams(self.context.combatants, self.combatant.team) for _, target in ipairs(opponents) do if target.health > 0 and target.team ~= self.combatant.team then local tx = target.x + target.width / 2 local ty = target.y + target.height / 2 local dx = (self.x + self.width / 2) - tx local dy = (self.y + self.height / 2) - ty if math.abs(dx) < (self.width / 2 + target.width / 2) and math.abs(dy) < (self.height / 2 + target.height / 2) then local atk = (self.combatant.stats and self.combatant.stats.atk or 5) * self.power local lck = self.combatant.stats and self.combatant.stats.lck or 0 local def = target.stats and target.stats.def or 0 local maxDmg = atk - def if maxDmg < lck then maxDmg = lck end local damage = math.random(lck, maxDmg) target:damage(damage) local knockDir = self.dirX > 0 and 1 or -1 local knockStr = (target.team == 2) and 180 or 150 target:knockback(knockDir, knockStr) ParticlePlayer:play("damage", math.floor(self.x), math.floor(self.y), { duration = 0.5 }) self.alive = false return end end end end function Projectile:isSolid(px, py) if px < 0 or px >= Config.ROOM_W or py < 0 or py >= Config.ROOM_H then return true end if self.context.roomManager.currentRoomCollision then return Utils.maskIsSolidAt(px, py, self.context.roomManager.currentRoomCollision) end return false end function Projectile:draw() --love.graphics.setColor(0.9, 0.9, 0.3, 1) --love.graphics.rectangle("fill", math.floor(self.x), math.floor(self.y), self.width, self.height) --love.graphics.setColor(1, 1, 1, 1) self.sprite:drawAnimationFrame(self.x, self.y, { scale = { self.dirX or 1, 1 } }) end return Projectile