Huge overhaul of targeting and team system
This commit is contained in:
parent
3e19060084
commit
f496abee18
@ -10,7 +10,7 @@ buildscript {
|
|||||||
google()
|
google()
|
||||||
}
|
}
|
||||||
dependencies {
|
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 'com.mobidevelop.robovm:robovm-gradle-plugin:2.3.7'
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
|
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
|
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 target = Target.Selected
|
||||||
var accuracy = 100
|
var accuracy = 100
|
||||||
|
|
||||||
var status : () -> Status? = {null}
|
var status: () -> Status? = { null }
|
||||||
var statusChance = 0
|
var statusChance = 0
|
||||||
|
|
||||||
fun applyStatus(creature : Creature) {
|
fun applyStatus(creature: Creature) {
|
||||||
val appStatus = status()
|
val appStatus = status()
|
||||||
if (appStatus != null && random(100) < statusChance) {
|
if (appStatus != null && random(100) < statusChance) {
|
||||||
creature.addStatus(appStatus)
|
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
|
@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 damageSteps = mutableListOf<Damage>()
|
||||||
val postSteps = mutableListOf<StatusApplier>()
|
val postSteps = mutableListOf<StatusApplier>()
|
||||||
|
|
||||||
fun damage(power : Int, block : Damage.() -> Unit = {}) {
|
fun damage(power: Int, block: Damage.() -> Unit = {}) {
|
||||||
val d = Damage(power, attribute)
|
val d = Damage(power, attribute)
|
||||||
d.block()
|
d.block()
|
||||||
damageSteps.add(d)
|
damageSteps.add(d)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addStatus(status : Status, target : Target = Target.Selected) {
|
fun addStatus(status: Status, target: Target = Target.Selected) {
|
||||||
postSteps.add (StatusApplier(target) { c -> c.addStatus(status) })
|
postSteps.add(StatusApplier(target) { c -> c.addStatus(status) })
|
||||||
}
|
}
|
||||||
|
|
||||||
fun removeStatus(status : Status, target : Target = Target.Selected) {
|
fun removeStatus(status: Status, target: Target = Target.Selected) {
|
||||||
postSteps.add (StatusApplier(target) { c -> c.removeStatus(status) })
|
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) {
|
class AdvancedSkill(name: String, attribute: Attribute) : Skill(name, attribute) {
|
||||||
override val name : String get() = super.name + "+"
|
override val name: String get() = super.name + "+"
|
||||||
val baseName : 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)
|
val ret = Skill(name, attribute)
|
||||||
ret.block()
|
ret.block()
|
||||||
return ret
|
return ret
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package me.msoucy.ptures.model
|
package me.msoucy.ptures.model
|
||||||
|
|
||||||
|
import me.msoucy.ptures.controller.Engine
|
||||||
|
|
||||||
sealed class Status {
|
sealed class Status {
|
||||||
|
|
||||||
open fun onTurnStart(engine : Engine, creature : Creature) {
|
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.Skill
|
||||||
import me.msoucy.ptures.model.VisibleStatus
|
import me.msoucy.ptures.model.VisibleStatus
|
||||||
|
|
||||||
class SkillViewText(val skill : Skill) : SkillView() {
|
class SkillViewText(skill : Skill) : SkillView(skill) {
|
||||||
override fun display() {
|
override fun display() {
|
||||||
println(skill.name)
|
println(skill.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun displayEnumerated(idx: Int) {
|
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) }
|
private val skillViews = creature.skills.map { SkillViewText(it) }
|
||||||
|
|
||||||
override val skillChoice : Skill get() {
|
private fun chooseSkillName() : Skill {
|
||||||
println("Skills:")
|
println("Skills:")
|
||||||
println("=======")
|
println("=======")
|
||||||
skillViews.forEachIndexed { index, skillView ->
|
skillViews.forEachIndexed { index, skillView ->
|
||||||
@ -33,10 +33,21 @@ class CreatureViewText(val creature : Creature) : CreatureView() {
|
|||||||
idx = tmpIdx
|
idx = tmpIdx
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return creature.skills[idx]
|
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() {
|
override fun displayName() {
|
||||||
println(creature.name)
|
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
|
package me.msoucy.ptures.view
|
||||||
|
|
||||||
|
import me.msoucy.ptures.model.Creature
|
||||||
import me.msoucy.ptures.model.Skill
|
import me.msoucy.ptures.model.Skill
|
||||||
|
|
||||||
interface SkillView {
|
data class SkillChoice (val skill : Skill, val target : Creature)
|
||||||
fun display()
|
|
||||||
fun displayEnumerated(idx : Int)
|
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()
|
abstract fun displayName()
|
||||||
fun displaySkills()
|
abstract fun displaySkills()
|
||||||
fun displayStatuses()
|
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