Created
June 8, 2019 10:30
-
-
Save frederikaalund/a31d201c1e351d03612aa8761cc42470 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package Character | |
import ClosureEvents | |
import ArchOnePerPlayer | |
import ArchCallback | |
import initlater Arena | |
public class Character | |
use AlwaysOnePerPlayer | |
static let onDeath = new LinkedList<MiddlewareBinary<Character, unit>> | |
static let onPick = new LinkedList<MiddlewareUnary<Character>> | |
static let onResurrect = new LinkedList<MiddlewareUnary<Character>> | |
static let onLevelUp = new LinkedList<MiddlewareUnary<Character>> | |
private CharacterUnit cu | |
private construct(player p) | |
this.p = p | |
this.cu = new CharacterUnit() | |
ondestroy | |
destroy this.cu | |
override static protected function initForAll() | |
for i = 0 to bj_MAX_PLAYER_SLOTS - 1 | |
instances[i] = new Character(players[i]) | |
/** May return null */ | |
static function getUnitFor(player p) returns unit | |
return getFor(p).getUnit() | |
static function existsUnitFor(player p) returns boolean | |
return null != getFor(p).getUnit() | |
/** Takes ownership of u */ | |
static function setUnitFor(player p, unit u) | |
let instance = getFor(p) | |
instance.cu.set(u) | |
onPick.call(instance) | |
/** May return null */ | |
function getUnit() returns unit | |
return this.cu.get() | |
function suspendXp(boolean suspended) | |
this.cu.suspendXp(suspended) | |
static function suspendXpForAll(boolean flag) | |
for i = 0 to bj_MAX_PLAYER_SLOTS - 1 | |
instances[i].suspendXp(flag) | |
/* Helper classes/functions */ | |
/** Unit wrapper that preserves state (e.g., XP) between unit instances. | |
* | |
* === Invariants === | |
* | |
* = Exclusivity = | |
* Either this.u is non-null or this.state is non-null but never both. | |
* One of this.u or this.state is always non-null. | |
* Think of the binary XOR operation. | |
*/ | |
class CharacterUnit | |
private unit u = null | |
private CharacterState state = new CharacterState(0, false) | |
ondestroy | |
if null != this.state | |
destroy this.state | |
else | |
this.u.remove() | |
/** May return null (if u is not set) */ | |
function get() returns unit | |
return this.u | |
/** Takes ownership of u (may be null) */ | |
function set(unit u) | |
// Setting to null is the same as calling remove() | |
if null == u | |
this.remove() | |
return | |
if null == this.state | |
// There is no state, so temporarily set one from this.u. | |
// We will use this state to reconfigure the given u. | |
this.state = new CharacterState(this.u) | |
// Due to exclusivity, we can infer that this.u must be | |
// set. Therefore, we remove it. | |
this.u.remove() | |
// Set u and apply the current state | |
this.u = u | |
this.u.setState(this.state) | |
// Now that u is set, the state must be unset (exclusivity) | |
destroy this.state | |
this.state = null | |
function remove() | |
// If u is already unset, there is nothing more to do | |
if null == this.u | |
return | |
// Save u's state | |
this.state = new CharacterState(this.u) | |
// Now that state is set, u must be unset (exclusivity) | |
this.u = null | |
function suspendXp(boolean suspended) | |
if null != this.state | |
this.state.xpSuspended = suspended | |
else | |
this.u.suspendXp(suspended) | |
class CharacterState | |
protected int xp | |
protected bool xpSuspended | |
construct(int xp, bool xpSuspended) | |
this.xp = xp | |
this.xpSuspended = xpSuspended | |
/** Takes u by reference */ | |
construct(unit u) | |
this.xp = u.getXp() | |
this.xpSuspended = u.isSuspendedXp() | |
/** Takes state by reference */ | |
function unit.setState(CharacterState state) | |
this.setXp(state.xp, false) | |
this.suspendXp(state.xpSuspended) | |
/* Init */ | |
init | |
Character.initForAll() | |
EventListener.add(EVENT_PLAYER_UNIT_DEATH) -> | |
let u = GetTriggerUnit() | |
let killingUnit = GetKillingUnit() | |
let char = Character.getFor(u.getOwner()) | |
if u == char.getUnit() | |
Character.onDeath.call(char, killingUnit) | |
EventListener.add(EVENT_PLAYER_HERO_LEVEL) -> | |
let u = GetTriggerUnit() | |
let char = Character.getFor(u.getOwner()) | |
if u == char.getUnit() | |
Character.onLevelUp.call(char) | |
EventListener.add(EVENT_PLAYER_HERO_REVIVE_FINISH) -> | |
let u = GetTriggerUnit() | |
let char = Character.getFor(u.getOwner()) | |
if u == char.getUnit() | |
Character.onLevelUp.call(char) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment