package event

Package event is where a map script says what should happen when: register a function for an event and the game calls it at the right step. Registration goes in the script's main function (or in an init function); the game runs main once, before the map starts.

Every On... function returns a Handle. Ignore it for a hook that stays for the whole game; keep it to disable, enable again or remove the hook later (even from inside the hook itself):

var h event.Handle
h = event.OnUnitDied(func(u game.Unit) {
	game.Print("first death:", u.ID())
	h.Remove() // a one-shot
})

A hook that is disabled or removed is not called again, not even for the events of the step it was switched off in, and the engine stops sending its kind of event when no enabled hook is left for it, so a hook nobody needs costs nothing. Hooks of one kind are called in the order they were registered, events in the order they happened. The state of every hook lives in the script's memory, so it is saved with the game (checkpoints, saves, replays).

import "w4/event"

Constants and variables

const StepsPerSecond = 30

Steps per second of the simulation.

Types

AbilityCastEvent

type AbilityCastEvent struct {
	Caster game.Unit
	// Target is the unit aimed at; its ID is -1 for a cast with no unit target.
	Target game.Unit
	// HasPoint says the cast was aimed at a spot (X, Y), in world units from the middle of the map.
	HasPoint bool
	X, Y     float64
	// Ability is the id of the ability's definition, as the editor shows it.
	Ability string
}

AbilityCastEvent is a cast that went through (cost paid, cooldown started).

AbilityHitEvent

type AbilityHitEvent struct {
	Caster, Target game.Unit
	// Ability is the id of the ability's definition, as the editor shows it.
	Ability string
}

AbilityHitEvent is an ability's effects reaching one unit.

BlockedEvent

type BlockedEvent struct {
	Target    game.Unit
	Prevented int
}

BlockedEvent is part of a blow being blocked.

CastInterruptedEvent

type CastInterruptedEvent struct {
	Unit game.Unit
	// Ability is the id of the ability's definition, as the editor shows it.
	Ability string
}

CastInterruptedEvent is a cast cut short while it was winding up.

DamageEvent

type DamageEvent struct {
	Target game.Unit
	// Source is the unit that struck; its ID is -1 when nobody did (a script's or a cheat's damage).
	Source game.Unit
	// Total is what the target really lost (never more than it had); Physical, Magic and True are
	// the parts after armour and magic resist, their sum.
	Total, Physical, Magic, True int
	// Crit says the blow was a critical strike (a spell never is).
	Crit bool
}

DamageEvent is health taken off a unit by one blow or spell.

GoldEvent

type GoldEvent struct {
	Player player.ID
	Amount int
	// HasPoint says the gold came from a place, (X, Y) in world units from the middle of the map.
	HasPoint bool
	X, Y     float64
}

GoldEvent is gold received by a player.

Handle

type Handle struct {
	// contains filtered or unexported fields
}

Handle names one hook: what every On... function returns. The zero Handle names nothing and every method of it does nothing. A Handle is a small number, never reused, so a stale one can not touch another hook.

OnAbilityCast

func OnAbilityCast(fn func(AbilityCastEvent)) Handle

OnAbilityCast calls fn when a cast goes through.

event.OnAbilityCast(func(e event.AbilityCastEvent) { game.Print("cast", e.Ability) })

OnAbilityHit

func OnAbilityHit(fn func(AbilityHitEvent)) Handle

