Verified Commit 1ac5ce1c authored by Lars Mitsem Selbekk's avatar Lars Mitsem Selbekk Committed by Mathias O. Myklebust
Browse files

Use passed caster-Hero for ActiveSpell-target

Previously, battle.hero1 was always used for the target, which made
sense except for when spells cast by the other player needed to be
applied. This adds a parameter so the ActiveSpell knows who cast it.

The reason this touches so many files is that the parameterization of
Hero<Spell<*>> needed to be removed because the type system isn't
capable enough. This means that using a Hero's Spell will always require
a check of the Spell type.

Closes #62
parent 990a673b
......@@ -166,15 +166,7 @@ class BattleController(
val spellsIterator = activeSpells.iterator()
while (spellsIterator.hasNext()) {
val spell = spellsIterator.next()
println(
"Applying spell $spell, hero1 ${battle.hero1.currentStats.actionPoints} " +
"${battle.hero2.currentStats.actionPoints}"
)
spell.apply(battle)
println(
"Applied spell, hero1 ${battle.hero1.currentStats.actionPoints} " +
"${battle.hero2.currentStats.actionPoints}"
)
if (spell.finished) {
spellsIterator.remove()
}
......@@ -249,19 +241,20 @@ class BattleController(
is SpellData.AdrenalineShot -> {
if (spell !is AdrenalineShotSpell)
throw IllegalStateException("Performed spell by other player isn't their spell")
spell.cast(spellData)
spell.cast(battle.hero2, spellData)
}
is SpellData.EphemeralAllegiance -> {
if (spell !is EphemeralAllegianceSpell)
throw IllegalStateException("Performed spell by other player isn't their spell")
spell.cast(
battle.hero2,
spellData.copy(targetPosition = otherPerspective(spellData.targetPosition))
)
}
is SpellData.Bird52 -> {
if (spell !is Bird52Spell)
throw IllegalStateException("Performed spell by other player isn't their spell")
spell.cast(spellData)
spell.cast(battle.hero2, spellData)
}
}
battle.activeSpells.second.add(activeSpell)
......@@ -299,17 +292,17 @@ class BattleController(
.random(random)
)!!
)
battle.activeSpells.first += battle.hero1.spell.cast(data)
battle.activeSpells.first += battle.hero1.spell.cast(battle.hero1, data)
data
}
is Bird52Spell -> {
val data = SpellData.Bird52
battle.activeSpells.first += battle.hero1.spell.cast(data)
battle.activeSpells.first += battle.hero1.spell.cast(battle.hero1, data)
data
}
is AdrenalineShotSpell -> {
val data = SpellData.AdrenalineShot
battle.activeSpells.first += battle.hero1.spell.cast(data)
battle.activeSpells.first += battle.hero1.spell.cast(battle.hero1, data)
data
}
else -> throw NotImplementedError(
......@@ -391,7 +384,7 @@ class BattleController(
return GridVector(battleMapController.mapSize.x - 1 - (pos.y % 2) - pos.x, pos.y)
}
private fun subtractActionPoints(hero: Hero<*>, pointsToSubtract: Int) {
private fun subtractActionPoints(hero: Hero, pointsToSubtract: Int) {
hero.applyStatsModifier(
HeroStatsModifier {
it.copy(actionPoints = it.actionPoints - pointsToSubtract)
......
......@@ -27,7 +27,7 @@ sealed class ActionState {
}
class BattleMapController(
private val hero: Hero<*>,
private val hero: Hero,
private val model: BattleMap,
private val view: BattleMapView,
private val onMoveUnit: (fromPosition: GridVector, toPosition: GridVector) -> Unit,
......
......@@ -12,7 +12,7 @@ import se.battlegoo.battlegoose.views.HeroSelectionViewModel
class HeroSelectionState : GameState() {
private val heroes: List<Hero<*>> = listOf(SergeantSwan(), MajorMallard(), AdmiralAlbatross())
private val heroes: List<Hero> = listOf(SergeantSwan(), MajorMallard(), AdmiralAlbatross())
private val heroSelection = HeroSelection(heroes)
private val heroSelectionView = HeroSelectionView(
heroes.map {
......
......@@ -5,8 +5,8 @@ import se.battlegoo.battlegoose.models.heroes.Hero
import se.battlegoo.battlegoose.models.spells.ActiveSpell
class Battle(
val hero1: Hero<*>,
val hero2: Hero<*>,
val hero1: Hero,
val hero2: Hero,
val battleMap: BattleMap,
val battleId: String,
val isHost: Boolean
......
......@@ -5,7 +5,7 @@ import se.battlegoo.battlegoose.models.units.DelinquentDuck
import se.battlegoo.battlegoose.models.units.GuardGoose
import se.battlegoo.battlegoose.models.units.PrivatePenguin
class AdmiralAlbatross : Hero<AdrenalineShotSpell>(
class AdmiralAlbatross : Hero(
HeroStats(),
AdrenalineShotSpell(),
"Admiral Albatross",
......
......@@ -5,9 +5,9 @@ import se.battlegoo.battlegoose.models.spells.Spell
import se.battlegoo.battlegoose.models.units.UnitModel
import kotlin.reflect.KClass
abstract class Hero<T : Spell<*>> (
abstract class Hero(
val baseStats: HeroStats,
val spell: T,
val spell: Spell<*>,
val name: String,
val description: String,
val heroSprite: HeroSprite,
......
package se.battlegoo.battlegoose.models.heroes
class HeroSelection(heroes: Collection<Hero<*>>) {
class HeroSelection(heroes: Collection<Hero>) {
private val heroesMap: Map<String, Hero<*>>
private val heroesMap: Map<String, Hero>
var selected: String = heroes.first()::class.java.name
set(value) {
......@@ -12,7 +12,7 @@ class HeroSelection(heroes: Collection<Hero<*>>) {
throw IllegalArgumentException("Tried to select non-existent hero")
}
val selectedHero: Hero<*>
val selectedHero: Hero
get() = heroesMap[selected]!!
init {
......
......@@ -5,7 +5,7 @@ import se.battlegoo.battlegoose.models.units.DelinquentDuck
import se.battlegoo.battlegoose.models.units.PrivatePenguin
import se.battlegoo.battlegoose.models.units.SpitfireSeagull
class MajorMallard : Hero<Bird52Spell>(
class MajorMallard : Hero(
HeroStats(),
Bird52Spell(),
"Major Mallard",
......
......@@ -6,7 +6,7 @@ import se.battlegoo.battlegoose.models.units.GuardGoose
import se.battlegoo.battlegoose.models.units.PrivatePenguin
import se.battlegoo.battlegoose.models.units.SpitfireSeagull
class SergeantSwan : Hero<EphemeralAllegianceSpell>(
class SergeantSwan : Hero(
HeroStats(),
EphemeralAllegianceSpell(),
"Sergeant Swan",
......
......@@ -2,9 +2,11 @@ package se.battlegoo.battlegoose.models.spells
import se.battlegoo.battlegoose.datamodels.SpellData
import se.battlegoo.battlegoose.models.Battle
import se.battlegoo.battlegoose.models.heroes.Hero
abstract class ActiveSpell<out T : Spell<*>>(
abstract class ActiveSpell<T : Spell<*>>(
val baseSpell: T,
val caster: Hero,
open val data: SpellData
) {
private var turnsSinceCast: Int = 0
......
......@@ -2,16 +2,17 @@ package se.battlegoo.battlegoose.models.spells
import se.battlegoo.battlegoose.datamodels.SpellData
import se.battlegoo.battlegoose.models.Battle
import se.battlegoo.battlegoose.models.heroes.Hero
import se.battlegoo.battlegoose.models.heroes.HeroStatsModifier
class AdrenalineShotActiveSpell(
baseSpell: AdrenalineShotSpell,
caster: Hero,
override val data: SpellData.AdrenalineShot
) :
ActiveSpell<AdrenalineShotSpell>(baseSpell, data) {
) : ActiveSpell<AdrenalineShotSpell>(baseSpell, caster, data) {
override fun applyImplementation(battle: Battle, turnsSinceCast: Int) {
battle.hero1.applyStatsModifier(
caster.applyStatsModifier(
HeroStatsModifier {
it.copy(actionPoints = it.actionPoints + 1)
}
......
package se.battlegoo.battlegoose.models.spells
import se.battlegoo.battlegoose.datamodels.SpellData
import se.battlegoo.battlegoose.models.heroes.Hero
class AdrenalineShotSpell : Spell<SpellData.AdrenalineShot>(
"Adrenaline Shot",
......@@ -8,7 +9,10 @@ class AdrenalineShotSpell : Spell<SpellData.AdrenalineShot>(
3,
6
) {
override fun cast(data: SpellData.AdrenalineShot): ActiveSpell<AdrenalineShotSpell> {
return AdrenalineShotActiveSpell(this, data)
override fun cast(
caster: Hero,
data: SpellData.AdrenalineShot
): ActiveSpell<AdrenalineShotSpell> {
return AdrenalineShotActiveSpell(this, caster, data)
}
}
......@@ -3,11 +3,15 @@ package se.battlegoo.battlegoose.models.spells
import se.battlegoo.battlegoose.datamodels.GridVector
import se.battlegoo.battlegoose.datamodels.SpellData
import se.battlegoo.battlegoose.models.Battle
import se.battlegoo.battlegoose.models.heroes.Hero
import kotlin.math.abs
import kotlin.math.floor
class Bird52ActiveSpell(baseSpell: Bird52Spell, override val data: SpellData.Bird52) :
ActiveSpell<Bird52Spell>(baseSpell, data) {
class Bird52ActiveSpell(
baseSpell: Bird52Spell,
caster: Hero,
override val data: SpellData.Bird52
) : ActiveSpell<Bird52Spell>(baseSpell, caster, data) {
override fun applyImplementation(battle: Battle, turnsSinceCast: Int) {
// Hits a number of columns equaling numColumnsToAttack or numColumnsToAttack+1,
......
package se.battlegoo.battlegoose.models.spells
import se.battlegoo.battlegoose.datamodels.SpellData
import se.battlegoo.battlegoose.models.heroes.Hero
class Bird52Spell : Spell<SpellData.Bird52>(
"Bird-52",
......@@ -11,7 +12,7 @@ class Bird52Spell : Spell<SpellData.Bird52>(
val numColumnsToAttack = 2
val attackDamage = 30
override fun cast(data: SpellData.Bird52): ActiveSpell<Bird52Spell> {
return Bird52ActiveSpell(this, data)
override fun cast(caster: Hero, data: SpellData.Bird52): ActiveSpell<Bird52Spell> {
return Bird52ActiveSpell(this, caster, data)
}
}
......@@ -2,13 +2,15 @@ package se.battlegoo.battlegoose.models.spells
import se.battlegoo.battlegoose.datamodels.SpellData
import se.battlegoo.battlegoose.models.Battle
import se.battlegoo.battlegoose.models.heroes.Hero
import se.battlegoo.battlegoose.models.units.UnitModel
import java.lang.IllegalStateException
class EphemeralAllegianceActiveSpell(
baseSpell: EphemeralAllegianceSpell,
caster: Hero,
override val data: SpellData.EphemeralAllegiance
) : ActiveSpell<EphemeralAllegianceSpell>(baseSpell, data) {
) : ActiveSpell<EphemeralAllegianceSpell>(baseSpell, caster, data) {
private lateinit var convertedUnit: UnitModel
......@@ -22,9 +24,9 @@ class EphemeralAllegianceActiveSpell(
private fun convertUnit(battle: Battle) {
convertedUnit = battle.battleMap.getUnit(data.targetPosition)
?: throw IllegalStateException("No unit on target tile ${data.targetPosition}")
if (convertedUnit.allegiance == battle.hero1) {
if (convertedUnit.allegiance == caster) {
throw IllegalStateException("Unit on target tile already belongs to this player")
}
convertedUnit.allegiance = battle.hero1
convertedUnit.allegiance = caster
}
}
package se.battlegoo.battlegoose.models.spells
import se.battlegoo.battlegoose.datamodels.SpellData
import se.battlegoo.battlegoose.models.heroes.Hero
class EphemeralAllegianceSpell : Spell<SpellData.EphemeralAllegiance>(
"Ephemeral Allegiance",
......@@ -8,7 +9,10 @@ class EphemeralAllegianceSpell : Spell<SpellData.EphemeralAllegiance>(
4, // Needs an extra (3+1) for cleanup
5
) {
override fun cast(data: SpellData.EphemeralAllegiance): ActiveSpell<EphemeralAllegianceSpell> {
return EphemeralAllegianceActiveSpell(this, data)
override fun cast(
caster: Hero,
data: SpellData.EphemeralAllegiance
): ActiveSpell<EphemeralAllegianceSpell> {
return EphemeralAllegianceActiveSpell(this, caster, data)
}
}
package se.battlegoo.battlegoose.models.spells
import se.battlegoo.battlegoose.datamodels.SpellData
import se.battlegoo.battlegoose.models.heroes.Hero
abstract class Spell<T : SpellData>(
val title: String,
......@@ -8,5 +9,5 @@ abstract class Spell<T : SpellData>(
val duration: Int,
val cooldown: Int
) {
abstract fun cast(data: T): ActiveSpell<Spell<*>>
abstract fun cast(caster: Hero, data: T): ActiveSpell<out Spell<T>>
}
......@@ -2,7 +2,7 @@ package se.battlegoo.battlegoose.models.units
import se.battlegoo.battlegoose.models.heroes.Hero
class DelinquentDuck(hero: Hero<*>) : UnitModel(
class DelinquentDuck(hero: Hero) : UnitModel(
hero,
UnitStats(80, 40, 0, 3, 1, false), "Delinquent Duck", "[Missing Description]"
)
......@@ -2,7 +2,7 @@ package se.battlegoo.battlegoose.models.units
import se.battlegoo.battlegoose.models.heroes.Hero
class GuardGoose(hero: Hero<*>) : UnitModel(
class GuardGoose(hero: Hero) : UnitModel(
hero,
UnitStats(110, 25, 50, 1, 1, false), "Guard Goose", "[Missing Description]"
)
......@@ -2,7 +2,7 @@ package se.battlegoo.battlegoose.models.units
import se.battlegoo.battlegoose.models.heroes.Hero
class PrivatePenguin(hero: Hero<*>) : UnitModel(
class PrivatePenguin(hero: Hero) : UnitModel(
hero,
UnitStats(100, 30, 10, 2, 1, false), "Private Penguin", "[Missing Description]"
)
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment