Huge overhaul of targeting and team system
This commit is contained in:
parent
3e19060084
commit
f496abee18
@ -10,7 +10,7 @@ buildscript {
|
||||
google()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.5.2'
|
||||
classpath 'com.android.tools.build:gradle:3.5.3'
|
||||
classpath 'com.mobidevelop.robovm:robovm-gradle-plugin:2.3.7'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
|
||||
|
||||
|
119
core/src/me/msoucy/ptures/controller/Engine.kt
Normal file
119
core/src/me/msoucy/ptures/controller/Engine.kt
Normal file
@ -0,0 +1,119 @@
|
||||
package me.msoucy.ptures.controller
|
||||
|
||||
import me.msoucy.ptures.model.Creature
|
||||
import me.msoucy.ptures.model.KnockedOut
|
||||
import me.msoucy.ptures.model.Skill
|
||||
import me.msoucy.ptures.model.Target
|
||||
import me.msoucy.ptures.model.Team
|
||||
import me.msoucy.ptures.view.BattleView
|
||||
import me.msoucy.ptures.view.SkillChoice
|
||||
|
||||
sealed class BattleType(vararg val teams: Team) {
|
||||
init {
|
||||
assert(teams.isNotEmpty())
|
||||
}
|
||||
|
||||
abstract val numGroups: Int
|
||||
}
|
||||
|
||||
sealed class IndividualBattle(vararg teams: Team) : BattleType(*teams) {
|
||||
override val numGroups: Int
|
||||
get() = teams.size
|
||||
}
|
||||
|
||||
class SingleBattle(vararg teams: Team) : IndividualBattle(*teams)
|
||||
class DoubleBattle(vararg teams: Team) : IndividualBattle(*teams)
|
||||
class TripleBattle(vararg teams: Team) : IndividualBattle(*teams)
|
||||
class TeamBattle(override val numGroups: Int, vararg teams: Team) : BattleType(*teams)
|
||||
class RaidBattle(val boss: Creature, vararg teams: Team) : BattleType(*teams) {
|
||||
override val numGroups: Int
|
||||
get() = 2
|
||||
}
|
||||
|
||||
|
||||
class Engine(private val battle: BattleType) {
|
||||
|
||||
private var currentCreature = 0
|
||||
|
||||
private val creatures get() = battle.teams.flatMap { it.activeCreatures }
|
||||
|
||||
val attacker: Creature
|
||||
get() {
|
||||
return creatures[currentCreature].creature
|
||||
}
|
||||
|
||||
private val forcedSkills = mutableMapOf<Creature, Skill>()
|
||||
|
||||
private val activeCreatures
|
||||
get() = creatures
|
||||
.filter { !it.creature.hasStatus<KnockedOut>() }
|
||||
.sortedBy { it.creature.spd }
|
||||
|
||||
fun resolveTurn(view: BattleView) {
|
||||
forcedSkills.clear()
|
||||
// All preconditions
|
||||
for (i in activeCreatures.indices) {
|
||||
val creature = creatures[i]
|
||||
for (status in creature.creature.statuses) {
|
||||
status.onTurnStart(this, creature.creature)
|
||||
}
|
||||
}
|
||||
// Get the moves each creature will use this turn
|
||||
val moves = activeCreatures.indices.map { i ->
|
||||
val forcedSkill = forcedSkills[creatures[i].creature]
|
||||
if (forcedSkill != null) {
|
||||
SkillChoice(forcedSkill, creatures[nextOpponent(i)].creature)
|
||||
} else {
|
||||
creatures[i].chooseSkill(activeCreatures.map { it.creature })
|
||||
}
|
||||
}
|
||||
// Resolve each move
|
||||
for (i in activeCreatures.indices) {
|
||||
// Resolve move
|
||||
val (skill, target) = moves[i]
|
||||
currentCreature = i
|
||||
for (step in skill.damageSteps) {
|
||||
for (targetCreature in getTargetList(step.target, target)) {
|
||||
if (attacker.hits(targetCreature, step)) {
|
||||
targetCreature.apply(step, attacker)
|
||||
step.applyStatus(targetCreature)
|
||||
}
|
||||
}
|
||||
}
|
||||
for (step in skill.postSteps) {
|
||||
for (targetCreature in getTargetList(step.target, target)) {
|
||||
step.apply(targetCreature)
|
||||
}
|
||||
}
|
||||
}
|
||||
// All post conditions
|
||||
for (creatureView in activeCreatures) {
|
||||
val creature = creatureView.creature
|
||||
for (status in creature.statuses) {
|
||||
status.onTurnEnd(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getTargetList(target: Target, selected: Creature): List<Creature> {
|
||||
return when (target) {
|
||||
Target.Self -> listOf(attacker)
|
||||
Target.Selected -> listOf(selected)
|
||||
Target.Others -> creatures.filter { it.creature != attacker }.map { it.creature }
|
||||
Target.Opponents -> creatures.filter { it.playerId != creatures[currentCreature].playerId }.map { it.creature }
|
||||
Target.All -> creatures.map { it.creature }
|
||||
}
|
||||
}
|
||||
|
||||
private fun nextOpponent(idx: Int): Int {
|
||||
var nextIdx = idx + 1
|
||||
while (nextIdx != idx) {
|
||||
if (creatures[nextIdx].playerId != creatures[idx].playerId) {
|
||||
return nextIdx
|
||||
}
|
||||
nextIdx = (nextIdx + 1) % creatures.size
|
||||
}
|
||||
// There are no opponents... so use the "none" index
|
||||
return -1
|
||||
}
|
||||
}
|
@ -1,91 +0,0 @@
|
||||
package me.msoucy.ptures.model
|
||||
|
||||
import me.msoucy.ptures.view.BattleView
|
||||
|
||||
class Engine(private vararg val creatures : Pair<Creature, Int>) {
|
||||
init {
|
||||
assert(creatures.isNotEmpty())
|
||||
}
|
||||
|
||||
private var currentCreature = 0
|
||||
|
||||
val attacker : Creature get() {
|
||||
return creatures[currentCreature].first
|
||||
}
|
||||
|
||||
val forcedSkills = mutableMapOf<Creature, Skill>()
|
||||
|
||||
val activeCreatures get() = creatures.withIndex()
|
||||
.filter { (_, c) -> !c.first.hasStatus<KnockedOut>() }
|
||||
.sortedBy { (_, c) -> c.first.spd }
|
||||
.map { (i, _) -> i}
|
||||
|
||||
fun resolveTurn(view : BattleView) {
|
||||
forcedSkills.clear()
|
||||
// All preconditions
|
||||
for (i in activeCreatures) {
|
||||
val creature = creatures[i]
|
||||
for (status in creature.first.statuses) {
|
||||
status.onTurnStart(this, creature.first)
|
||||
}
|
||||
}
|
||||
// Get the moves each creature will use this turn
|
||||
val moves = activeCreatures.map { i ->
|
||||
if (creatures[i].first in forcedSkills) {
|
||||
Pair(forcedSkills[creatures[i].first], nextOpponent(i))
|
||||
} else {
|
||||
TODO("Fill in view here")
|
||||
}
|
||||
}
|
||||
// Resolve each move
|
||||
for (i in activeCreatures) {
|
||||
// Resolve move
|
||||
val (skill, target) = moves[i]
|
||||
currentCreature = i
|
||||
for (step in skill.damageSteps) {
|
||||
for (t in getTargetList(step.target, target)) {
|
||||
val (targetCreature, _) = creatures[t]
|
||||
if (attacker.hits(targetCreature, step)) {
|
||||
targetCreature.apply(step, attacker)
|
||||
step.applyStatus(targetCreature)
|
||||
}
|
||||
}
|
||||
}
|
||||
for(step in skill.postSteps) {
|
||||
for (t in getTargetList(step.target, target)) {
|
||||
val (targetCreature, _) = creatures[t]
|
||||
step.apply(targetCreature)
|
||||
}
|
||||
}
|
||||
}
|
||||
// All post conditions
|
||||
for (i in activeCreatures) {
|
||||
val creature = creatures[i]
|
||||
for (status in creature.first.statuses) {
|
||||
status.onTurnEnd(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getTargetList(target : Target, selected : Int) : List<Int> {
|
||||
return when(target) {
|
||||
Target.Self -> listOf(currentCreature)
|
||||
Target.Selected -> if (selected == -1) { listOf() } else { listOf(selected) }
|
||||
Target.Others -> creatures.indices.filter { it != currentCreature }
|
||||
Target.Opponents -> creatures.indices.filter { creatures[it].second != creatures[currentCreature].second }
|
||||
Target.All -> creatures.indices.toList()
|
||||
}
|
||||
}
|
||||
|
||||
private fun nextOpponent(idx : Int) : Int {
|
||||
var nextIdx = idx + 1
|
||||
while (nextIdx != idx) {
|
||||
if (creatures[nextIdx].second != creatures[idx].second) {
|
||||
return nextIdx
|
||||
}
|
||||
nextIdx = (nextIdx + 1) % creatures.size
|
||||
}
|
||||
// There are no opponents... so use the "none" index
|
||||
return -1
|
||||
}
|
||||
}
|
@ -22,14 +22,14 @@ enum class Attribute {
|
||||
Wood
|
||||
}
|
||||
|
||||
class Damage(val power : Int, val attribute : Attribute = Attribute.Neutral) {
|
||||
class Damage(val power: Int, val attribute: Attribute = Attribute.Neutral) {
|
||||
var target = Target.Selected
|
||||
var accuracy = 100
|
||||
|
||||
var status : () -> Status? = {null}
|
||||
var status: () -> Status? = { null }
|
||||
var statusChance = 0
|
||||
|
||||
fun applyStatus(creature : Creature) {
|
||||
fun applyStatus(creature: Creature) {
|
||||
val appStatus = status()
|
||||
if (appStatus != null && random(100) < statusChance) {
|
||||
creature.addStatus(appStatus)
|
||||
@ -37,34 +37,42 @@ class Damage(val power : Int, val attribute : Attribute = Attribute.Neutral) {
|
||||
}
|
||||
}
|
||||
|
||||
class StatusApplier(val target : Target, val apply : (Creature) -> Unit)
|
||||
class StatusApplier(val target: Target, val apply: (Creature) -> Unit)
|
||||
|
||||
@SkillMarker
|
||||
sealed class Skill(open val name : String, val attribute : Attribute) {
|
||||
open class Skill(open val name: String, val attribute: Attribute) {
|
||||
val damageSteps = mutableListOf<Damage>()
|
||||
val postSteps = mutableListOf<StatusApplier>()
|
||||
|
||||
fun damage(power : Int, block : Damage.() -> Unit = {}) {
|
||||
fun damage(power: Int, block: Damage.() -> Unit = {}) {
|
||||
val d = Damage(power, attribute)
|
||||
d.block()
|
||||
damageSteps.add(d)
|
||||
}
|
||||
|
||||
fun addStatus(status : Status, target : Target = Target.Selected) {
|
||||
postSteps.add (StatusApplier(target) { c -> c.addStatus(status) })
|
||||
fun addStatus(status: Status, target: Target = Target.Selected) {
|
||||
postSteps.add(StatusApplier(target) { c -> c.addStatus(status) })
|
||||
}
|
||||
|
||||
fun removeStatus(status : Status, target : Target = Target.Selected) {
|
||||
postSteps.add (StatusApplier(target) { c -> c.removeStatus(status) })
|
||||
fun removeStatus(status: Status, target: Target = Target.Selected) {
|
||||
postSteps.add(StatusApplier(target) { c -> c.removeStatus(status) })
|
||||
}
|
||||
|
||||
// Assume that the first damage step is the one that provides the target
|
||||
val target: Target
|
||||
get() = if (damageSteps.isNotEmpty()) {
|
||||
damageSteps[0].target
|
||||
} else {
|
||||
Target.Self
|
||||
}
|
||||
}
|
||||
|
||||
class AdvancedSkill(name : String, attribute : Attribute) : Skill(name, attribute) {
|
||||
override val name : String get() = super.name + "+"
|
||||
val baseName : String get() = super.name
|
||||
class AdvancedSkill(name: String, attribute: Attribute) : Skill(name, attribute) {
|
||||
override val name: String get() = super.name + "+"
|
||||
val baseName: String get() = super.name
|
||||
}
|
||||
|
||||
fun skill(name : String, attribute : Attribute = Attribute.Neutral, block : Skill.() -> Unit) : Skill {
|
||||
fun skill(name: String, attribute: Attribute = Attribute.Neutral, block: Skill.() -> Unit): Skill {
|
||||
val ret = Skill(name, attribute)
|
||||
ret.block()
|
||||
return ret
|
||||
|
@ -1,5 +1,7 @@
|
||||
package me.msoucy.ptures.model
|
||||
|
||||
import me.msoucy.ptures.controller.Engine
|
||||
|
||||
sealed class Status {
|
||||
|
||||
open fun onTurnStart(engine : Engine, creature : Creature) {
|
||||
|
11
core/src/me/msoucy/ptures/model/Team.kt
Normal file
11
core/src/me/msoucy/ptures/model/Team.kt
Normal file
@ -0,0 +1,11 @@
|
||||
package me.msoucy.ptures.model
|
||||
|
||||
import me.msoucy.ptures.view.PlayerView
|
||||
|
||||
class Team(var view : PlayerView) {
|
||||
|
||||
var creatures = mutableListOf<Creature>()
|
||||
var selectedCreatures = mutableListOf(0)
|
||||
|
||||
val activeCreatures get() = selectedCreatures.map { view.creatureViewFor(creatures[it]) }
|
||||
}
|
@ -4,21 +4,21 @@ import me.msoucy.ptures.model.Creature
|
||||
import me.msoucy.ptures.model.Skill
|
||||
import me.msoucy.ptures.model.VisibleStatus
|
||||
|
||||
class SkillViewText(val skill : Skill) : SkillView() {
|
||||
class SkillViewText(skill : Skill) : SkillView(skill) {
|
||||
override fun display() {
|
||||
println(skill.name)
|
||||
}
|
||||
|
||||
override fun displayEnumerated(idx: Int) {
|
||||
println("${idx}: ${skill.name}")
|
||||
println("${idx+1}: ${skill.name}")
|
||||
}
|
||||
}
|
||||
|
||||
class CreatureViewText(val creature : Creature) : CreatureView() {
|
||||
class CreatureViewText(playerId : Int, creature : Creature) : CreatureView(playerId, creature) {
|
||||
|
||||
private val skillViews = creature.skills.map { SkillViewText(it) }
|
||||
|
||||
override val skillChoice : Skill get() {
|
||||
private fun chooseSkillName() : Skill {
|
||||
println("Skills:")
|
||||
println("=======")
|
||||
skillViews.forEachIndexed { index, skillView ->
|
||||
@ -33,10 +33,21 @@ class CreatureViewText(val creature : Creature) : CreatureView() {
|
||||
idx = tmpIdx
|
||||
}
|
||||
}
|
||||
|
||||
return creature.skills[idx]
|
||||
}
|
||||
|
||||
private fun chooseTarget(skill : Skill, possibleTargets : List<Creature>) : Creature {
|
||||
return creature
|
||||
}
|
||||
|
||||
override fun chooseSkill(possibleTargets : List<Creature>) : SkillChoice {
|
||||
|
||||
val skill = chooseSkillName()
|
||||
val target = chooseTarget(skill, possibleTargets)
|
||||
|
||||
return SkillChoice(skill, target)
|
||||
}
|
||||
|
||||
override fun displayName() {
|
||||
println(creature.name)
|
||||
}
|
||||
@ -53,3 +64,7 @@ class CreatureViewText(val creature : Creature) : CreatureView() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class PlayerViewText(playerId : Int) : PlayerView(playerId) {
|
||||
override fun creatureViewFor(creature: Creature) = CreatureViewText(playerId, creature)
|
||||
}
|
@ -1,21 +1,27 @@
|
||||
package me.msoucy.ptures.view
|
||||
|
||||
import me.msoucy.ptures.model.Creature
|
||||
import me.msoucy.ptures.model.Skill
|
||||
|
||||
interface SkillView {
|
||||
fun display()
|
||||
fun displayEnumerated(idx : Int)
|
||||
data class SkillChoice (val skill : Skill, val target : Creature)
|
||||
|
||||
abstract class SkillView(val skill : Skill) {
|
||||
abstract fun display()
|
||||
abstract fun displayEnumerated(idx : Int)
|
||||
}
|
||||
|
||||
interface CreatureView {
|
||||
abstract class CreatureView(val playerId : Int, val creature: Creature) {
|
||||
|
||||
val skillChoice : Skill
|
||||
abstract fun chooseSkill(possibleTargets : List<Creature>) : SkillChoice
|
||||
|
||||
fun displayName()
|
||||
fun displaySkills()
|
||||
fun displayStatuses()
|
||||
abstract fun displayName()
|
||||
abstract fun displaySkills()
|
||||
abstract fun displayStatuses()
|
||||
}
|
||||
|
||||
interface BattleView {
|
||||
//
|
||||
abstract class BattleView {
|
||||
}
|
||||
|
||||
abstract class PlayerView(val playerId : Int) {
|
||||
abstract fun creatureViewFor(creature: Creature) : CreatureView
|
||||
}
|
Loading…
Reference in New Issue
Block a user