/src/World.hx
Haxe | 1280 lines | 1054 code | 179 blank | 47 comment | 294 complexity | a80bf117e1216b458a5f5f91cab75174 MD5 | raw file
-
- import flash.Lib;
- import flash.display.Sprite;
- import flash.display.Shape;
- import flash.events.Event;
- import flash.events.KeyboardEvent;
- import flash.events.MouseEvent;
- import flash.ui.Keyboard;
- import flash.text.TextField;
- import haxe.Serializer;
- import haxe.Unserializer;
- import haxe.Timer;
- import haxe.Log;
-
-
- import script.Machine;
- import script.Program;
-
- import Common;
- import Node;
- import Link;
- import Bug;
- import Level;
- import Grid;
- import HUD;
-
-
- import CommandMacro;
- @:build(CommandMacro.build()) class Commands {}
-
- enum InputMode
- {
- Default;
- CreateNode;
- Disabled;
- LinkDirection;
- }
-
- class WorldProperties
- {
- /** How many Scout bugs should be automatically
- * spawned constantly */
- public var autoSpawnScouts:Int;
- /** Duration between two autoSpawns (s) */
- public var autoSpawnInterval:Float;
- /** Will bugs target Core node only
- * or attack any node */
- public var targetCore:Bool;
-
-
- public function new() {
- targetCore = false;
- autoSpawnInterval = 1;
- }
- }
-
- class WorldState
- {
- public var nodes:Array<Node>;
- public var links:Array<Link>;
- public var bugs:List<Bug>;
- public var cells:List<Cell>;
- public var players:Array<Player>;
- public var time:Float;
- public var properties:WorldProperties;
-
- public function new()
- {
- }
- }
-
-
-
- class BugSpawnHandler implements script.ICommandHandler
- {
- public function new(w:World)
- {
- this.world = w;
- }
-
- public function handleCommand(cmd:String, arg:String):Bool
- {
- if (cmd == Commands.target) {
- target = cast(world.getNodeByID(arg), BugNestNode);
- if (target == null) {
- Log.trace("ERROR: could not find target " + arg);
- }
- return true;
- }
- else if (cmd == Commands.spawn) {
- if (target != null) {
- var type = Type.createEnum(BugType, arg);
- if (type != null) {
- world.spawnBug(target, type);
- }
- else {
- Log.trace("ERROR: could not find bug type " + arg);
- }
- }
- return true;
- }
- return false;
- }
-
- var target:BugNestNode;
- var world:World;
- }
-
-
- class WorldCommandHandler implements script.ICommandHandler
- {
- public function new(w:World)
- {
- world = w;
- spawner = new BugSpawnHandler(w);
- }
-
- public function handleCommand(cmd:String, arg:String):Bool
- {
- if (spawner.handleCommand(cmd, arg))
- return true;
-
- if (cmd == Commands.gameLose) {
- world.onGameLose(arg);
- }
- else if (cmd == Commands.msgInfo) {
- Log.trace(arg);
- }
- else if (cmd == Commands.set) {
- var args = arg.split(',');
- try {
- var member = Reflect.field(world.properties, args[0]);
- if (Type.typeof(member) == Type.ValueType.TBool) {
- Reflect.setField(world.properties, args[0], args[1]=='0' ? false : true);
- }
- else if (Type.typeof(member) == Type.ValueType.TInt) {
- Reflect.setField(world.properties, args[0], Std.parseInt(args[1]));
- }
- else if (Type.typeof(member) == Type.ValueType.TFloat) {
- Reflect.setField(world.properties, args[0], Std.parseFloat(args[1]));
- }
- else
- Reflect.setField(world.properties, args[0], args[1]);
-
- } catch (e:String){ Log.trace("Could not set property: " + e); }
- }
- else if (cmd == Commands.exec) {
- world.executeScriptlet(arg);
- }
-
- return false;
- }
-
- var spawner:BugSpawnHandler;
- var world:World;
- }
-
-
- class World extends Sprite
- {
- public static var Instance:World;
- public var players:Array<Player>;
- public var nodes:Array<Node>;
- public var links:Array<Link>;
- public var properties:WorldProperties;
- var bugs:List<Bug>;
- var inputMode:InputMode;
- var activePlayerIndex:Int;
- var grid:Grid;
- var script:script.Machine;
- var cmdHandler:WorldCommandHandler;
- var level:Level;
- public var time:Float;
-
-
- public var selectedNode:Node;
- public var nStepsPerFrame:Int;
- public var playing:Bool;
-
- // GUI
- public var backgroundLayer:Sprite;
- public var rootLayer:Sprite;
- var gridLayer:GridUI;
- var linksLayer:Sprite;
- var linksFXLayer:Sprite;
- var nodesLayer:Sprite;
- var bugsLayer:Sprite;
- var effectsLayer:Sprite;
- public var hud:HUD;
-
-
- // Temp
- var tempNode:Node;
- var tempNodeUI:NodeUI;
-
- public function new()
- {
- super();
- Instance = this;
- inputMode = InputMode.Default;
- activePlayerIndex = -1;
- nStepsPerFrame = 1;
- players = new Array<Player>();
- playing = false;
- properties = new WorldProperties();
- init();
- }
-
- public function getWidth() { return 800; }
- public function getHeight() { return 600; }
-
- public function getPlayer(i:Int): Player
- {
- return players[i];
- }
- public function setActivePlayer(i:Int)
- {
- activePlayerIndex = i;
- Debug.assert(getPlayer(i) != null);
- }
-
- function init()
- {
- // Background
- backgroundLayer = new Sprite();
- backgroundLayer.graphics.clear();
- backgroundLayer.graphics.beginFill(0xffffff, 1);
- backgroundLayer.graphics.drawRect(0, 0, 800, 600);
- backgroundLayer.graphics.endFill();
- backgroundLayer.addEventListener(MouseEvent.MOUSE_DOWN, mouseDown);
- backgroundLayer.addEventListener(MouseEvent.MOUSE_UP, mouseUp);
- backgroundLayer.addEventListener(MouseEvent.MOUSE_MOVE, mouseMove);
- backgroundLayer.addEventListener(MouseEvent.CLICK, mouseClicked);
- addChild(backgroundLayer);
-
- resetWorld();
-
- addEventListener(Event.ENTER_FRAME, update);
-
- flash.Lib.current.stage.addEventListener(KeyboardEvent.KEY_DOWN, keydown);
- }
-
- public function step(dt:Float)
- {
- // Update links
- for (link in links)
- {
- link.step(dt);
- }
-
- stepNodes();
- stepBugs();
-
- grid.update();
-
- script.setTime(time);
-
- time += dt;
- }
-
-
- public function update(e:Event)
- {
- // Simulation
- if (playing) {
- for (i in 0...nStepsPerFrame)
- {
- step(Settings.Gameplay.StepDuration);
- }
- }
-
-
- // Keyboard temp
- {
- var s = 20;
- if (KeyboardManager.Instance.getKeyState(Keyboard.LEFT).active) {
- rootLayer.x += s;
- }
- if (KeyboardManager.Instance.getKeyState(Keyboard.RIGHT).active) {
- rootLayer.x -= s;
- }
- if (KeyboardManager.Instance.getKeyState(Keyboard.UP).active) {
- rootLayer.y += s;
- }
- if (KeyboardManager.Instance.getKeyState(Keyboard.DOWN).active) {
- rootLayer.y -= s;
- }
- }
-
- gridLayer.moveTo(rootLayer.x, rootLayer.y);
- }
-
- public function spawnBug(nest:BugNestNode, type:BugType)
- {
- var b = new Bug();
- b.pos.x = Math.random() * 5 + nest.pos.x;
- b.pos.y = Math.random() * 5 + nest.pos.y;
- b.ownerPlayer = nest.owner;
- b.targetPlayer = -1;
- b.state = BugState.Chase;
- b.type = type;
- var itype = Type.enumIndex(type);
- b.speed = Settings.Gameplay.Bugs.Speed[itype];
- b.attack = Settings.Gameplay.Bugs.Attack[itype];
- b.health = b.getHP();
- nest.lastSpawnTime = time;
- addNewBug(b);
- }
-
- public function deleteNode(c:Cell)
- {
- // Unregister from cell
- var n = c.node;
- if (n == null)
- return;
-
- c.node = null;
- n.deleted = true;
-
- // Remove links
- var toDelete = new Array<Link>();
- for (l in links) {
- if (l.a == n || l.b == n) {
- toDelete.push(l);
- }
- }
- for (l in toDelete) {
- l.unlink();
- links.remove(l);
- linksLayer.removeChild(l.ui);
- }
-
- // Remove node
- nodes.remove(n);
- nodesLayer.removeChild(n.ui);
- }
-
- public function addNewNode(n:Node, ?direct:Bool=false)
- {
- // Add new links
- for (on in nodes)
- {
- if (canLinkWith(n, on))
- {
- var l = new Link();
- l.link(on, n);
- l.pending = true;
- addNewLink(l);
- }
- }
-
- if (direct)
- {
- n.state = NodeState.Idle;
- n.buildValue = n.getProperty("BuildCost");
- fixNodeCell(n);
- }
- else
- {
- n.state = NodeState.Creation;
- n.buildValue = 0;
- }
-
- // UI
- var ui = new NodeUI(n);
- ui.activate();
- n.ui = ui;
-
- nodesLayer.addChild(ui);
- nodes.push(n);
- }
-
- public function addNewLink(l:Link)
- {
- links.push(l);
-
- var ui = new LinkUI(l);
- l.ui = ui;
- ui.rebuildUI();
- linksLayer.addChild(ui);
- }
-
- public function addNewBug(b:Bug)
- {
- bugs.push(b);
- var ui = new BugUI(b);
- b.ui = ui;
- bugsLayer.addChild(ui);
- }
-
- public function removeBug(b:Bug)
- {
- bugs.remove(b);
- bugsLayer.removeChild(b.ui);
- }
-
- public function addNewPlayer(p:Player)
- {
- players.push(p);
- }
-
- public function serialize(s:Serializer)
- {
- var ws = new WorldState();
- ws.nodes = nodes;
- ws.links = links;
- ws.bugs = bugs;
- ws.players = players;
- ws.time = time;
- ws.properties = properties;
-
- ws.cells = new List<Cell>();
- for (c in grid.getCells())
- {
- ws.cells.add(c);
- }
-
- s.serialize(ws);
- }
-
- public function unSerialize(s:Unserializer)
- {
- var ws:WorldState = s.unserialize();
- reloadWorld(ws);
- }
-
-
- public function resetWorld()
- {
- properties = new WorldProperties();
- script = new script.Machine();
- nodes = new Array<Node>();
- links = new Array<Link>();
- bugs = new List<Bug>();
- time = 0;
- playing = false;
-
- cmdHandler = new WorldCommandHandler(this);
-
- // Grid
- grid = new Grid();
- if (gridLayer != null)
- removeChild(gridLayer);
- gridLayer = new GridUI(grid);
- addChild(gridLayer);
- gridLayer.rebuild(getWidth(), getHeight());
- grid.ui = gridLayer;
-
-
- // Root layer
- if (rootLayer != null)
- removeChild(rootLayer);
- rootLayer = new Sprite();
- addChild(rootLayer);
-
- linksLayer = new Sprite();
- rootLayer.addChild(linksLayer);
-
- linksFXLayer = new Sprite();
- rootLayer.addChild(linksFXLayer);
-
- nodesLayer = new Sprite();
- rootLayer.addChild(nodesLayer);
-
- if (Settings.Debug.Phero)
- nodesLayer.alpha = 0.2;
-
- bugsLayer = new Sprite();
- rootLayer.addChild(bugsLayer);
-
- effectsLayer = new Sprite();
- rootLayer.addChild(effectsLayer);
-
- if (hud != null) {
- hud.shutdown();
- removeChild(hud);
- }
- hud = new HUD();
- addChild(hud);
-
- tempNodeUI = null;
- }
-
- private function reloadWorld(ws:WorldState)
- {
- resetWorld();
-
- nodes = ws.nodes;
- links = ws.links;
- bugs = ws.bugs;
- time = ws.time;
- properties = ws.properties;
-
- for (n in nodes)
- {
- var ui = new NodeUI(n);
- ui.activate();
- n.ui = ui;
- nodesLayer.addChild(ui);
- }
- for (l in links)
- {
- var ui = new LinkUI(l);
- l.ui = ui;
- ui.rebuildUI();
- linksLayer.addChild(ui);
- }
- for (b in bugs)
- {
- var ui = new BugUI(b);
- b.ui = ui;
- bugsLayer.addChild(ui);
- }
-
- grid.loadCells(ws.cells.iterator());
- }
-
- public function loadLevel(l:Level)
- {
- level = l;
- nodes = level.nodes;
- links = level.links;
-
- grid.loadCells(level.cells.iterator());
-
- for (n in nodes)
- {
- fixNodeCell(n);
- postLoadNode(n);
- // UI
- var ui = new NodeUI(n);
- ui.activate();
- n.ui = ui;
- nodesLayer.addChild(ui);
- }
- for (l in links)
- {
- var ui = new LinkUI(l);
- l.ui = ui;
- ui.rebuildUI();
- linksLayer.addChild(ui);
- }
- }
-
- public function start()
- {
- playing = true;
- executeScriptlet("game_start");
- }
-
- function postLoadNode(n:Node)
- {
- if (n.type == NodeType.BugNest)
- {
- var bn = cast(n, BugNestNode);
- }
- }
-
- public function selectNode(n:Node)
- {
- if (selectedNode != null)
- {
- var ss = selectedNode;
- selectedNode = null;
- ss.ui.reset();
- }
- selectedNode = n;
- if (n != null)
- selectedNode.ui.reset();
- }
-
- public function getLinkConnection(a:Node, b:Node)
- {
- for (l in links) {
- if (l.a == a && l.b == b ||
- l.b == a && l.a == b) {
- return l;
- }
- }
- return null;
- }
-
- public function getNodeByID(id:String)
- {
- for (n in nodes)
- {
- if (n.id == id)
- return n;
- }
- return null;
- }
-
- static function getDist(na:Node, nb:Node):Float
- {
- return nb.pos.sub(na.pos).getSize();
- }
-
- function canLinkWith(na:Node, nb:Node):Bool
- {
- if (na.owner != nb.owner)
- return false;
-
- if (!nb.canGiveEnergy())
- return false;
-
- var dx = na.pos.x - nb.pos.x;
- var dy = na.pos.y - nb.pos.y;
- var rad = grid.HexSize * 3 + MathUtils.Epsilon;
- if (dx * dx + dy * dy <= rad * rad)
- {
- return true;
- }
- return false;
- }
-
- public function setMode(newMode:InputMode)
- {
- if (newMode == inputMode)
- return;
-
- if (newMode == InputMode.CreateNode)
- {
- rootLayer.mouseChildren = false;
- rootLayer.mouseEnabled = false;
- }
- else if (inputMode == InputMode.CreateNode)
- {
- nodesLayer.removeChild(tempNodeUI);
- tempNodeUI = null;
- tempNode = null;
- rootLayer.mouseEnabled = true;
- rootLayer.mouseChildren = true;
-
- var g = linksFXLayer.graphics;
- g.clear();
- }
-
- if (newMode == InputMode.Disabled)
- {
- rootLayer.mouseChildren = false;
- rootLayer.mouseEnabled = false;
- }
- else if (inputMode == InputMode.Disabled)
- {
- rootLayer.mouseEnabled = true;
- rootLayer.mouseChildren = true;
- }
-
- if (newMode == InputMode.LinkDirection) {
-
- }
-
- inputMode = newMode;
- }
-
- public function setCreationMode(nodeModel:Node)
- {
- setMode(InputMode.CreateNode);
- tempNode = nodeModel;
- if(tempNodeUI != null)
- nodesLayer.removeChild(tempNodeUI);
- tempNodeUI = new NodeUI(tempNode);
- tempNode.ui = tempNodeUI;
- nodesLayer.addChild(tempNodeUI);
- }
-
- function setType(node:Node, newtype:NodeType)
- {
- var s = node;
- if (s == null)
- return;
- s.type = newtype;
- s.ui.reset();
- }
-
- function fixNodeCell(n:Node)
- {
- var gc = grid.worldToCell(n.pos.x, n.pos.y);
- var bcell = grid.getCell(gc.i, gc.j);
- if (bcell == null)
- {
- bcell = new Cell();
- bcell.blocking = false;
- grid.setCell(gc.i, gc.j, bcell);
- }
-
- Debug.assert(bcell.node == null);
- bcell.node = n;
- bcell.setPhero(n.owner, Settings.Gameplay.MaxPhero);
- }
-
- public function executeScriptlet(id:String)
- {
- if (level != null)
- {
- var s = level.getScriptlet(id);
- if(s != null) {
- script.executeProgram(s.program, cmdHandler);
- }
- else {
- Log.trace("WARNING: scriptlet '" + id + "' does not exist");
- }
- }
- }
-
- public function onGameLose(reason:String)
- {
- if (Settings.Cheats.NeverLose)
- return;
-
- hud.showFailDialog(reason);
- }
-
- public function getRandomBugSpawner() : BugNestNode
- {
- var list = new Array<BugNestNode>();
- for (n in nodes) {
- if (n.type == NodeType.BugNest) {
- list.push(cast(n, BugNestNode));
- }
- }
- if (list.length > 0) {
- return list[ MathUtils.randomInt(list.length) ];
- }
- return null;
- }
-
-
- ////////////
- // Inputs //
- ////////////
-
- function keydown(e:KeyboardEvent)
- {
- var code = String.fromCharCode(e.charCode);
- var kcode = String.fromCharCode(e.keyCode);
- }
-
- function mouseDown(e:Event)
- {
- }
-
- function mouseUp(e:Event)
- {
-
- }
-
- function mouseMove(e:MouseEvent)
- {
- var gm = grid.snapToGrid(rootLayer.mouseX, rootLayer.mouseY);
-
- // Links FX
- {
- if (inputMode == InputMode.CreateNode)
- {
- var g = linksFXLayer.graphics;
- g.clear();
-
- tempNode.pos.x = gm.x;
- tempNode.pos.y = gm.y;
- tempNode.owner = activePlayerIndex;
- tempNodeUI.x = gm.x;
- tempNodeUI.y = gm.y;
- tempNodeUI.reset();
-
-
- g.lineStyle(1, 0xff0000, 1);
- for (on in nodes)
- {
- if (canLinkWith(tempNode, on))
- {
- g.moveTo(gm.x, gm.y);
- g.lineTo(on.pos.x, on.pos.y);
- }
- }
- }
- }
- }
-
- function mouseClicked(e:MouseEvent)
- {
- var gm = grid.snapToGrid(rootLayer.mouseX, rootLayer.mouseY);
-
- if (inputMode == InputMode.CreateNode)
- {
- var ll:Bool = false;
- for (on in nodes)
- {
- if (canLinkWith(tempNode, on))
- {
- ll = true;
- break;
- }
- }
-
- var nn:Node = Node.createNew(tempNode.type);
- nn.copyFrom(tempNode);
- nn.owner = activePlayerIndex;
-
- if (ll) {
- addNewNode(nn);
- }
- else if(KeyboardManager.Instance.getKeyState(Keyboard.SHIFT).active){
- addNewNode(nn, true);
- }
- }
- }
-
- ////////////////
- // Simulation //
- ////////////////
-
- static function getHighestConnectedNode(node:Node): Node
- {
- var res:Node = null;
- var maxe:Float = 0;
- for (n in node.neighbours)
- {
- if (n.type == NodeType.Core)
- return n;
-
- if (!n.deleted && n.energy > maxe) {
- res = n;
- maxe = n.energy;
- }
- }
- return res;
- }
-
- static function getRandomConnectedNode(node: Node): Node
- {
- if (node.neighbours.length == 0)
- return null;
- return node.neighbours[ MathUtils.randomInt(node.neighbours.length) ];
- }
-
- function stepBugs():Void
- {
- var bugsTargetCore:Bool = properties.targetCore;
- var nScouts = 0;
-
- // TODO OPTIM: static
- var toRemove = new List<Bug>();
- for (bug in bugs)
- {
- if (bug.health < 0)
- {
- toRemove.push(bug);
- continue;
- }
-
- if (bug.type == BugType.Scout)
- nScouts++;
-
- var nextCoords = grid.worldToCell(bug.pos.x, bug.pos.y);
- var newCell = grid.getCell(nextCoords.i, nextCoords.j);
- if (newCell == null)
- {
- // TODO: should never happen
- newCell = new Cell();
- newCell.blocking = false;
- grid.setCell(nextCoords.i, nextCoords.j, newCell);
- }
-
- var cellChanged = bug.currentCoords == null || !nextCoords.equals(bug.currentCoords);
- var destcoords = bug.targetCoords;
- var stateChanged:Bool = false;
- var findNextTarget:Bool = false;
-
- var doSearch = cellChanged || bug.mustReplan;
- bug.mustReplan = false;
-
- // First step only
- if (bug.currentCoords == null)
- bug.currentCoords = nextCoords;
-
- if (bug.state == BugState.Chase)
- {
- if (cellChanged)
- {
- // Drop phero on current cell
- if (bug.type == BugType.Scout)
- {
- var pherodelt = bug.ownerPhero * Settings.Gameplay.PheroDrop;
- bug.ownerPhero -= pherodelt;
- if (newCell.getPhero(bug.ownerPlayer) < bug.ownerPhero)
- {
- newCell.setPhero(bug.ownerPlayer, bug.ownerPhero);
- }
- }
-
- // Detect pheromones
- if (bug.targetPlayer == -1)
- {
- var pheroIndex = newCell.getHighestPhero(bug.ownerPlayer);
- if (pheroIndex >= 0)
- {
- bug.targetPlayer = pheroIndex;
- }
- }
-
- // Detect proximity nodes
- var tnode = grid.getCellNode(grid.worldToCell(bug.pos.x, bug.pos.y));
- if (tnode != null && !tnode.deleted && tnode.owner != bug.ownerPlayer)
- {
- if (bug.targetPlayer == -1)
- bug.targetPlayer = tnode.owner;
-
- if (tnode.type == NodeType.Core || !bugsTargetCore)
- {
- stateChanged = true;
- if (bug.type == BugType.Scout)
- {
- bug.state = BugState.Flee;
-
- // Mark cell
- bug.targetPhero = Settings.Gameplay.MaxPhero;
- newCell.setPhero(bug.targetPlayer, bug.targetPhero);
- }
- else if (bug.attack)
- {
- // Attack starting from nearest node
- bug.targetNode = tnode;
- bug.state = BugState.Attack;
- }
-
- // Search next step
- bug.mustReplan = true;
- doSearch = false;
- }
- }
- }
-
- if (doSearch)
- {
- // Find path
- if (bug.targetPlayer == -1)
- destcoords = grid.explorePheromonePath(nextCoords, bug.ownerPlayer);
- else
- {
- destcoords = grid.findPheromonePath(nextCoords, bug.ownerPlayer, bug.targetPlayer);
-
- // Correct current phero
- if (bug.type == BugType.Scout) {
- var destCell = grid.getCell(destcoords.i, destcoords.j);
- var targetPhero = destCell.getPhero(bug.targetPlayer);
- var currentPhero = newCell.getPhero(bug.targetPlayer);
- if (targetPhero < currentPhero)
- {
- newCell.setPhero(bug.targetPlayer, Math.max(targetPhero - MathUtils.Epsilon, 0));
- }
- }
- }
- }
- }
- else if (bug.state == BugState.Flee)
- {
- if (cellChanged)
- {
- var pherodelt = bug.targetPhero * Settings.Gameplay.PheroDrop;
- bug.targetPhero -= pherodelt;
- if (newCell.getPhero(bug.targetPlayer) < bug.targetPhero)
- {
- newCell.setPhero(bug.targetPlayer, bug.targetPhero);
- }
-
- var tnode = grid.getCellNode(grid.worldToCell(bug.pos.x, bug.pos.y));
- if (tnode != null && tnode.owner == bug.ownerPlayer)
- {
- bug.state = BugState.Chase;
- stateChanged = true;
-
- // Mark cell
- bug.ownerPhero = Settings.Gameplay.MaxPhero;
- newCell.setPhero(bug.ownerPlayer, bug.ownerPhero);
-
- // Search next step
- bug.mustReplan = true;
- doSearch = false;
- }
- }
-
- if (doSearch)
- {
- destcoords = grid.findPheromonePath(nextCoords, bug.targetPlayer, bug.ownerPlayer);
-
- // Correct current phero
- var destCell = grid.getCell(destcoords.i, destcoords.j);
- var targetPhero = destCell.getPhero(bug.ownerPlayer);
- if (targetPhero < newCell.getPhero(bug.ownerPlayer))
- {
- newCell.setPhero(bug.ownerPlayer, targetPhero - MathUtils.Epsilon);
- }
- }
- }
- else if (bug.state == BugState.Attack)
- {
- if (bug.targetNode.deleted) {
- bug.state = BugState.Chase;
- bug.mustReplan = true;
- }
- else if (doSearch)
- {
- var tnode = grid.getCellNode(grid.worldToCell(bug.pos.x, bug.pos.y));
- if (tnode != null && tnode == bug.targetNode)
- {
- var doCrunch = bug.getCrunchForce() > 0 &&
- (tnode.type != NodeType.Relay || Settings.Gameplay.AttackRelays);
-
- if (doCrunch) {
- bug.state = BugState.Crunch;
- bug.crunchLastTime = time;
- destcoords = null;
- }
- else {
- findNextTarget = true;
- }
-
- if (!StringUtils.isNullOrEmpty(tnode.onHitScript)) {
- executeScriptlet(tnode.onHitScript);
- }
- }
- }
- }
- else if (bug.state == BugState.Crunch)
- {
- var ccoords = grid.worldToCell(bug.pos.x, bug.pos.y);
- var tnode = grid.getCellNode(ccoords);
- if (tnode != null && !tnode.deleted)
- {
- if (bug.crunchLastTime + bug.getCrunchDt() < time) {
- bug.crunchLastTime = time;
- var cf = bug.getCrunchForce();
- tnode.health -= cf;
- if (tnode.health < 0)
- {
- tnode.health = 0;
- if (!Settings.Cheats.DoNotKillNodes) {
- deleteNode(grid.getCell(ccoords.i, ccoords.j));
- }
- else {
- tnode.deleted = true;
- }
- tnode.state = NodeState.Idle;
- findNextTarget = true;
-
- if (!StringUtils.isNullOrEmpty(tnode.onKilledScript)) {
- executeScriptlet(tnode.onKilledScript);
- }
- }
- }
- }
- else {
- findNextTarget = true;
- }
- }
-
-
- // Find next target
- if (findNextTarget)
- {
- var ccoords = grid.worldToCell(bug.pos.x, bug.pos.y);
- var tnode = grid.getCellNode(ccoords);
- var next:Node = null;
- if (tnode != null) {
- if (MathUtils.randomInt(2) == 0)
- next = getRandomConnectedNode(tnode);
- else
- next = getHighestConnectedNode(tnode);
- }
- if (next != null) {
- bug.state = BugState.Attack;
- bug.targetNode = next;
- destcoords = grid.worldToCell(next.pos.x, next.pos.y);
- }
- else {
- bug.state = BugState.Chase;
- bug.mustReplan = true;
- }
- }
-
-
- if ((bug.state == BugState.Chase || bug.state == BugState.Flee)
- && cellChanged && !stateChanged)
- {
- // Pick random cell
- if (destcoords == null || (MathUtils.randomInt(4) == 0)) {
- destcoords = grid.getValidRandomNeighbour(nextCoords, bug.currentCoords);
- }
- }
-
- bug.currentCoords = nextCoords;
- bug.targetCoords = destcoords;
-
- if (bug.ownerPhero < MathUtils.Epsilon)
- {
- bug.ownerPhero = 0;
- toRemove.push(bug);
- continue;
- }
-
- // Move it
- if (destcoords != null)
- {
- var wp = grid.cellToWorld(destcoords.i, destcoords.j);
- var delt = wp.sub(bug.pos).norm().scale(bug.speed);
- bug.pos.addIn(delt);
- bug.orientation = delt.getAtan();
- }
- else
- {
- // Not moving
- }
- }
- for (bug in toRemove)
- {
- removeBug(bug);
- }
-
- // Ajust scouts number !
- if (nScouts < properties.autoSpawnScouts)
- {
- var target = getRandomBugSpawner();
- if (target != null && (time - target.lastSpawnTime) > properties.autoSpawnInterval) {
- spawnBug(target, BugType.Scout);
- }
- }
- }
-
- // Update nodes
- function stepNodes()
- {
- var dt:Float = Settings.Gameplay.StepDuration;
- var totalConsumption = 0.0;
- var totalEnergy = 0.0;
- var anyActiveNode:Bool = false;
-
- for (node in nodes)
- {
- if (node.state == NodeState.Creation)
- continue;
- if (node.deleted)
- continue;
-
- if (node.owner == activePlayerIndex &&
- (!Settings.Gameplay.AttackRelays || node.type != NodeType.Relay))
- anyActiveNode = true;
-
- var searchResource = false;
-
- if (node.type == NodeType.Generator)
- {
- var de = node.getProperty("Rate") * dt;
- node.energy += de;
- var cap = node.getCapacity();
- if (node.energy > cap) {
- node.energy = cap;
- }
- }
- else if (node.type == NodeType.Relay)
- {
- searchResource = true;
- }
- else if (node.type == NodeType.Microwave)
- {
- var ecost:Float = node.getProperty("Consumption") * dt;
- var nhit:Float = node.getProperty("Force") * dt;
- var nrange = node.getProperty("Range") * Settings.Gameplay.HexSize;
-
- node.state = NodeState.Idle;
- if (node.energy >= ecost)
- {
- for (bug in bugs)
- {
- if (MathUtils.isDistanceSmaller(bug.pos.x, bug.pos.y, node.pos.x, node.pos.y, nrange))
- {
- bug.health -= nhit;
- node.state = NodeState.Attack;
- }
- }
- }
-
- if (node.state == NodeState.Attack)
- {
- node.energy -= ecost;
- }
- }
- else if (node.type == NodeType.Ray)
- {
- var raynode = cast(node, RayNode);
- var ecost:Float = node.getProperty("Consumption") * dt;
- var nhit:Float = node.getProperty("Force") * dt;
- var nrange = node.getProperty("Range") * Settings.Gameplay.HexSize;
- var maxrays:Int = node.getPropertyInt("NumRays");
- var nrays:Int = 0;
-
- node.state = NodeState.Idle;
- if (node.energy >= ecost)
- {
- raynode.target = null;
- var highestHP:Float = 0;
- for (bug in bugs) {
- if (bug.type == BugType.Scout && !raynode.attackScouts)
- continue;
-
- if (MathUtils.isDistanceSmaller(bug.pos.x, bug.pos.y, node.pos.x, node.pos.y, nrange)) {
- if (bug.getHP() > highestHP) {
- node.state = NodeState.Attack;
- raynode.target = bug;
- highestHP = bug.getHP();
- }
- }
- }
- if (raynode.target != null) {
- raynode.target.health -= nhit;
- }
- }
-
- if(node.state == NodeState.Attack)
- {
- node.energy -= ecost;
- }
- }
- else if (node.type == NodeType.Accumulator)
- {
- searchResource = true;
- }
-
- if (searchResource)
- {
- var nc = node.closestResCell;
- if (nc == null || grid.getCell(nc.i, nc.j) == null)
- {
- nc = grid.findClosestEnergyCell(node.pos, grid.HexSize * 3);
- node.closestResCell = nc;
- }
-
- if (nc != null)
- {
- var cell = grid.getCell(nc.i, nc.j);
-
- // Consume
- var delta = 30.0 * dt;
- if (delta > cell.energy)
- delta = cell.energy;
- if (node.energy + delta > node.getCapacity())
- delta = node.getCapacity() - node.energy;
-
- if (delta > 0)
- {
- cell.energy -= delta;
- node.energy += delta;
- }
-
- #if debug
- if (Math.isNaN(cell.energy))
- {
- Log.trace("OMG");
- }
- #end
-
- if (cell.energy < MathUtils.Epsilon)
- {
- cell.ui.rebuild();
- node.closestResCell = null;
- }
- }
- }
- totalEnergy += node.energy;
- }
-
- if (level != null)
- {
- if (!anyActiveNode) {
- onGameLose("All units killed lol");
- }
- }
- }
- }
-