OnAbilityHit calls fn once for each unit the effects of a cast reach (damage, heal, stun, slow from the ability's effects list), just before the events of the effects themselves (OnDamage, OnHealed, OnStunned). Abilities with no effects never call it.

event.OnAbilityHit(func(e event.AbilityHitEvent) { game.Print(e.Target.ID(), "was hit by", e.Ability) })

OnBlocked

func OnBlocked(fn func(BlockedEvent)) Handle

OnBlocked calls fn when part of a blow is blocked. Not called today (the rules have no block).

event.OnBlocked(func(e event.BlockedEvent) { game.Print("blocked", e.Prevented) })

OnBuilt

func OnBuilt(fn func(game.Unit)) Handle

OnBuilt calls fn with a building whose construction finished.

event.OnBuilt(func(u game.Unit) { game.Print("built", u.ID()) })

OnCastInterrupted

func OnCastInterrupted(fn func(CastInterruptedEvent)) Handle

OnCastInterrupted calls fn when an ability with a cast time is cut short because its caster died or was stunned before the time was over. The cost stays paid and the effects never land.

event.OnCastInterrupted(func(e event.CastInterruptedEvent) { game.Print(e.Unit.ID(), "lost its cast") })

OnDamage

func OnDamage(fn func(DamageEvent)) Handle

OnDamage calls fn for every blow that took health off a unit: one call per blow, with the parts it was made of. OnUnitDamaged is the short form with the total only.

event.OnDamage(func(e event.DamageEvent) { game.Printf("%d magic of %d", e.Magic, e.Total) })

OnEnter

func OnEnter(region game.Region, fn func(game.Unit)) Handle

OnEnter calls fn with each unit that walks (or is put) into the region. A unit already inside when the region was made does not count. Dead units do not enter.

OnGoldGained

func OnGoldGained(fn func(GoldEvent)) Handle

OnGoldGained calls fn when a player receives gold.

event.OnGoldGained(func(e event.GoldEvent) { game.Print("gold", e.Amount) })

OnHealed

func OnHealed(fn func(HealedEvent)) Handle

OnHealed calls fn when health is restored by the rules. Not called today: a heal from a script (Unit.Heal) sets the stat and is reported by OnStat.

event.OnHealed(func(e event.HealedEvent) { game.Print("healed", e.Amount) })

OnHit

func OnHit(fn func(HitEvent)) Handle

OnHit calls fn when an attack lands, just before the OnDamage of the same blow.

event.OnHit(func(e event.HitEvent) { if e.Crit { game.Print("critical!") } })

OnImmune

func OnImmune(fn func(game.Unit)) Handle

OnImmune calls fn with a unit that ignored a blow or spell because it is immune. Not called today (the rules have no immunity yet).

event.OnImmune(func(u game.Unit) { game.Print(u, "is immune") })

OnItemBought

func OnItemBought(fn func(ItemEvent)) Handle

OnItemBought calls fn when a unit buys an item at a shop.

event.OnItemBought(func(e event.ItemEvent) { game.Print(e.Unit.ID(), "bought", e.Item) })

OnItemDropped

func OnItemDropped(fn func(ItemEvent)) Handle

OnItemDropped calls fn when a unit drops an item or dies carrying one; X and Y say where it fell, in world units from the middle of the map.

event.OnItemDropped(func(e event.ItemEvent) { game.Print(e.Unit.ID(), "dropped", e.Item, "at", e.X, e.Y) })

OnItemPickedUp

func OnItemPickedUp(fn func(ItemEvent)) Handle

OnItemPickedUp calls fn when a unit picks an item up from the ground.

event.OnItemPickedUp(func(e event.ItemEvent) { game.Print(e.Unit.ID(), "picked up", e.Item) })

OnItemSold

func OnItemSold(fn func(ItemEvent)) Handle

OnItemSold calls fn when a unit sells an item.

event.OnItemSold(func(e event.ItemEvent) { game.Print(e.Unit.ID(), "sold", e.Item) })

OnItemUsed

func OnItemUsed(fn func(ItemEvent)) Handle

OnItemUsed calls fn when a unit uses the active ability of an item (a use the game accepted: not on cooldown, with the mana and a valid target).

event.OnItemUsed(func(e event.ItemEvent) { game.Print(e.Unit.ID(), "used slot", e.Slot) })

OnLeave

func OnLeave(region game.Region, fn func(game.Unit)) Handle

OnLeave calls fn with each unit that leaves the region. A unit that dies inside leaves it (it is not alive in the handler).

OnLevelUp

func OnLevelUp(fn func(game.Unit)) Handle

OnLevelUp calls fn with a hero that went up a level.

event.OnLevelUp(func(u game.Unit) { game.Print("level up", u.ID()) })

OnLoaded

func OnLoaded(fn func(TransportEvent)) Handle

OnLoaded calls fn when a unit climbs into a transport.

event.OnLoaded(func(e event.TransportEvent) { game.Print("boarded", e.Transport.ID()) })

OnManaChanged

func OnManaChanged(fn func(ManaChangedEvent)) Handle

OnManaChanged calls fn when a unit's mana changes by Delta (a cast paying its cost is negative).

event.OnManaChanged(func(e event.ManaChangedEvent) { game.Print("mana", e.Delta) })

OnMapInit

func OnMapInit(fn func()) Handle

OnMapInit calls fn once when the game starts.

OnMiss

func OnMiss(fn func(MissEvent)) Handle

OnMiss calls fn when an attack misses. The rules have no miss chance yet, so it is not called today; a map that listens works unchanged when it arrives.

event.OnMiss(func(e event.MissEvent) { game.Print("missed") })

OnPaused

func OnPaused(fn func()) Handle

OnPaused calls fn when the host pauses the game. (The game does not step while it is paused; the hook runs on the first step after the host resumes, before OnResumed.)

event.OnPaused(func() { game.Print("paused") })

OnPlayerJoined

func OnPlayerJoined(fn func(PlayerEvent)) Handle

OnPlayerJoined calls fn when a player is seated in the running game (late join included).

event.OnPlayerJoined(func(e event.PlayerEvent) { game.Print(e.Player, "joined team", e.Team) })

OnPlayerLeft

func OnPlayerLeft(fn func(PlayerEvent)) Handle

OnPlayerLeft calls fn when a seat is marked abandoned because its player left. Its units stay.

event.OnPlayerLeft(func(e event.PlayerEvent) { game.Print(e.Player, "left") })

OnResumed

func OnResumed(fn func()) Handle

OnResumed calls fn when the host resumes a paused game.

event.OnResumed(func() { game.Print("resumed") })

OnSeatChanged

func OnSeatChanged(fn func(SeatEvent)) Handle

OnSeatChanged calls fn when a seat opens, is taken or is abandoned (after OnPlayerJoined or OnPlayerLeft of the same change).

event.OnSeatChanged(func(e event.SeatEvent) { game.Print(e.Player, "seat is now", int(e.State)) })

OnShot

func OnShot(fn func(ShotEvent)) Handle

OnShot calls fn when a ranged attacker lets a shot go; the matching OnHit comes when it lands.

event.OnShot(func(e event.ShotEvent) { game.Print("shot from", e.Attacker.ID()) })

OnSpawned

func OnSpawned(fn func(game.Unit)) Handle

OnSpawned calls fn with every new unit (a script's spawn, a trained unit, a placed building).

event.OnSpawned(func(u game.Unit) { game.Print("new unit", u.ID()) })

OnStat

func OnStat(fn func(StatEvent)) Handle

OnStat calls fn when a stat of a unit is set to a value by a script's heal, a mana set, a cast paying its mana or a hero's level set.

event.OnStat(func(e event.StatEvent) { if e.Stat == event.StatLevel { game.Print("level", e.Value) } })

OnStunned

func OnStunned(fn func(StunnedEvent)) Handle

OnStunned calls fn when a unit is stunned. Not called today (the rules have no stun yet).

event.OnStunned(func(e event.StunnedEvent) { game.Print("stunned for", e.Seconds) })

OnTrained

func OnTrained(fn func(TrainedEvent)) Handle

OnTrained calls fn when a building finishes training a unit (OnSpawned for the same unit comes just before).

event.OnTrained(func(e event.TrainedEvent) { game.Print("ready", e.Unit.ID()) })

OnUnitDamaged

func OnUnitDamaged(fn func(unit, attacker game.Unit, amount float64)) Handle

OnUnitDamaged calls fn whenever a unit loses health: with the unit, who struck it and how much health it lost (a blow that was more than it had left counts what it had). The attacker is a unit that is not alive (its ID is -1) when nobody struck, as with Unit.Damage from a script. A unit that dies of the blow is heard here first and then in OnUnitDied. OnDamage tells more (the parts of the blow, whether it was critical).

OnUnitDied

func OnUnitDied(fn func(game.Unit)) Handle

OnUnitDied calls fn with every unit that dies.

OnUnitRevealed

func OnUnitRevealed(fn func(RevealEvent)) Handle

OnUnitRevealed calls fn when a unit becomes visible to enemies because it attacked or cast from fog or brush, for a short time. A refresh while still shown is not a new event.

event.OnUnitRevealed(func(e event.RevealEvent) { game.Print(e.Unit, "was revealed") })

OnUnloaded

func OnUnloaded(fn func(TransportEvent)) Handle

OnUnloaded calls fn when a unit steps out of a transport.

event.OnUnloaded(func(e event.TransportEvent) { game.Print("landed", e.Unit.ID()) })

OnUpgraded

func OnUpgraded(fn func(game.Unit)) Handle

OnUpgraded calls fn with a building that finished an upgrade.

event.OnUpgraded(func(u game.Unit) { game.Print("upgraded", u.ID()) })

OnUtilityRecharged

func OnUtilityRecharged(fn func(UtilityEvent)) Handle

OnUtilityRecharged calls fn when a charge of a unit's slot comes back.

event.OnUtilityRecharged(func(e event.UtilityEvent) { game.Print("ready:", e.Charges) })

OnUtilitySwapped

func OnUtilitySwapped(fn func(UtilityEvent)) Handle

OnUtilitySwapped calls fn when a unit swaps the tool in its slot near its base; the new tool starts full.

event.OnUtilitySwapped(func(e event.UtilityEvent) { game.Print("now holds tool", int(e.Tool)) })

OnUtilityUsed

func OnUtilityUsed(fn func(UtilityEvent)) Handle

OnUtilityUsed calls fn when a unit spends a charge of its slot (a ward placed, a sweep started).

event.OnUtilityUsed(func(e event.UtilityEvent) { game.Print(e.Charges, "charges left") })

OnWardDestroyed

func OnWardDestroyed(fn func(WardEvent)) Handle

OnWardDestroyed calls fn when a ward is killed by blows.

event.OnWardDestroyed(func(e event.WardEvent) { game.Print("ward killed", e.Ward) })

OnWardExpired

func OnWardExpired(fn func(WardEvent)) Handle

OnWardExpired calls fn when a ward runs out of time or is pushed out by a newer one.

event.OnWardExpired(func(e event.WardEvent) { game.Print("ward gone", e.Ward) })

OnWardPlaced

func OnWardPlaced(fn func(WardEvent)) Handle

OnWardPlaced calls fn when a ward is placed.

event.OnWardPlaced(func(e event.WardEvent) { game.Print("ward", e.Ward, "at", e.X, e.Y) })

OnWardRevealed

func OnWardRevealed(fn func(WardEvent)) Handle

OnWardRevealed calls fn when a stealth ward of Owner is revealed to Team (a pink ward or a sweep covers it).

event.OnWardRevealed(func(e event.WardEvent) { game.Print("ward seen by team", e.Team) })

OnXpGained

func OnXpGained(fn func(XpGainedEvent)) Handle

OnXpGained calls fn when a hero gains experience (each hero of a kill separately).

event.OnXpGained(func(e event.XpGainedEvent) { game.Print("xp", e.Amount) })

Register

func Register(kind Kind, fn any) Handle

Register adds fn for an event: a func() for MapInit, a func(game.Unit) for UnitDied. A function of the wrong shape is reported in the log and ignored (the Handle is then the zero Handle).

Handle.Disable

func (h Handle) Disable()

Disable stops the hook from being called until Enable. Takes effect at once: a hook disabled by an earlier hook of the same event does not run for that event. Disabling a disabled or removed hook does nothing.

Handle.Enable

func (h Handle) Enable()

Enable lets a disabled hook run again, for the events that happen from now on. It does nothing for a hook that is enabled or was removed.

Handle.Enabled

func (h Handle) Enabled() bool

Enabled reports whether the hook exists and will be called.

Handle.Remove

func (h Handle) Remove()

Remove takes the hook away for good (a Handle of a removed hook can not be enabled again). It may be called from inside the hook itself, which makes it a one-shot, or from another hook.

HealedEvent

type HealedEvent struct {
	Target game.Unit
	Amount int
	// Source is the unit that healed; its ID is -1 when nobody did.
	Source game.Unit
}

HealedEvent is health really restored to a unit.

HitEvent

type HitEvent struct {
	Attacker, Target game.Unit
	Crit             bool
}

HitEvent is a blow landing (melee, or a shot arriving).

ItemEvent

type ItemEvent struct {
	Unit game.Unit
	// Item is the id of the item's definition, as the editor shows it.
	Item string
	// Slot is the inventory slot (0 to 5) for a use, and -1 for a purchase or a sale.
	Slot int
	// X and Y are where an item fell, in world units from the map's middle (OnItemDropped only).
	X, Y float64
	// Ground is the id the item has while it lies on the ground (OnItemDropped and OnItemPickedUp
	// only); it is the same number in both, and 0 for the other events.
	Ground int
}

ItemEvent is a unit buying, selling or using an item.

Kind

type Kind int

Kind names an event for Register.

const (
	// MapInit fires once, at the first step of the game, with a func().
	MapInit Kind = iota
	// UnitDied fires when a unit dies, with a func(game.Unit).
	UnitDied
)

ManaChangedEvent

type ManaChangedEvent struct {
	Unit  game.Unit
	Delta int
}

ManaChangedEvent is a change of a unit's mana.

MissEvent

type MissEvent struct{ Attacker, Target game.Unit }

MissEvent is an attack that missed or was evaded.

PlayerEvent

type PlayerEvent struct {
	Player player.ID
	// Team of the seat (0: none known); set for OnPlayerJoined only.
	Team int
}

PlayerEvent is a player joining or leaving.

RevealEvent

type RevealEvent struct {
	Unit game.Unit
	// Team it is shown to; 0 means every team that could not see it (brush).
	Team int
}

RevealEvent is a unit being shown to the other side because it attacked or cast unseen.

SeatEvent

type SeatEvent struct {
	Player player.ID
	State  SeatState
}

SeatEvent is a seat changing state.

SeatState

type SeatState int

SeatState is the state of a player's seat.

const (
	// SeatOpen is a seat nobody has taken yet.
	SeatOpen SeatState = iota
	// SeatSeated is a seat with a player in it.
	SeatSeated
	// SeatAbandoned is a seat whose player left; its units stay.
	SeatAbandoned
)

ShotEvent

type ShotEvent struct {
	Projectile int
	Attacker   game.Unit
	Target     game.Unit
	// Where the shot left, in world units from the middle of the map.
	X, Y float64
}

ShotEvent is a ranged attacker letting a shot go.

Stat

type Stat int

Stat is which stat of a unit a StatEvent is about.

const (
	StatHealth Stat = iota
	StatMana
	StatLevel
)

StatEvent

type StatEvent struct {
	Unit  game.Unit
	Stat  Stat
	Value int
}

StatEvent is a stat of a unit set by something other than a fight.

StunnedEvent

type StunnedEvent struct {
	Target  game.Unit
	Seconds float64
	Source  game.Unit
}

StunnedEvent is a unit being stunned.

Timer

type Timer struct {
	// contains filtered or unexported fields
}

Timer is a function the game calls later, made by Every or After. Stop it to cancel it.

After

func After(seconds float64, fn func()) *Timer

After calls fn once, seconds seconds of game time from now (at least one step). Stop the returned timer to cancel it before it runs.

Every

func Every(seconds float64, fn func()) *Timer

Every calls fn every seconds seconds of game time (at least once a step), the first time after that long counted from when Every was called. Stop the returned timer to end it.

Timer.Stop

func (t *Timer) Stop()

Stop cancels the timer: it is not called again. Stopping a timer that already ran (an After) or was stopped is fine.

TrainedEvent

type TrainedEvent struct{ Building, Unit game.Unit }

TrainedEvent is a building finishing training a unit.

TransportEvent

type TransportEvent struct{ Unit, Transport game.Unit }

TransportEvent is a unit climbing into or out of a transport.

UtilityEvent

type UtilityEvent struct {
	Unit game.Unit
	Tool UtilityTool
	// Charges the slot holds now (OnUtilityUsed and OnUtilityRecharged).
	Charges int
}

UtilityEvent is something that happened to a unit's utility (trinket) slot.

UtilityTool

type UtilityTool int

UtilityTool is what a unit's utility (trinket) slot holds.

const (
	// StealthTool places yellow wards.
	StealthTool UtilityTool = iota
	// FarsightTool places blue wards.
	FarsightTool
	// SweeperTool reveals and disables enemy wards in an area.
	SweeperTool
)

WardEvent

type WardEvent struct {
	Ward  int
	Owner player.ID
	// Kind is set for OnWardPlaced only.
	Kind WardKind
	// Team is the team the ward was revealed to (OnWardRevealed only).
	Team int
	// Where the ward stands, in world units from the middle of the map.
	X, Y float64
}

WardEvent is something that happened to a ward.

WardKind

type WardKind int

WardKind is the kind of a ward.

const (
	// YellowWard is the stealth ward: it sees, and is invisible until revealed.
	YellowWard WardKind = iota
	// PinkWard is the control ward: it reveals enemy wards around it.
	PinkWard
	// BlueWard is the farsight ward: it sees far, for a short time.
	BlueWard
)

XpGainedEvent

type XpGainedEvent struct {
	Unit   game.Unit
	Amount int
}

XpGainedEvent is experience given to a hero.