public BattleAction(BattleUnit actor, ActionDefinition actiondef) { this.actor = actor; this.actiondef = actiondef; CTR = BattleQueue.calculateCTR(100, actiondef.speed); Priority = 2; ID = GameBattle.generateID(); //rangeBrush = new SolidBrush(Color.FromArgb(255, 255, 0, 0)); spreadBrush = new SolidBrush(Color.FromArgb(255, 0, 255, 0)); }
public static int getTargetFutureDamage(BattleUnit unit, BattleUnit target, int CTR) { /* * This function calculates the amount of damage to be inflicted upon a unit from actions * targetted at that unit's x,y location before a given CTR value */ BattleQueue queue = GameBattle.getQueue(); int damage = 0; List <BattleAction> actions = queue.getActions(target.X, target.Y, CTR); actions.ForEach(action => damage += BattleAction.getDamage(unit, target, action.actiondef)); return(damage); }
public void invoke(BattleMap map, List <BattleUnit> units, BattleQueue queue) { if (path.Count > 0) { GameBattle.WriteLine("BattleMove: " + unit.name + " moved to " + path[0].x + ", " + path[0].y); var node = path[0]; path.RemoveAt(0); map.moveUnit(ref unit, node.x, node.y); } else { done(); } }
public GameBattle() { map = new BattleMap(MAP_WIDTH, MAP_HEIGHT); units = new List <BattleUnit>(); units.Add(new BattleUnit("alfred", "cpu1", 0, 0)); units.Add(new BattleUnit("bob", "cpu2", 2, 2)); map.addUnits(units); queue = new BattleQueue(units); consoleBuffer = ""; }
public void done() { CT = 60; if (moved) { CT += 20; } if (acted) { CT += action.actiondef.CTCost; } CTR = BattleQueue.calculateCTR(CT, Speed); Ready = false; moved = false; acted = false; Done = true; }
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(); } }