func (a *Interact) HandleInput(group gui.EventGroup, g *game.Game) (bool, game.ActionExec) { if found, event := group.FindEvent(gin.MouseLButton); found && event.Type == gin.Press { bx, by := g.GetViewer().WindowToBoard(gin.In().GetCursor("Mouse").Point()) room_num := a.ent.CurrentRoom() room := g.House.Floors[0].Rooms[room_num] for door_num, door := range room.Doors { rect := makeRectForDoor(room, door) if rect.Contains(float64(bx), float64(by)) { var exec interactExec exec.Toggle_door = true exec.SetBasicData(a.ent, a) exec.Room = room_num exec.Door = door_num return true, &exec } } } target := g.HoveredEnt() if target == nil { return false, nil } if found, event := group.FindEvent(gin.MouseLButton); found && event.Type == gin.Press { for i := range a.targets { if a.targets[i] == target && distBetweenEnts(a.ent, target) <= a.Range { var exec interactExec exec.SetBasicData(a.ent, a) exec.Target = target.Id return true, &exec } } return true, nil } return false, nil }
func (a *SummonAction) Maintain(dt int64, g *game.Game, ae game.ActionExec) game.MaintenanceStatus { if ae != nil { exec := ae.(*summonExec) ent := g.EntityById(exec.Ent) if ent == nil { base.Error().Printf("Got a summon action without a valid entity.") return game.Complete } a.ent = ent _, a.cx, a.cy = a.ent.Game().FromVertex(exec.Pos) a.ent.Stats.ApplyDamage(-a.Ap, 0, status.Unspecified) a.spawn = game.MakeEntity(a.Ent_name, a.ent.Game()) if a.Current_ammo > 0 { a.Current_ammo-- } } if a.ent.Sprite().State() == "ready" { a.ent.TurnToFace(a.cx, a.cy) a.ent.Sprite().Command(a.Animation) a.spawn.Stats.OnBegin() a.ent.Game().SpawnEntity(a.spawn, a.cx, a.cy) return game.Complete } return game.InProgress }
func (a *AoeAttack) getTargetsAt(g *game.Game, tx, ty int) []*game.Entity { x := tx - (a.Diameter+1)/2 y := ty - (a.Diameter+1)/2 x2 := tx + a.Diameter/2 y2 := ty + a.Diameter/2 // If the diameter is even we need to run los from all four positions // around the center of the aoe. num_centers := 1 if a.Diameter%2 == 0 { num_centers = 4 } var targets []*game.Entity for i := 0; i < num_centers; i++ { // If num_centers is 4 then this will calculate the los for all four // positions around the center g.DetermineLos(tx+i%2, ty+i/2, a.Diameter, grid[i]) } for _, ent := range g.Ents { entx, enty := ent.Pos() has_los := false for i := 0; i < num_centers; i++ { has_los = has_los || grid[i][entx][enty] } if has_los && entx >= x && entx < x2 && enty >= y && enty < y2 { targets = append(targets, ent) } } algorithm.Choose(&targets, func(e *game.Entity) bool { return e.Stats != nil }) return targets }
func (a *SummonAction) HandleInput(group gui.EventGroup, g *game.Game) (bool, game.ActionExec) { cursor := group.Events[0].Key.Cursor() if cursor != nil { bx, by := g.GetViewer().WindowToBoard(cursor.Point()) bx += 0.5 by += 0.5 if bx < 0 { bx-- } if by < 0 { by-- } a.cx = int(bx) a.cy = int(by) } if found, event := group.FindEvent(gin.MouseLButton); found && event.Type == gin.Press { if g.IsCellOccupied(a.cx, a.cy) { return true, nil } if a.Personal_los && !a.ent.HasLos(a.cx, a.cy, 1, 1) { return true, nil } if a.ent.Stats.ApCur() >= a.Ap { var exec summonExec exec.SetBasicData(a.ent, a) exec.Pos = a.ent.Game().ToVertex(a.cx, a.cy) return true, &exec } return true, nil } return false, nil }
func (a *Move) Prep(ent *game.Entity, g *game.Game) bool { a.ent = ent fx, fy := g.GetViewer().WindowToBoard(gin.In().GetCursor("Mouse").Point()) a.findPath(ent, int(fx), int(fy)) a.threshold = a.ent.Stats.ApCur() return true }
func (a *AoeAttack) Maintain(dt int64, g *game.Game, ae game.ActionExec) game.MaintenanceStatus { if ae != nil { a.exec = ae.(*aoeExec) a.targets = a.getTargetsAt(g, a.exec.X, a.exec.Y) if a.Current_ammo > 0 { a.Current_ammo-- } a.ent = g.EntityById(ae.EntityId()) if !a.ent.HasLos(a.exec.X, a.exec.Y, 1, 1) { base.Error().Printf("Entity %d tried to target position (%d, %d) with an aoe but doesn't have los to it: %v", a.ent.Id, a.exec.X, a.exec.Y, a.exec) return game.Complete } if a.Ap > a.ent.Stats.ApCur() { base.Error().Printf("Got an aoe attack that required more ap than available: %v", a.exec) return game.Complete } a.ent.Stats.ApplyDamage(-a.Ap, 0, status.Unspecified) // Track this information for the ais - the attacking ent will only // remember one ent that it hit, but that's ok for _, target := range a.targets { if target.Side() != a.ent.Side() { target.Info.LastEntThatAttackedMe = a.ent.Id a.ent.Info.LastEntThatIAttacked = target.Id } } } if a.ent.Sprite().State() != "ready" { return game.InProgress } for _, target := range a.targets { if target.Stats.HpCur() > 0 && target.Sprite().State() != "ready" { return game.InProgress } } a.ent.TurnToFace(a.exec.X, a.exec.Y) for _, target := range a.targets { target.TurnToFace(a.ent.Pos()) } a.ent.Sprite().Command(a.Animation) for _, target := range a.targets { if g.DoAttack(a.ent, target, a.Strength, a.Kind) { for _, name := range a.Conditions { target.Stats.ApplyCondition(status.MakeCondition(name)) } target.Stats.ApplyDamage(0, -a.Damage, a.Kind) if target.Stats.HpCur() <= 0 { target.Sprite().CommandN([]string{"defend", "killed"}) } else { target.Sprite().CommandN([]string{"defend", "damaged"}) } } else { target.Sprite().CommandN([]string{"defend", "undamaged"}) } } return game.Complete }
func (exec summonExec) Push(L *lua.State, g *game.Game) { exec.BasicActionExec.Push(L, g) if L.IsNil(-1) { return } _, x, y := g.FromVertex(exec.Pos) L.PushString("Pos") game.LuaPushPoint(L, x, y) L.SetTable(-3) }
func (exec basicAttackExec) Push(L *lua.State, g *game.Game) { exec.BasicActionExec.Push(L, g) if L.IsNil(-1) { return } target := g.EntityById(exec.Target) L.PushString("Target") game.LuaPushEntity(L, target) L.SetTable(-3) }
func (a *BasicAttack) HandleInput(group gui.EventGroup, g *game.Game) (bool, game.ActionExec) { target := g.HoveredEnt() if found, event := group.FindEvent(gin.MouseLButton); found && event.Type == gin.Press { if target == nil || !a.validTarget(a.ent, target) { return true, nil } return true, a.makeExec(a.ent, target) } return false, nil }
func (a *AoeAttack) Prep(ent *game.Entity, g *game.Game) bool { if !a.Preppable(ent, g) { return false } a.ent = ent bx, by := g.GetViewer().WindowToBoard(gin.In().GetCursor("Mouse").Point()) a.tx = int(bx) a.ty = int(by) return true }
func (a *Move) Maintain(dt int64, g *game.Game, ae game.ActionExec) game.MaintenanceStatus { if ae != nil { exec := ae.(*moveExec) a.ent = g.EntityById(ae.EntityId()) if len(exec.Path) == 0 { base.Error().Printf("Got a move exec with a path length of 0: %v", exec) return game.Complete } a.cost = exec.measureCost(a.ent, g) if a.cost > a.ent.Stats.ApCur() { base.Error().Printf("Got a move that required more ap than available: %v", exec) base.Error().Printf("Path: %v", exec.Path) return game.Complete } if a.cost == -1 { base.Error().Printf("Got a move that followed an invalid path: %v", exec) base.Error().Printf("Path: %v", exec.Path) if a.ent == nil { base.Error().Printf("ENT was Nil!") } else { x, y := a.ent.Pos() v := g.ToVertex(x, y) base.Error().Printf("Ent pos: (%d, %d) -> (%d)", x, y, v) } return game.Complete } algorithm.Map2(exec.Path, &a.path, func(v int) [2]int { _, x, y := g.FromVertex(v) return [2]int{x, y} }) base.Log().Printf("Path Validated: %v", exec) a.ent.Stats.ApplyDamage(-a.cost, 0, status.Unspecified) src := g.ToVertex(a.ent.Pos()) graph := g.Graph(a.ent.Side(), true, nil) a.drawPath(a.ent, g, graph, src) } // Do stuff factor := float32(math.Pow(2, a.ent.Walking_speed)) dist := a.ent.DoAdvance(factor*float32(dt)/200, a.path[0][0], a.path[0][1]) for dist > 0 { if len(a.path) == 1 { a.ent.DoAdvance(0, 0, 0) a.ent.Info.RoomsExplored[a.ent.CurrentRoom()] = true a.ent = nil return game.Complete } a.path = a.path[1:] a.ent.Info.RoomsExplored[a.ent.CurrentRoom()] = true dist = a.ent.DoAdvance(dist, a.path[0][0], a.path[0][1]) } return game.InProgress }
func (a *BasicAttack) Maintain(dt int64, g *game.Game, ae game.ActionExec) game.MaintenanceStatus { if ae != nil { a.exec = ae.(*basicAttackExec) a.ent = g.EntityById(ae.EntityId()) a.target = a.ent.Game().EntityById(a.exec.Target) // Track this information for the ais if a.ent.Side() != a.target.Side() { a.ent.Info.LastEntThatIAttacked = a.target.Id a.target.Info.LastEntThatAttackedMe = a.ent.Id } if a.Ap > a.ent.Stats.ApCur() { base.Error().Printf("Got a basic attack that required more ap than available: %v", a.exec) base.Error().Printf("Ent: %s, Ap: %d", a.ent.Name, a.ent.Stats.ApCur()) return game.Complete } if !a.validTarget(a.ent, a.target) { base.Error().Printf("Got a basic attack that was invalid for some reason: %v", a.exec) return game.Complete } } if a.ent.Sprite().State() == "ready" && a.target.Sprite().State() == "ready" { a.target.TurnToFace(a.ent.Pos()) a.ent.TurnToFace(a.target.Pos()) if a.Current_ammo > 0 { a.Current_ammo-- } a.ent.Stats.ApplyDamage(-a.Ap, 0, status.Unspecified) var defender_cmds []string if g.DoAttack(a.ent, a.target, a.Strength, a.Kind) { for _, name := range a.Conditions { a.target.Stats.ApplyCondition(status.MakeCondition(name)) } a.target.Stats.ApplyDamage(0, -a.Damage, a.Kind) if a.target.Stats.HpCur() <= 0 { defender_cmds = []string{"defend", "killed"} } else { defender_cmds = []string{"defend", "damaged"} } results[a.exec.id] = BasicAttackResult{Hit: true} } else { defender_cmds = []string{"defend", "undamaged"} results[a.exec.id] = BasicAttackResult{Hit: false} } sprites := []*sprite.Sprite{a.ent.Sprite(), a.target.Sprite()} sprite.CommandSync(sprites, [][]string{[]string{a.Animation}, defender_cmds}, "hit") return game.Complete } return game.InProgress }
func (exec *moveExec) measureCost(ent *game.Entity, g *game.Game) int { if len(exec.Path) == 0 { base.Error().Printf("Zero length path") return -1 } if g.ToVertex(ent.Pos()) != exec.Path[0] { base.Error().Printf("Path doesn't begin at ent's position, %d != %d", g.ToVertex(ent.Pos()), exec.Path[0]) return -1 } graph := g.Graph(ent.Side(), true, nil) v := g.ToVertex(ent.Pos()) cost := 0 for _, step := range exec.Path[1:] { dsts, costs := graph.Adjacent(v) ok := false prev := v base.Log().Printf("Adj(%d):", v) for j := range dsts { base.Log().Printf("Node %d", dsts[j]) if dsts[j] == step { cost += int(costs[j]) v = dsts[j] ok = true break } } base.Log().Printf("%d -> %d: %t", prev, v, ok) if !ok { return -1 } } return cost }
func (exec *moveExec) Push(L *lua.State, g *game.Game) { exec.BasicActionExec.Push(L, g) if L.IsNil(-1) { return } L.PushString("Path") L.NewTable() for i := range exec.Path { L.PushInteger(i + 1) _, x, y := g.FromVertex(exec.Path[i]) game.LuaPushPoint(L, x, y) L.SetTable(-3) } L.SetTable(-3) }
func (exec interactExec) Push(L *lua.State, g *game.Game) { exec.BasicActionExec.Push(L, g) if L.IsNil(-1) { return } L.PushString("Toggle Door") L.PushBoolean(exec.Toggle_door) L.SetTable(-3) if exec.Toggle_door { L.PushString("Door") game.LuaPushDoor(L, g, exec.getDoor(g)) } else { L.PushString("Target") game.LuaPushEntity(L, g.EntityById(exec.Target)) } L.SetTable(-3) }
func (a *AoeAttack) HandleInput(group gui.EventGroup, g *game.Game) (bool, game.ActionExec) { cursor := group.Events[0].Key.Cursor() if cursor != nil && cursor.Name() == "Mouse" { bx, by := g.GetViewer().WindowToBoard(cursor.Point()) a.tx = int(bx) a.ty = int(by) } if found, event := group.FindEvent(gin.MouseLButton); found && event.Type == gin.Press { ex, ey := a.ent.Pos() if dist(ex, ey, a.tx, a.ty) <= a.Range && a.ent.HasLos(a.tx, a.ty, 1, 1) { var exec aoeExec exec.SetBasicData(a.ent, a) exec.X, exec.Y = a.tx, a.ty return true, &exec } else { return true, nil } return true, nil } return false, nil }
func (a *Move) HandleInput(group gui.EventGroup, g *game.Game) (bool, game.ActionExec) { cursor := group.Events[0].Key.Cursor() if cursor != nil { fx, fy := g.GetViewer().WindowToBoard(cursor.Point()) a.findPath(a.ent, int(fx), int(fy)) } if found, _ := group.FindEvent(gin.MouseLButton); found { if len(a.path) > 0 { if a.cost <= a.ent.Stats.ApCur() { var exec moveExec exec.SetBasicData(a.ent, a) algorithm.Map2(a.path, &exec.Path, func(v [2]int) int { return g.ToVertex(v[0], v[1]) }) return true, &exec } return true, nil } else { return false, nil } } return false, nil }
func (a *Move) drawPath(ent *game.Entity, g *game.Game, graph algorithm.Graph, src int) { if path_tex != nil { pix := path_tex.Pix() for i := range pix { for j := range pix[i] { pix[i][j] = 0 } } current := 0.0 for i := 1; i < len(a.path); i++ { src := g.ToVertex(a.path[i-1][0], a.path[i-1][1]) dst := g.ToVertex(a.path[i][0], a.path[i][1]) v, cost := graph.Adjacent(src) for j := range v { if v[j] == dst { current += cost[j] break } } pix[a.path[i][1]][a.path[i][0]] += byte(current) } path_tex.Remap() } }
func (a *Interact) Maintain(dt int64, g *game.Game, ae game.ActionExec) game.MaintenanceStatus { if ae != nil { exec := ae.(*interactExec) a.ent = g.EntityById(ae.EntityId()) if (exec.Target != 0) == (exec.Toggle_door) { base.Error().Printf("Got an interact that tried to target a door and an entity: %v", exec) return game.Complete } if exec.Target != 0 { target := g.EntityById(exec.Target) if target == nil { base.Error().Printf("Tried to interact with an entity that doesn't exist: %v", exec) return game.Complete } if target.ObjectEnt == nil { base.Error().Printf("Tried to interact with an entity that wasn't an object: %v", exec) return game.Complete } if target.Sprite().State() != "ready" { base.Error().Printf("Tried to interact with an object that wasn't in its ready state: %v", exec) return game.Complete } if distBetweenEnts(a.ent, target) > a.Range { base.Error().Printf("Tried to interact with an object that was out of range: %v", exec) return game.Complete } x, y := target.Pos() dx, dy := target.Dims() if !a.ent.HasLos(x, y, dx, dy) { base.Error().Printf("Tried to interact with an object without having los: %v", exec) return game.Complete } a.ent.Stats.ApplyDamage(-a.Ap, 0, status.Unspecified) target.Sprite().Command("inspect") return game.Complete } else { // We're interacting with a door here if exec.Floor < 0 || exec.Floor >= len(g.House.Floors) { base.Error().Printf("Specified an unknown floor %v", exec) return game.Complete } floor := g.House.Floors[exec.Floor] if exec.Room < 0 || exec.Room >= len(floor.Rooms) { base.Error().Printf("Specified an unknown room %v", exec) return game.Complete } room := floor.Rooms[exec.Room] if exec.Door < 0 || exec.Door >= len(room.Doors) { base.Error().Printf("Specified an unknown door %v", exec) return game.Complete } door := room.Doors[exec.Door] x, y := a.ent.Pos() dx, dy := a.ent.Dims() ent_rect := makeIntFrect(x, y, x+dx, y+dy) if !ent_rect.Overlaps(makeRectForDoor(room, door)) { base.Error().Printf("Tried to open a door that was out of range: %v", exec) return game.Complete } _, other_door := floor.FindMatchingDoor(room, door) if other_door != nil { door.SetOpened(!door.IsOpened()) other_door.SetOpened(door.IsOpened()) // if door.IsOpened() { // sound.PlaySound(door.Open_sound) // } else { // sound.PlaySound(door.Shut_sound) // } g.RecalcLos() a.ent.Stats.ApplyDamage(-a.Ap, 0, status.Unspecified) } else { base.Error().Printf("Couldn't find matching door: %v", exec) return game.Complete } } } return game.Complete }