package challenge func (e *Engine) register(event Event, p *Player) { if p.Registered || p.InDungeon { e.impossible(event) return } p.Registered = true e.log(event.At, "Player [%d] registered", p.ID) } func (e *Engine) enterDungeon(event Event, p *Player) { if p.InDungeon || event.At < e.openAt || event.At >= e.closeAt { e.impossible(event) return } p.InDungeon = true p.Attempted = true p.EnteredAt = event.At p.EndedAt = event.At p.Floor = 1 e.startFloorTimer(p, event.At) e.log(event.At, "Player [%d] entered the dungeon", p.ID) } func (e *Engine) killMonster(event Event, p *Player) { if !p.InDungeon || p.Floor < 1 || p.Floor > e.regularFloors || p.MonsterKills[p.Floor] >= e.cfg.Monsters { e.impossible(event) return } p.MonsterKills[p.Floor]++ e.log(event.At, "Player [%d] killed the monster", p.ID) if p.MonsterKills[p.Floor] == e.cfg.Monsters { e.finishFloorTimer(p, event.At) } } func (e *Engine) nextFloor(event Event, p *Player) { if !p.InDungeon || p.Floor < 1 || p.Floor >= e.cfg.Floors || !e.floorCleared(p, p.Floor) { e.impossible(event) return } e.pauseFloorTimer(p, event.At) p.Floor++ e.startFloorTimer(p, event.At) e.log(event.At, "Player [%d] went to the next floor", p.ID) } func (e *Engine) previousFloor(event Event, p *Player) { if !p.InDungeon || p.Floor <= 1 { e.impossible(event) return } e.pauseFloorTimer(p, event.At) p.Floor-- e.startFloorTimer(p, event.At) e.log(event.At, "Player [%d] went to the previous floor", p.ID) } func (e *Engine) enterBoss(event Event, p *Player) { if !p.InDungeon || p.BossEntered || p.Floor != e.cfg.Floors || !e.allRegularFloorsCleared(p) { e.impossible(event) return } p.BossEntered = true p.BossEnterAt = event.At e.log(event.At, "Player [%d] entered the boss's floor", p.ID) } func (e *Engine) killBoss(event Event, p *Player) { if !p.InDungeon || !p.BossEntered || p.BossKilled { e.impossible(event) return } p.BossKilled = true p.BossTime = event.At - p.BossEnterAt e.log(event.At, "Player [%d] killed the boss", p.ID) } func (e *Engine) leaveDungeon(event Event, p *Player) { if !p.InDungeon { e.impossible(event) return } e.pauseFloorTimer(p, event.At) p.InDungeon = false p.Left = true p.Terminal = true p.EndedAt = event.At e.log(event.At, "Player [%d] left the dungeon", p.ID) } func (e *Engine) cannotContinue(event Event, p *Player) { p.Disqual = true p.Terminal = true p.EndedAt = event.At e.log(event.At, "Player [%d] cannot continue due to [%s]", p.ID, event.Extra) } func (e *Engine) restoreHealth(event Event, p *Player) { amount, ok := parseNonNegativeInt(event.Extra) if !ok || !p.InDungeon { e.impossible(event) return } p.Health = min(100, p.Health+amount) e.log(event.At, "Player [%d] has restored [%d] of health", p.ID, amount) } func (e *Engine) takeDamage(event Event, p *Player) { damage, ok := parseNonNegativeInt(event.Extra) if !ok || !p.InDungeon { e.impossible(event) return } p.Health = max(0, p.Health-damage) e.log(event.At, "Player [%d] recieved [%d] of damage", p.ID, damage) if p.Health == 0 { e.pauseFloorTimer(p, event.At) p.Dead = true p.InDungeon = false p.Terminal = true p.EndedAt = event.At e.log(event.At, "Player [%d] is dead", p.ID) } } func (e *Engine) impossible(event Event) { e.log(event.At, "Player [%d] makes imposible move [%d]", event.Player, event.ID) }