public Form1() { InitializeComponent(); bgc = BufferedGraphicsManager.Current; bg = bgc.Allocate(pictureBox1.CreateGraphics(), pictureBox1.DisplayRectangle); GameBattle.start(); timer = new Timer(); timer.Tick += new EventHandler(loop); timer.Interval = 100; timer.Enabled = true; }
public static double getTileSafetyScore(List <BattleUnit> units, BattleUnit unit, int x, int y) { double safetyScore = 0; foreach (BattleUnit u in units) { if (u.Equals(unit)) { continue; } int dx = x - u.X; int dy = y - u.Y; double distance = Math.Sqrt(dx * dx + dy * dy); if (u.team == unit.team) { //distance from ally safetyScore += (distance == 0) ? 1 : (1 / distance); } else { //distance from enemy safetyScore -= (distance == 0) ? 1 : (1 / distance); } } //check queue for future action spreads that hit this tile List <BattleAction> actions = GameBattle.getQueue().getActions(x, y, 20); //find all actions under 20 ctr actions.ForEach(action => { // "what if" the unit moved to the proposed x,y? int damage = BattleAction.getDamage(action.actor, unit, action.actiondef); if (damage > 0) { //unit would be damaged safetyScore -= 1; } if (unit.hp - damage < 0) { //unit would be killed safetyScore -= 2; } if (damage < 0) { //unit would be healed safetyScore += 1; } }); return(safetyScore); }
public BattleMove(BattleUnit unit, MoveNode node, List <MoveNode> moveNodes) { this.unit = unit; this.node = node; this.moveNodes = moveNodes; path = BattleMap.getPath(node); CTR = 0; Ready = true; Priority = 1; ID = GameBattle.generateID(); //restrict path to unit's move limit if (path.Count > unit.moveLimit) { path = path.Take(unit.moveLimit).ToList(); } }
public void invoke(BattleMap map, List <BattleUnit> units, BattleQueue queue) { List <ITargetable> targets = new List <ITargetable>(); Spread.ForEach(s => { ITargetable target = map.getFirstTileUnit(s.X, s.Y); if (target != null) { targets.Add(target); } }); targets.ForEach(target => { var damages = getDamage(actor, target, actiondef); GameBattle.WriteLine(actor.name + " used " + actiondef.name + " on " + ((BattleUnit)target).name + " for " + damages + " damages."); }); done(); }
//generate action coverage for a particular unit public static List <BattleAction> generateCoverage(BattleMap map, List <BattleUnit> units, BattleUnit unit) { double min = 0, max = 1; List <BattleAction> coverage = new List <BattleAction>(); coverage.Add(getDefaultAction(unit)); //if currently charging action, add it to coverage as well to see if it is worth switching if (unit.action != null) { int damage = getDamage(unit, unit.action.target, unit.action.actiondef); unit.action.score = getScore(unit, unit.action.target, damage); coverage.Add(unit.action); } List <MoveNode> moveNodes = new List <MoveNode>(); //if already moved, generate move nodes for current position only if (unit.moved) { moveNodes.Add(new MoveNode(unit.X, unit.Y, 0, null)); } else //generate all move nodes using pathfinding algorithm { moveNodes = BattleMap.getMoveNodes(map.tiles, GameBattle.MAP_WIDTH, GameBattle.MAP_HEIGHT, units, unit, -999, true); //list of possible move nodes moveNodes = moveNodes.Where(node => node.steps <= unit.moveLimit).ToList(); } unit.jobclass.actions.ForEach(actiondef => { moveNodes.ForEach(node => { var diamond = createDiamond(node.x, node.y, actiondef.range, GameBattle.MAP_WIDTH, GameBattle.MAP_HEIGHT, false); //list of possible action nodes diamond.ForEach(d => { int totalDamage = 0; double totalScore = 0; int actionCTR = BattleQueue.calculateCTR(100, actiondef.speed); bool sticky = false; actiondef.spread.ForEach(s => { int x = s.X + d.X; int y = s.Y + d.Y; if (BattleMap.inRange(x, y)) //if target node is in range { BattleUnit target = null; if (x == node.x && y == node.y) //is this where the actor is moving to? { target = unit; //then he will hit himself } else { target = map.getFirstTileUnit(x, y); //get the unit at spread node //if target is actor but actor will move before it hits if (target != null && unit.Equals(target) && (node.x != unit.X || node.y != unit.Y)) { target = null; //ignore actor } //if action will be invoked after target's turn (target has opportunity to move) if (target != null && target.CTR < actionCTR) { if (actiondef.sticky) //action can stick { sticky = true; } else //action cannot stick { target = null; //ignore target } } //if action will invoke before target's turn if (target != null & target.CTR >= actionCTR) { //pass } //if target is to be killed before action is invoked if (target != null) { int futureDamage = BattleQueue.getTargetFutureDamage(unit, target, actionCTR); if (futureDamage > target.hp) { target = null; //ignore target } } } if (target != null) { int damage = getDamage(unit, target, actiondef); //get damage totalScore += getScore(unit, target, damage); //get score from damage totalDamage += damage; //add damage to running total for this action } } }); //if nothing was accomplished in the spread, ignore this action node if (totalScore <= 0) { return; } totalScore += node.SafetyScore; int dx = d.X - node.x; int dy = d.Y - node.y; double distance = Math.Sqrt(dx * dx + dy * dy); //distance from action node to move node totalScore += distance; //todo: for ranged attacks higher is better, for ranged buffs lower is better BattleAction battleAction = new BattleAction(unit, actiondef); battleAction.node = node; battleAction.distance = distance; battleAction.damage = totalDamage; battleAction.score = totalScore; battleAction.moveNodes = moveNodes; battleAction.diamond = diamond; if (sticky) { battleAction.target = GameBattle.getMap().getFirstTileUnit(d.X, d.Y); } if (battleAction.target == null) { battleAction.target = GameBattle.getMap().tiles[d.X, d.Y]; } coverage.Add(battleAction); min = totalScore < min ? totalScore : min; max = totalScore > max ? totalScore : max; }); //diamond }); //mapNodes }); //actions //normalization of scores coverage.ForEach(c => { c.score = (c.score - min) / (max - min); }); coverage.Sort(); return(coverage); }
public void invoke(BattleMap map, List <BattleUnit> units, BattleQueue queue) { GameBattle.WriteLine(name + " invoked"); //this.safetyMap = generateSafetyMap(battle.units, this); List <BattleAction> coverage = BattleAction.generateCoverage(map, units, this); if (!moved && !acted) { if (action != null) { GameBattle.WriteLine(name + " is already preparing to act."); //todo: if action is sticky, allow movement acted = true; } else { action = coverage.First(); //supposedly the best action //if action requires move if (action.node.x != X || action.node.y != Y) { move = new BattleMove(this, action.node, action.moveNodes); queue.add(move); moved = true; action = null; //will get new action after move is completed } else { queue.add(action); acted = true; GameBattle.WriteLine(name + " queued an action called " + action.actiondef.name); } } } else if (acted && !moved) { GameBattle.WriteLine("Moving to a safer location."); List <MoveNode> moveNodes = BattleMap.getMoveNodes(map.tiles, GameBattle.MAP_WIDTH, GameBattle.MAP_HEIGHT, units, this, moveLimit, true); moveNodes.Sort(); MoveNode newNode = moveNodes[0]; move = new BattleMove(this, newNode, action.moveNodes); queue.add(move); //only counts as move if actually moved if (newNode.x != X || newNode.y != Y) { moved = true; } done(); } else if (!acted && moved) { if (action != null) { GameBattle.WriteLine(name + " is already preparing to act!!!"); } else { action = coverage[0]; queue.add(action); acted = true; GameBattle.WriteLine(name + " queued an action called " + action.actiondef.name); } done(); } else { GameBattle.WriteLine("This should never happen."); done(); } }
public List <BattleAction> getActions(int x, int y, int ctr) { return(list.OfType <BattleAction>().Where(action => action.CTR <= ctr && GameBattle.listHasPoint(action.Spread, x, y)).ToList()); }
public static void start() { instance = new GameBattle(); timer = new Timer(_ => instance.update(), null, 0, 1000); }