Skip to content

Instantly share code, notes, and snippets.

@frederikaalund
Created June 8, 2019 10:30
Show Gist options
  • Save frederikaalund/a31d201c1e351d03612aa8761cc42470 to your computer and use it in GitHub Desktop.
Save frederikaalund/a31d201c1e351d03612aa8761cc42470 to your computer and use it in GitHub Desktop.
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