[Scummvm-cvs-logs] scummvm master -> ad04376054f9734d81099b36b013478498364cb3

sev- sev at scummvm.org
Sun May 22 00:45:20 CEST 2016


This automated email contains information about 11 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
4ed193b51e SCUMM HE: Documented more opcodes
9d60209a33 SCUMM HE: Initial stub for Moonbase AI
adc884ae8f SCUMM HE: AIEntity class implementation
33a0afc8f8 SCUMM HE: Added Weapon class
412ae07efb SCUMM HE: Added Moonbase Node class
e4de5bf9ce SCUMM HE: Added implementation for Sortie and DefenderUnit classes
bb88aaf119 SCUMM HE: Added Moonbase Traveller class
26b5416433 SCUMM HE: Moved Moonbase stuff to v90he
44333f7453 SCUMM HE: Added main Moonbase AI code
441f630ec5 SCUMM HE: Added stub for Tree class
ad04376054 SCUMM HE: Cleanup


Commit: 4ed193b51e62891fca2c79b2195aacb83c9b65fb
    https://github.com/scummvm/scummvm/commit/4ed193b51e62891fca2c79b2195aacb83c9b65fb
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2016-05-22T00:45:02+02:00

Commit Message:
SCUMM HE: Documented more opcodes

Changed paths:
    engines/scumm/he/script_v100he.cpp



diff --git a/engines/scumm/he/script_v100he.cpp b/engines/scumm/he/script_v100he.cpp
index 053d1bd..cd807f0 100644
--- a/engines/scumm/he/script_v100he.cpp
+++ b/engines/scumm/he/script_v100he.cpp
@@ -942,10 +942,10 @@ void ScummEngine_v100he::o100_setSpriteGroupInfo() {
 	byte subOp = fetchScriptByte();
 
 	switch (subOp) {
-	case 0:
+	case 0: // SO_INIT
 		_curSpriteGroupId = pop();
 		break;
-	case 6:
+	case 6: // SO_MOVE
 		value2 = pop();
 		value1 = pop();
 		if (!_curSpriteGroupId)
@@ -953,7 +953,7 @@ void ScummEngine_v100he::o100_setSpriteGroupInfo() {
 
 		_sprite->setGroupPosition(_curSpriteGroupId, value1, value2);
 		break;
-	case 18:
+	case 18: // SO_CLIPPED
 		value4 = pop();
 		value3 = pop();
 		value2 = pop();
@@ -963,10 +963,10 @@ void ScummEngine_v100he::o100_setSpriteGroupInfo() {
 
 		_sprite->setGroupBounds(_curSpriteGroupId, value1, value2, value3, value4);
 		break;
-	case 38:
+	case 38: // SO_GROUP
 		type = pop() - 1;
 		switch (type) {
-		case 0:
+		case 0: // SPRGRPOP_MOVE
 			value2 = pop();
 			value1 = pop();
 			if (!_curSpriteGroupId)
@@ -974,48 +974,48 @@ void ScummEngine_v100he::o100_setSpriteGroupInfo() {
 
 			_sprite->moveGroupMembers(_curSpriteGroupId, value1, value2);
 			break;
-		case 1:
+		case 1: // SPRGRPOP_ORDER
 			value1 = pop();
 			if (!_curSpriteGroupId)
 				break;
 
 			_sprite->setGroupMembersPriority(_curSpriteGroupId, value1);
 			break;
-		case 2:
+		case 2: // SPRGRPOP_NEW_GROUP
 			value1 = pop();
 			if (!_curSpriteGroupId)
 				break;
 
 			_sprite->setGroupMembersGroup(_curSpriteGroupId, value1);
 			break;
-		case 3:
+		case 3: // SPRGRPOP_UPDATE_TYPE
 			value1 = pop();
 			if (!_curSpriteGroupId)
 				break;
 
 			_sprite->setGroupMembersUpdateType(_curSpriteGroupId, value1);
 			break;
-		case 4:
+		case 4: // SPRGRPOP_NEW
 			if (!_curSpriteGroupId)
 				break;
 
 			_sprite->setGroupMembersResetSprite(_curSpriteGroupId);
 			break;
-		case 5:
+		case 5: // SPRGRPOP_ANIMATION_SPEED
 			value1 = pop();
 			if (!_curSpriteGroupId)
 				break;
 
 			_sprite->setGroupMembersAnimationSpeed(_curSpriteGroupId, value1);
 			break;
-		case 6:
+		case 6: // SPRGRPOP_ANIMATION_TYPE
 			value1 = pop();
 			if (!_curSpriteGroupId)
 				break;
 
 			_sprite->setGroupMembersAutoAnimFlag(_curSpriteGroupId, value1);
 			break;
-		case 7:
+		case 7: // SPRGRPOP_SHADOW
 			value1 = pop();
 			if (!_curSpriteGroupId)
 				break;
@@ -1026,14 +1026,14 @@ void ScummEngine_v100he::o100_setSpriteGroupInfo() {
 			error("o100_setSpriteGroupInfo subOp 38: Unknown case %d", subOp);
 		}
 		break;
-	case 40:
+	case 40: // SO_IMAGE
 		value1 = pop();
 		if (!_curSpriteGroupId)
 			break;
 
 		_sprite->setGroupImage(_curSpriteGroupId, value1);
 		break;
-	case 49:
+	case 49: // SO_AT
 		value2 = pop();
 		value1 = pop();
 		if (!_curSpriteGroupId)
@@ -1041,51 +1041,51 @@ void ScummEngine_v100he::o100_setSpriteGroupInfo() {
 
 		_sprite->moveGroup(_curSpriteGroupId, value1, value2);
 		break;
-	case 52:
+	case 52: // SO_NAME
 		copyScriptString(string, sizeof(string));
 		break;
-	case 53:
+	case 53: // SO_NEW
 		if (!_curSpriteGroupId)
 			break;
 
 		_sprite->resetGroup(_curSpriteGroupId);
 		break;
-	case 54:
+	case 54: // SO_NEW_GENERAL_PROPERTY
 		// dummy case
 		pop();
 		pop();
 		break;
-	case 59:
+	case 59: // SO_PRIORITY
 		value1 = pop();
 		if (!_curSpriteGroupId)
 			break;
 
 		_sprite->setGroupPriority(_curSpriteGroupId, value1);
 		break;
-	case 60:
+	case 60: // SO_PROPERTY
 		type = pop();
 		value1 = pop();
 		if (!_curSpriteGroupId)
 			break;
 
 		switch (type) {
-		case 0:
+		case 0: // SPRGRPPROP_XMUL
 			_sprite->setGroupXMul(_curSpriteGroupId, value1);
 			break;
-		case 1:
+		case 1: // SPRGRPPROP_XDIV
 			_sprite->setGroupXDiv(_curSpriteGroupId, value1);
 			break;
-		case 2:
+		case 2: // SPRGRPPROP_YMUL
 			_sprite->setGroupYMul(_curSpriteGroupId, value1);
 			break;
-		case 3:
+		case 3: // SPRGRPPROP_YDIV
 			_sprite->setGroupYDiv(_curSpriteGroupId, value1);
 			break;
 		default:
 			error("o100_setSpriteGroupInfo subOp 60: Unknown case %d", subOp);
 		}
 		break;
-	case 89:
+	case 89: // SO_NEVER_ZCLIP
 		if (!_curSpriteGroupId)
 			break;
 


Commit: 9d60209a33d2eab4075662e9ed4f1e9215c719a2
    https://github.com/scummvm/scummvm/commit/9d60209a33d2eab4075662e9ed4f1e9215c719a2
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2016-05-22T00:45:03+02:00

Commit Message:
SCUMM HE: Initial stub for Moonbase AI

Changed paths:
  A engines/scumm/he/moonbase/ai_defenseunit.cpp
  A engines/scumm/he/moonbase/ai_defenseunit.h
  A engines/scumm/he/moonbase/ai_main.h
  A engines/scumm/he/moonbase/ai_node.h
  A engines/scumm/he/moonbase/ai_tree.h
    engines/scumm/he/moonbase/moonbase.h
    engines/scumm/module.mk



diff --git a/engines/scumm/he/moonbase/ai_defenseunit.cpp b/engines/scumm/he/moonbase/ai_defenseunit.cpp
new file mode 100644
index 0000000..1312752
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_defenseunit.cpp
@@ -0,0 +1,759 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/rect.h"
+#include "common/util.h"
+#include "scumm/scumm.h"
+#include "scumm/he/moonbase/ai_defenseunit.h"
+#include "scumm/he/moonbase/ai_main.h"
+
+namespace Scumm {
+
+DefenseUnit::DefenseUnit() {
+	m_state = DUS_ON;
+}
+
+DefenseUnit::DefenseUnit(DefenseUnit *inUnit) {
+	m_ID = inUnit->getID();
+	m_pos.x = inUnit->getPosX();
+	m_pos.y = inUnit->getPosY();
+	m_distanceTo = inUnit->getDistanceTo();
+	m_state = inUnit->getState();
+	m_radius = inUnit->getRadius();
+	m_armor = inUnit->getArmor();
+}
+
+DefenseUnit::~DefenseUnit() {
+}
+
+Common::Point *AntiAirUnit::createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY) {
+	float ratio;
+	int radius;
+	Common::Point *targetPos = new Common::Point;
+
+	if (!distance) distance = 1;
+
+	switch (weaponType) {
+	case ITEM_BOMB:
+		targetPos->x = getPosX();
+		targetPos->y = getPosY();
+		break;
+
+	case ITEM_CLUSTER:
+		targetPos->x = getPosX();
+		targetPos->y = getPosY();
+		break;
+
+	case ITEM_CRAWLER:
+		radius = getRadius();
+
+		if ((distance < radius) || (getState() == DUS_OFF)) {
+			targetPos->x = getPosX();
+			targetPos->y = getPosY();
+		} else {
+			ratio = MAX(0, (getRadius() / distance));
+			targetPos->x = getPosX() - ratio * (getPosX() - sourceX);
+			targetPos->y = getPosY() - ratio * (getPosY() - sourceY);
+		}
+
+		break;
+
+	case ITEM_EMP:
+		if (getRadius() + 215 > distance) { //emp radius
+			double x1 = static_cast<double>(sourceX);
+			double y1 = static_cast<double>(sourceY);
+			double x2 = static_cast<double>(getPosX());
+			double y2 = static_cast<double>(getPosY());
+			double r1 = static_cast<double>(215);
+			double r2 = static_cast<double>(getRadius() + 3);
+			double d = static_cast<double>(distance);
+
+			//formulae for calculating one point of intersection of two circles
+			float root = sqrt((((r1 + r2) * (r1 + r2)) - (d * d)) * ((d * d) - ((r2 - r1) * (r2 - r1))));
+			int x = ((x1 + x2) / 2) + ((x2 - x1) * (r1 * r1 - r2 * r2)) / (2 * d * d) + ((y2 - y1) / (2 * d * d)) * root;
+			int y = ((y1 + y2) / 2) + ((y2 - y1) * (r1 * r1 - r2 * r2)) / (2 * d * d) - ((x2 - x1) / (2 * d * d)) * root;
+
+			targetPos->x = x;
+			targetPos->y = y;
+		} else {
+			ratio = 1 - (getRadius() / static_cast<float>(distance - 20));
+			targetPos->x = sourceX + ratio * (getPosX() - sourceX);
+			targetPos->y = sourceY + ratio * (getPosY() - sourceY);
+		}
+
+		break;
+
+	default:
+		targetPos->x = getPosX();
+		targetPos->y = getPosY();
+		break;
+	}
+
+	return targetPos;
+}
+
+int AntiAirUnit::selectWeapon(int index) {
+	switch (index) {
+	case 0:
+		return ITEM_CLUSTER;
+		break;
+
+	case 1:
+		return ITEM_EMP;
+		break;
+
+	case 2:
+		if (getState() == DUS_OFF) {
+			if (GetPlayerEnergy() > 6) {
+				if (!_vm->_rnd.getRandomNumber(3)) {
+					return ITEM_VIRUS;
+				}
+			}
+
+			if (GetPlayerEnergy() > 2) {
+				if (!_vm->_rnd.getRandomNumber(1)) {
+					return ITEM_SPIKE;
+				}
+			}
+
+			return ITEM_BOMB;
+		}
+
+		return ITEM_CLUSTER;
+		break;
+
+	default:
+		return ITEM_CLUSTER;
+		break;
+	}
+}
+
+Common::Point *ShieldUnit::createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY) {
+	float ratio;
+	Common::Point *targetPos = new Common::Point;
+
+	if (getState() == DUS_OFF) {
+		targetPos->x = getPosX();
+		targetPos->y = getPosY();
+	} else {
+		switch (weaponType) {
+		case ITEM_BOMB:
+			targetPos->x = getPosX();
+			targetPos->y = getPosY();
+			break;
+
+		case ITEM_CLUSTER:
+			targetPos->x = getPosX();
+			targetPos->y = getPosY();
+			break;
+
+		case ITEM_CRAWLER:
+			ratio = MAX(0.0, 1.0 - (static_cast<float>(getRadius()) / static_cast<float>(distance - 20)));
+			{
+				int maxX = GetMaxX();
+				int maxY = GetMaxY();
+				int thisX = (static_cast<int>(sourceX + ratio * (getPosX() - sourceX)) + maxX) % maxX;
+				int thisY = (static_cast<int>(sourceY + ratio * (getPosY() - sourceY)) + maxY) % maxY;
+				targetPos->x = thisX;
+				targetPos->y = thisY;
+			}
+			break;
+
+		case ITEM_EMP:
+			if (getRadius() + 215 > distance) { //emp radius
+				double x1 = static_cast<double>(sourceX);
+				double y1 = static_cast<double>(sourceY);
+				double x2 = static_cast<double>(getPosX());
+				double y2 = static_cast<double>(getPosY());
+				double r1 = static_cast<double>(215);
+				double r2 = static_cast<double>(getRadius() + 10);
+				double d = static_cast<double>(distance);
+
+				//formulae for calculating one point of intersection of two circles
+				float root = sqrt((((r1 + r2) * (r1 + r2)) - (d * d)) * ((d * d) - ((r2 - r1) * (r2 - r1))));
+				int x = ((x1 + x2) / 2) + ((x2 - x1) * (r1 * r1 - r2 * r2)) / (2 * d * d) + ((y2 - y1) / (2 * d * d)) * root;
+				int y = ((y1 + y2) / 2) + ((y2 - y1) * (r1 * r1 - r2 * r2)) / (2 * d * d) - ((x2 - x1) / (2 * d * d)) * root;
+
+				targetPos->x = x;
+				targetPos->y = y;
+			} else {
+				ratio = 1 - (getRadius() / static_cast<float>(distance - 20));
+				targetPos->x = sourceX + ratio * (getPosX() - sourceX);
+				targetPos->y = sourceY + ratio * (getPosY() - sourceY);
+			}
+
+			if (distance < getRadius()) {
+				targetPos->x = getPosX();
+				targetPos->y = getPosY();
+			}
+
+			break;
+
+		default:
+			targetPos->x = getPosX();
+			targetPos->y = getPosY();
+			break;
+		}
+	}
+
+	return targetPos;
+}
+
+int ShieldUnit::selectWeapon(int index) {
+	warning("Shield weapon select");
+
+	int myUnit = GetClosestUnit(getPosX(), getPosY(), GetMaxX(), GetCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, 0);
+	int dist = GetDistance(getPosX(), getPosY(), GetHubX(myUnit), GetHubY(myUnit));
+
+	if ((dist < (getRadius() - 20)) && (dist > 90)) {
+		return ITEM_SPIKE;
+	}
+
+	switch (index) {
+	case 0:
+		if (getState() == DUS_OFF)  {
+			if (GetPlayerEnergy() < 3) {
+				return ITEM_BOMB;
+			} else {
+				return ITEM_SPIKE;
+			}
+		}
+
+		return ITEM_EMP;
+		break;
+
+	case 1:
+		if (dist < getRadius() + 150) {
+			return ITEM_EMP;
+		} else {
+			return ITEM_CRAWLER;
+		}
+
+		break;
+
+	default:
+		return ITEM_EMP;
+		break;
+	}
+}
+
+Common::Point *MineUnit::createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY) {
+	float ratio;
+	Common::Point *targetPos = new Common::Point;
+
+	switch (weaponType) {
+	case ITEM_BOMB:
+		targetPos->x = getPosX();
+		targetPos->y = getPosY();
+		break;
+
+	case ITEM_CLUSTER:
+		targetPos->x = getPosX();
+		targetPos->y = getPosY();
+		break;
+
+	case ITEM_EMP:
+		ratio = 1 - (getRadius() / static_cast<float>(distance - 20));
+		targetPos->x = sourceX + ratio * (getPosX() - sourceX);
+		targetPos->y = sourceY + ratio * (getPosY() - sourceY);
+		break;
+
+	default:
+		targetPos->x = getPosX();
+		targetPos->y = getPosY();
+		break;
+	}
+
+	return targetPos;
+}
+
+int MineUnit::selectWeapon(int index) {
+	int myUnit = GetClosestUnit(getPosX(), getPosY(), GetMaxX(), GetCurrentPlayer(), 1, 0, 0, 0);
+	int x = getPosX();
+	int y = getPosY();
+
+	int dist = GetDistance(x, y, GetHubX(myUnit), GetHubY(myUnit));
+
+	if ((getState() == DUS_ON) && (dist < 110)) {
+		return ITEM_EMP;
+	} else {
+		return ITEM_BOMB;
+	}
+}
+
+
+Common::Point *HubUnit::createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY) {
+	Common::Point *targetPos = new Common::Point;
+
+	if (!distance) distance = 1;
+
+	switch (weaponType) {
+	case ITEM_BOMB:
+		targetPos->x = getPosX();
+		targetPos->y = getPosY();
+		break;
+
+	case ITEM_CLUSTER:
+		targetPos->x = getPosX();
+		targetPos->y = getPosY();
+		break;
+
+	case ITEM_CRAWLER:
+		targetPos->x = getPosX();
+		targetPos->y = getPosY();
+		break;
+
+	default:
+		targetPos->x = getPosX();
+		targetPos->y = getPosY();
+		break;
+	}
+
+	return targetPos;
+}
+
+int HubUnit::selectWeapon(int index) {
+	warning("Hub weapon select");
+
+	int energy = GetPlayerEnergy();
+
+	if (energy > 6) {
+		//possibly choose crawler
+		if (GetBuildingWorth(getID()) > 21) {
+			return ITEM_CRAWLER;
+		}
+	}
+
+	//choose betw/ bomb and cluster
+	if (GetBuildingArmor(getID()) < 1.5) {
+		return ITEM_CLUSTER;
+	}
+
+	if (energy > 2) {
+		if (!_vm->_rnd.getRandomNumber(3)) {
+			return ITEM_SPIKE;
+		}
+
+		if (!_vm->_rnd.getRandomNumber(4)) {
+			return ITEM_GUIDED;
+		}
+
+		if (!_vm->_rnd.getRandomNumber(4)) {
+			return ITEM_MINE;
+		}
+
+		if (!_vm->_rnd.getRandomNumber(9)) {
+			return ITEM_EMP;
+		}
+	}
+
+	return ITEM_BOMB;
+}
+
+
+Common::Point *TowerUnit::createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY) {
+	Common::Point *targetPos = new Common::Point;
+
+	if (!distance) distance = 1;
+
+	switch (weaponType) {
+	case ITEM_BOMB:
+		targetPos->x = getPosX();
+		targetPos->y = getPosY();
+		break;
+
+	case ITEM_SPIKE:
+		targetPos->x = getPosX();
+		targetPos->y = getPosY();
+		break;
+
+	default:
+		targetPos->x = getPosX();
+		targetPos->y = getPosY();
+		break;
+	}
+
+	return targetPos;
+}
+
+int TowerUnit::selectWeapon(int index) {
+	switch (index) {
+	case 0:
+		return ITEM_SPIKE;
+		break;
+
+	default:
+		return ITEM_SPIKE;
+		break;
+	}
+}
+
+
+Common::Point *BridgeUnit::createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY) {
+	Common::Point *targetPos = new Common::Point;
+
+	if (!distance) distance = 1;
+
+	switch (weaponType) {
+	case ITEM_BOMB:
+		targetPos->x = getPosX();
+		targetPos->y = getPosY();
+		break;
+
+	case ITEM_CLUSTER:
+		targetPos->x = getPosX();
+		targetPos->y = getPosY();
+		break;
+
+	default:
+		targetPos->x = getPosX();
+		targetPos->y = getPosY();
+		break;
+	}
+
+	return targetPos;
+}
+
+int BridgeUnit::selectWeapon(int index) {
+	switch (index) {
+	case 0:
+		return ITEM_BOMB;
+		break;
+
+	case 1:
+		return ITEM_CLUSTER;
+		break;
+
+	default:
+		return ITEM_BOMB;
+		break;
+	}
+}
+
+
+Common::Point *EnergyUnit::createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY) {
+	Common::Point *targetPos = new Common::Point;
+
+	if (!distance) distance = 1;
+
+	switch (weaponType) {
+	case ITEM_BOMB:
+		targetPos->x = getPosX();
+		targetPos->y = getPosY();
+		break;
+
+	case ITEM_CLUSTER:
+		targetPos->x = getPosX();
+		targetPos->y = getPosY();
+		break;
+
+	case ITEM_CRAWLER:
+		targetPos->x = getPosX();
+		targetPos->y = getPosY();
+		break;
+
+	default:
+		targetPos->x = getPosX();
+		targetPos->y = getPosY();
+		break;
+	}
+
+	return targetPos;
+}
+
+int EnergyUnit::selectWeapon(int index) {
+	warning("Energy weapon select");
+
+	int energy = GetPlayerEnergy();
+
+	if (energy > 6) {
+		//possibly choose crawler
+		if (GetBuildingWorth(getID()) > 21) {
+			return ITEM_CRAWLER;
+		}
+	}
+
+	//choose betw/ bomb and cluster
+	if (GetBuildingArmor(getID()) < 1.5) {
+		return ITEM_CLUSTER;
+	}
+
+	if (energy > 2) {
+		if (!_vm->_rnd.getRandomNumber(3)) {
+			return ITEM_EMP;
+		}
+	}
+
+	return ITEM_BOMB;
+}
+
+Common::Point *OffenseUnit::createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY) {
+	Common::Point *targetPos = new Common::Point;
+
+	if (!distance) distance = 1;
+
+	switch (weaponType) {
+	case ITEM_BOMB:
+		targetPos->x = getPosX();
+		targetPos->y = getPosY();
+		break;
+
+	case ITEM_CLUSTER:
+		targetPos->x = getPosX();
+		targetPos->y = getPosY();
+		break;
+
+	case ITEM_CRAWLER:
+		targetPos->x = getPosX();
+		targetPos->y = getPosY();
+		break;
+
+	default:
+		targetPos->x = getPosX();
+		targetPos->y = getPosY();
+		break;
+	}
+
+	return targetPos;
+}
+
+int OffenseUnit::selectWeapon(int index) {
+	warning("Offense weapon select");
+
+	int energy = GetPlayerEnergy();
+
+	if (energy > 6) {
+		//possibly choose crawler
+		if (GetBuildingWorth(getID()) > 21) {
+			return ITEM_CRAWLER;
+		}
+	}
+
+	//choose betw/ bomb and cluster
+	if (GetBuildingArmor(getID()) < 1.5) {
+		return ITEM_CLUSTER;
+	}
+
+	return ITEM_BOMB;
+}
+
+Common::Point *CrawlerUnit::createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY) {
+	Common::Point *targetPos = new Common::Point;
+
+	if (!distance)
+		distance = 1;
+
+	switch (weaponType) {
+	case ITEM_BOMB:
+		targetPos->x = getPosX();
+		targetPos->y = getPosY();
+		break;
+
+	case ITEM_CLUSTER:
+		targetPos->x = getPosX();
+		targetPos->y = getPosY();
+		break;
+
+	case ITEM_CRAWLER:
+		targetPos->x = getPosX();
+		targetPos->y = getPosY();
+		break;
+
+	default:
+		targetPos->x = getPosX();
+		targetPos->y = getPosY();
+		break;
+	}
+
+	return targetPos;
+}
+
+int CrawlerUnit::selectWeapon(int index) {
+	warning("Crawler weapon select");
+	int myUnit = GetClosestUnit(getPosX(), getPosY(), GetMaxX(), GetCurrentPlayer(), 1, 0, 0, 0);
+	int dist = GetDistance(GetHubX(myUnit), GetHubY(myUnit), getPosX(), getPosY());
+
+	int x = getPosX();
+	int y = getPosY();
+	int energy = GetPlayerEnergy();
+	int terrain = GetTerrain(x, y);
+
+	if (terrain != TERRAIN_TYPE_WATER) {
+		if ((energy > 2) && (dist < 220)) {
+			return ITEM_RECLAIMER;
+		} else {
+			return ITEM_BOMB;
+		}
+	} else {
+		if (energy > 6) {
+			return ITEM_CRAWLER;
+		}
+
+		if (energy > 2) {
+			if (_vm->_rnd.getRandomNumber(1)) {
+				return ITEM_MINE;
+			} else {
+				return ITEM_TIME_EXPIRED;
+			}
+		}
+	}
+
+	return SKIP_TURN;
+}
+
+AntiAirUnit::AntiAirUnit() {
+	setRadius(190);
+	setArmor(3);
+	setCost(1);
+}
+
+ShieldUnit::ShieldUnit() {
+	setRadius(170);
+	setArmor(3);
+	setCost(7);
+}
+
+MineUnit::MineUnit() {
+	setRadius(80);
+	setArmor(1);
+	setCost(3);
+}
+
+HubUnit::HubUnit() {
+	setRadius(1);
+	setArmor(5);
+	setCost(7);
+}
+
+TowerUnit::TowerUnit() {
+	setRadius(1);
+	setArmor(3);
+	setCost(1);
+}
+
+BridgeUnit::BridgeUnit() {
+	setRadius(1);
+	setArmor(3);
+	setCost(1);
+}
+
+EnergyUnit::EnergyUnit() {
+	setRadius(1);
+	setArmor(5);
+	setCost(7);
+}
+
+OffenseUnit::OffenseUnit() {
+	setRadius(1);
+	setArmor(3);
+	setCost(7);
+}
+
+CrawlerUnit::CrawlerUnit() {
+	setRadius(1);
+	setArmor(3);
+	setCost(7);
+}
+
+AntiAirUnit::AntiAirUnit(DefenseUnit *inUnit) : DefenseUnit(inUnit) {
+	setID(inUnit->getID());
+	setPos(inUnit->getPosX(), inUnit->getPosY());
+	setDistanceTo(inUnit->getDistanceTo());
+	setState(inUnit->getState());
+	setRadius(inUnit->getRadius());
+	setArmor(inUnit->getArmor());
+
+}
+
+ShieldUnit::ShieldUnit(DefenseUnit *inUnit) : DefenseUnit(inUnit) {
+	setID(inUnit->getID());
+	setPos(inUnit->getPosX(), inUnit->getPosY());
+	setDistanceTo(inUnit->getDistanceTo());
+	setState(inUnit->getState());
+	setRadius(inUnit->getRadius());
+	setArmor(inUnit->getArmor());
+}
+
+MineUnit::MineUnit(DefenseUnit *inUnit) : DefenseUnit(inUnit) {
+	setID(inUnit->getID());
+	setPos(inUnit->getPosX(), inUnit->getPosY());
+	setDistanceTo(inUnit->getDistanceTo());
+	setState(inUnit->getState());
+	setRadius(inUnit->getRadius());
+	setArmor(inUnit->getArmor());
+}
+
+HubUnit::HubUnit(DefenseUnit *inUnit) : DefenseUnit(inUnit) {
+	setID(inUnit->getID());
+	setPos(inUnit->getPosX(), inUnit->getPosY());
+	setDistanceTo(inUnit->getDistanceTo());
+	setState(inUnit->getState());
+	setRadius(inUnit->getRadius());
+	setArmor(inUnit->getArmor());
+}
+
+TowerUnit::TowerUnit(DefenseUnit *inUnit) : DefenseUnit(inUnit) {
+	setID(inUnit->getID());
+	setPos(inUnit->getPosX(), inUnit->getPosY());
+	setDistanceTo(inUnit->getDistanceTo());
+	setState(inUnit->getState());
+	setRadius(inUnit->getRadius());
+	setArmor(inUnit->getArmor());
+}
+
+BridgeUnit::BridgeUnit(DefenseUnit *inUnit) : DefenseUnit(inUnit) {
+	setID(inUnit->getID());
+	setPos(inUnit->getPosX(), inUnit->getPosY());
+	setDistanceTo(inUnit->getDistanceTo());
+	setState(inUnit->getState());
+	setRadius(inUnit->getRadius());
+	setArmor(inUnit->getArmor());
+}
+
+EnergyUnit::EnergyUnit(DefenseUnit *inUnit) : DefenseUnit(inUnit) {
+	setID(inUnit->getID());
+	setPos(inUnit->getPosX(), inUnit->getPosY());
+	setDistanceTo(inUnit->getDistanceTo());
+	setState(inUnit->getState());
+	setRadius(inUnit->getRadius());
+	setArmor(inUnit->getArmor());
+}
+
+OffenseUnit::OffenseUnit(DefenseUnit *inUnit) : DefenseUnit(inUnit) {
+	setID(inUnit->getID());
+	setPos(inUnit->getPosX(), inUnit->getPosY());
+	setDistanceTo(inUnit->getDistanceTo());
+	setState(inUnit->getState());
+	setRadius(inUnit->getRadius());
+	setArmor(inUnit->getArmor());
+}
+
+CrawlerUnit::CrawlerUnit(DefenseUnit *inUnit) : DefenseUnit(inUnit) {
+	setID(inUnit->getID());
+	setPos(inUnit->getPosX(), inUnit->getPosY());
+	setDistanceTo(inUnit->getDistanceTo());
+	setState(inUnit->getState());
+	setRadius(inUnit->getRadius());
+	setArmor(inUnit->getArmor());
+}
+
+} // End of namespace Scumm
diff --git a/engines/scumm/he/moonbase/ai_defenseunit.h b/engines/scumm/he/moonbase/ai_defenseunit.h
new file mode 100644
index 0000000..bc4c79a
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_defenseunit.h
@@ -0,0 +1,190 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef SCUMM_HE_MOONBASE_AI_DEFENCEUNIT_H
+#define SCUMM_HE_MOONBASE_AI_DEFENCEUNIT_H
+
+namespace Scumm {
+
+enum {
+	DUT_ANTI_AIR = 1,
+	DUT_SHIELD = 2,
+	DUT_MINE = 3,
+	DUT_HUB = 4,
+	DUT_TOWER = 5,
+	DUT_BRIDGE = 6,
+	DUT_ENERGY = 7,
+	DUT_OFFENSE = 8,
+	DUT_CRAWLER = 9
+};
+
+enum {
+	DUS_ON = 1,
+	DUS_OFF = 2,
+	DUS_DESTROYED = 3
+};
+
+class DefenseUnit {
+private:
+	int m_ID;
+	Common::Point m_pos;
+	int m_distanceTo;
+	int m_state;
+	int m_radius;
+	int m_armor;
+	int m_cost;
+
+public:
+	DefenseUnit();
+	DefenseUnit(DefenseUnit *inUnit);
+
+	virtual ~DefenseUnit();
+
+	void setID(int id) { m_ID = id; }
+	void setDistanceTo(int distanceTo) { m_distanceTo = distanceTo; }
+	void setState(int state) { m_state = state; }
+	void setRadius(int radius) { m_radius = radius; }
+	void setArmor(int armor) { m_armor = armor; }
+	void setDamage(int damage) { m_armor -= damage; }
+	void setPos(int x, int y) {
+		m_pos.x = x;
+		m_pos.y = y;
+	}
+	void setCost(int cost) { m_cost = cost; }
+
+	int getID() const { return m_ID; }
+	int getDistanceTo() const { return m_distanceTo; }
+	int getState() const { return m_state; }
+	int getRadius() const { return m_radius; }
+	int getArmor() const { return m_armor; }
+	int getPosX() const { return m_pos.x; }
+	int getPosY() const { return m_pos.y; }
+	int getCost() const { return m_cost; }
+
+	virtual int getType() const = 0;
+
+	virtual Common::Point *createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY) = 0;
+	virtual int selectWeapon(int index) = 0;
+};
+
+class AntiAirUnit : public DefenseUnit {
+private:
+
+public:
+	AntiAirUnit();
+	AntiAirUnit(DefenseUnit *inUnit);
+	int getType() const { return DUT_ANTI_AIR; }
+	Common::Point *createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY);
+	int selectWeapon(int index);
+};
+
+class ShieldUnit : public DefenseUnit {
+private:
+
+public:
+	ShieldUnit();
+	ShieldUnit(DefenseUnit *inUnit);
+	int getType() const { return DUT_SHIELD; }
+	Common::Point *createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY);
+	int selectWeapon(int index);
+};
+
+class MineUnit : public DefenseUnit {
+private:
+
+public:
+	MineUnit();
+	MineUnit(DefenseUnit *inUnit);
+	int getType() const { return DUT_MINE; }
+	Common::Point *createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY);
+	int selectWeapon(int index);
+};
+
+class HubUnit : public DefenseUnit {
+private:
+
+public:
+	HubUnit();
+	HubUnit(DefenseUnit *inUnit);
+	int getType() const { return DUT_HUB; }
+	Common::Point *createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY);
+	int selectWeapon(int index);
+};
+
+class TowerUnit : public DefenseUnit {
+private:
+
+public:
+	TowerUnit();
+	TowerUnit(DefenseUnit *inUnit);
+	int getType() const { return DUT_TOWER; }
+	Common::Point *createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY);
+	int selectWeapon(int index);
+};
+
+class BridgeUnit : public DefenseUnit {
+private:
+
+public:
+	BridgeUnit();
+	BridgeUnit(DefenseUnit *inUnit);
+	int getType() const { return DUT_BRIDGE; }
+	Common::Point *createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY);
+	int selectWeapon(int index);
+};
+
+class EnergyUnit : public DefenseUnit {
+private:
+
+public:
+	EnergyUnit();
+	EnergyUnit(DefenseUnit *inUnit);
+	int getType() const { return DUT_ENERGY; }
+	Common::Point *createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY);
+	int selectWeapon(int index);
+};
+
+class OffenseUnit : public DefenseUnit {
+private:
+
+public:
+	OffenseUnit();
+	OffenseUnit(DefenseUnit *inUnit);
+	int getType() const { return DUT_OFFENSE; }
+	Common::Point *createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY);
+	int selectWeapon(int index);
+};
+
+class CrawlerUnit : public DefenseUnit {
+private:
+
+public:
+	CrawlerUnit();
+	CrawlerUnit(DefenseUnit *inUnit);
+	int getType() const { return DUT_CRAWLER; }
+	Common::Point *createTargetPos(int index, int distance, int weaponType, int sourceX, int sourceY);
+	int selectWeapon(int index);
+};
+
+} // End of namespace Scumm
+
+#endif
diff --git a/engines/scumm/he/moonbase/ai_main.h b/engines/scumm/he/moonbase/ai_main.h
new file mode 100644
index 0000000..ca85ff1
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_main.h
@@ -0,0 +1,188 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef SCUMM_HE_MOONBASE_AI_MAIN_H
+#define SCUMM_HE_MOONBASE_AI_MAIN_H
+
+#include "scumm/he/moonbase/ai_tree.h"
+
+namespace Scumm {
+
+extern ScummEngine *_vm;
+
+typedef Common::List<int>::iterator intVecItr;
+
+enum {
+	TERRAIN_TYPE_GOOD = 0,
+	TERRAIN_TYPE_SLOPE = 1,
+	TERRAIN_TYPE_WATER = 2,
+	MAX_MEMORY = 3
+};
+
+enum {
+	ITEM_BOMB = 0,
+	ITEM_CLUSTER = 1,
+	ITEM_REPAIR = 2,
+	ITEM_ANTIAIR = 3,
+	ITEM_BRIDGE = 4,
+	ITEM_TOWER = 5,
+	ITEM_GUIDED = 6,
+	ITEM_EMP = 7,
+	ITEM_SPIKE = 8,
+	ITEM_RECLAIMER = 9,
+	ITEM_BALLOON = 10,
+	ITEM_MINE = 11,
+	ITEM_CRAWLER = 12,
+	ITEM_VIRUS = 13,
+	ITEM_ENERGY = 14,
+	ITEM_SHIELD = 15,
+	ITEM_OFFENSE = 16,
+	ITEM_HUB = 17,
+	ITEM_TIME_EXPIRED = 18,
+	SKIP_TURN = -999
+};
+
+enum BuildingTypes {
+	BUILDING_ENERGY_COLLECTOR = 3,
+	BUILDING_MAIN_BASE = 4,
+	BUILDING_BRIDGE = 5,
+	BUILDING_TOWER = 6,
+	BUILDING_EXPLOSIVE_MINE = 7,
+	BUILDING_SHIELD = 8,
+	BUILDING_ANTI_AIR = 9,
+	BUILDING_OFFENSIVE_LAUNCHER = 10,
+	BUILDING_BALLOON   = 11,
+	BUILDING_CRAWLER   = 12
+};
+
+enum {
+	ENERGY_POOL_X = 45,
+	ENERGY_POOL_Y = 46,
+	ENERGY_POOL_UNITS_ON = 47,
+
+	MIN_DIST = 108
+};
+
+static int energyHogType = 0;
+
+void ResetAI();
+void CleanUpAI();
+void SetAIType(const int paramCount, const int *params);
+int MasterControlProgram(const int paramCount, const int *params);
+
+int ChooseBehavior();
+int ChooseTarget(int behavior);
+
+Tree *InitApproachTarget(int targetX, int targetY, Node **retNode);
+int *ApproachTarget(Tree *myTree, int &x, int &y, Node **currentNode);
+Tree *InitAcquireTarget(int targetX, int targetY, Node **retNode);
+int *AcquireTarget(int targetX, int targetY);
+int *AcquireTarget(int targetX, int targetY, Tree *myTree, int &errorCode);
+int *OffendTarget(int &targetX, int &targetY, int index);
+int *DefendTarget(int &targetX, int &targetY, int index);
+int *EnergizeTarget(int &targetX, int &targetY, int index);
+
+int GetClosestUnit(int x, int y, int radius, int player, int alignment, int unitType, int checkUnitEnabled);
+int GetClosestUnit(int x, int y, int radius, int player, int alignment, int unitType, int checkUnitEnabled, int minDist);
+
+int GetDistance(int originX, int originY, int endX, int endY);
+int GetAngle(int originX, int originY, int endX, int endY);
+int GetAngle(int originX, int originY, int endX, int endY, int noWrapFlag);
+int GetTerrain(int x, int y);
+int GetHubX(int hub);
+int GetHubY(int hub);
+int GetMaxX();
+int GetMaxY();
+int GetCurrentPlayer();
+int GetMaxPower();
+int GetMinPower();
+int GetTerrainSquareSize();
+int GetBuildingOwner(int building);
+int GetBuildingState(int building);
+int GetBuildingType(int building);
+int GetBuildingArmor(int building);
+int GetBuildingWorth(int building);
+void DebugBreak();
+int GetEnergyPoolsArray();
+int GetCoordinateVisibility(int x, int y, int playerNum);
+int GetUnitVisibility(int unit, int playerNum);
+int GetEnergyPoolVisibility(int pool, int playerNum);
+int GetNumberOfPools();
+int GetNumberOfPlayers();
+int GetPlayerEnergy();
+int GetPlayerMaxTime();
+int GetWindXSpeed();
+int GetWindYSpeed();
+int GetTotalWindSpeed();
+int GetWindXSpeedMax();
+int GetWindYSpeedMax();
+int GetBigXSize();
+int GetBigYSize();
+int GetEnergyPoolWidth(int pool);
+int GetBuildingMaxArmor(int building);
+int GetTimerValue(int timerNum);
+int GetLastAttacked(int &x, int &y);
+int PrintDebugTimer(int max, int timerVal);
+int GetPlayerTeam(int player);
+int GetBuildingTeam(int building);
+int GetFOW();
+int GetAnimSpeed();
+int GetBuildingStackPtr();
+int GetTurnCounter();
+
+int GetGroundAltitude(int x, int y);
+int CheckForCordOverlap(int xStart, int yStart, int affectRadius, int simulateFlag);
+int CheckForAngleOverlap(int unit, int angle);
+int EstimateNextRoundEnergy(int player);
+int CheckForUnitOverlap(int x, int y, int radius, int ignoredUnit);
+int CheckForEnergySquare(int x, int y);
+int AIChat();
+
+
+int SimulateBuildingLaunch(int x, int y, int power, int angle, int numSteps, int isEnergy);
+int SimulateWeaponLaunch(int x, int y, int power, int angle, int numSteps);
+int FakeSimulateWeaponLaunch(int x, int y, int power, int angle);
+
+int GetPowerAngleFromPoint(int originX, int originY, int endX, int endY, int threshold, int olFlag);
+int GetPowerAngleFromPoint(int originX, int originY, int endX, int endY, int threshold);
+int CheckIfWaterState(int x, int y);
+int CheckIfWaterSquare(int x, int y);
+int GetUnitsWithinRadius(int x, int y, int radius);
+int GetLandingPoint(int x, int y, int power, int angle);
+int GetEnemyUnitsVisible(int playerNum);
+
+float degToRad(float degrees);
+void MACRO_LimitLocation(int &a, int &b, int c, int d);
+int energyPoolSize(int pool);
+int GetMaxCollectors(int pool);
+
+int TempChooseBehavior();
+int TempChooseTarget(int behavior);
+
+int GetEnergyHogType();
+
+extern Common::List<int> lastXCoord[];
+extern Common::List<int> lastYCoord[];
+
+} // End of namespace Scumm
+
+#endif
diff --git a/engines/scumm/he/moonbase/ai_node.h b/engines/scumm/he/moonbase/ai_node.h
new file mode 100644
index 0000000..87b6b96
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_node.h
@@ -0,0 +1,106 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef SCUMM_HE_MOONBASE_AI_NODE_H
+#define SCUMM_HE_MOONBASE_AI_NODE_H
+
+#include "common/list.h"
+
+namespace Scumm {
+
+const float SUCCESS = -1;
+const float FAILURE = 1e20;
+
+class IContainedObject {
+private:
+	int objID;
+	float valueG;
+
+protected:
+	virtual float getG() const { return valueG; }
+	virtual float calcH() { return 0; }
+
+
+public:
+	IContainedObject() { valueG = 0; }
+	IContainedObject(float inG) { valueG = inG; }
+	IContainedObject(IContainedObject &sourceContainedObject);
+	virtual ~IContainedObject() {}
+
+	virtual IContainedObject *duplicate() = 0;
+
+	void setValueG(float inG) { valueG = inG; }
+	float getValueG() { return valueG; }
+
+	int getObjID() const { return objID; }
+	void setObjID(int inputObjID) { objID = inputObjID; }
+
+	virtual int numChildrenToGen() = 0;
+	virtual IContainedObject *createChildObj(int index, int &completionFlag) = 0;
+
+	virtual int checkSuccess() = 0;
+	virtual float calcT() { return getG(); }
+
+	float returnG() const { return getG(); }
+};
+
+class Node {
+private:
+	Node *pParent;
+	Common::List<Node *> vpChildren;
+
+	int m_depth;
+	static int m_nodeCount;
+
+	IContainedObject *pContents;
+
+public:
+	Node();
+	Node(Node *sourceNode);
+	~Node();
+
+	void setParent(Node *parentPtr) { pParent = parentPtr; }
+	Node *getParent() const { return pParent; }
+
+	void setDepth(int depth) { m_depth = depth; }
+	int getDepth() const { return m_depth; }
+
+	static int getNodeCount() { return m_nodeCount; }
+
+	void setContainedObject(IContainedObject *pValue) { pContents = pValue; }
+	IContainedObject *getContainedObject() { return pContents; }
+
+	Common::List<Node *> getChildren() const { return vpChildren; }
+	int generateChildren();
+	int generateNextChild();
+	Node *popChild();
+
+	float getObjectT() { return pContents->calcT(); }
+
+	Node *getFirstStep();
+
+	void printPath();
+};
+
+} // End of namespace Scumm
+
+#endif
diff --git a/engines/scumm/he/moonbase/ai_tree.h b/engines/scumm/he/moonbase/ai_tree.h
new file mode 100644
index 0000000..c76d03c
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_tree.h
@@ -0,0 +1,78 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef SCUMM_HE_MOONBASE_AI_TREE_H
+#define SCUMM_HE_MOONBASE_AI_TREE_H
+
+#include "scumm/he/moonbase/ai_node.h"
+
+namespace Scumm {
+
+//typedef std::multimap< float, Node *, std::less<float> > fnpMMap;
+
+const int MAX_DEPTH = 100;
+const int MAX_NODES = 1000000;
+
+class Tree {
+private:
+	Node *pBaseNode;
+
+	int m_maxDepth;
+	int m_maxNodes;
+
+	int currentChildIndex;
+	unsigned long m_startTime;
+
+	//fnpMMap m_currentMap;
+	Node *m_currentNode;
+
+public:
+	Tree();
+	Tree(IContainedObject *contents);
+	Tree(IContainedObject *contents, int maxDepth);
+	Tree(IContainedObject *contents, int maxDepth, int maxNodes);
+	Tree(const Tree *sourceTree);
+	~Tree();
+
+	void duplicateTree(Node *sourceNode, Node *destNode);
+
+	Node *GetBaseNode() const { return pBaseNode; }
+	void setMaxDepth(int maxDepth) { m_maxDepth = maxDepth; }
+	int getMaxDepth() const { return m_maxDepth; }
+
+	void setMaxNodes(int maxNodes) { m_maxNodes = maxNodes; }
+	int getMaxNodes() const { return m_maxNodes; }
+
+	void setStartTime(unsigned long sTime) { m_startTime = sTime; }
+	unsigned long getStartTime() const { return m_startTime; }
+
+	Node *aStarSearch();
+
+	Node *aStarSearch_singlePassInit();
+	Node *aStarSearch_singlePass(Node **currentNode);
+
+	int IsBaseNode(Node *thisNode);
+};
+
+} // End of namespace Scumm
+
+#endif
diff --git a/engines/scumm/he/moonbase/moonbase.h b/engines/scumm/he/moonbase/moonbase.h
index e82ae01..0b47ba6 100644
--- a/engines/scumm/he/moonbase/moonbase.h
+++ b/engines/scumm/he/moonbase/moonbase.h
@@ -20,8 +20,8 @@
  *
  */
 
-#ifndef SCUMM_HE_MOONBASE_H
-#define SCUMM_HE_MOONBASE_H
+#ifndef SCUMM_HE_MOONBASE_MOONBASE_H
+#define SCUMM_HE_MOONBASE_MOONBASE_H
 
 #ifdef ENABLE_HE
 
diff --git a/engines/scumm/module.mk b/engines/scumm/module.mk
index c56ef7e..f1551b2 100644
--- a/engines/scumm/module.mk
+++ b/engines/scumm/module.mk
@@ -139,6 +139,7 @@ MODULE_OBJS += \
 	he/logic/moonbase_logic.o \
 	he/logic/puttrace.o \
 	he/logic/soccer.o \
+	he/moonbase/ai_defenseunit.o \
 	he/moonbase/moonbase.o \
 	he/moonbase/moonbase_fow.o
 endif


Commit: adc884ae8f484a439bf13a0371f0fea95cd50392
    https://github.com/scummvm/scummvm/commit/adc884ae8f484a439bf13a0371f0fea95cd50392
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2016-05-22T00:45:03+02:00

Commit Message:
SCUMM HE: AIEntity class implementation

Changed paths:
  A engines/scumm/he/moonbase/ai_types.cpp
  A engines/scumm/he/moonbase/ai_types.h
    engines/scumm/module.mk



diff --git a/engines/scumm/he/moonbase/ai_types.cpp b/engines/scumm/he/moonbase/ai_types.cpp
new file mode 100644
index 0000000..1674e03
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_types.cpp
@@ -0,0 +1,175 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/textconsole.h"
+#include "scumm/he/moonbase/ai_types.h"
+
+namespace Scumm {
+
+AIEntity::AIEntity(int id) {
+	switch (id) {
+	case BRUTAKAS:
+		warning("BRUTAKAS");
+		_id = id;
+		_nameString = new char[64];
+		strcpy(_nameString, "BRUTAKAS");
+		_behaviorVariation = AI_VAR_SMALL;
+		_targetVariation = AI_VAR_SMALL;
+		_angleVariation = AI_VAR_SMALL;
+		_powerVariation = AI_VAR_SMALL;
+		break;
+
+	case AGI:
+		warning("Agi");
+		_id = id;
+		_nameString = new char[64];
+		strcpy(_nameString, "Agi");
+		_behaviorVariation = AI_VAR_SMALL;
+		_targetVariation = AI_VAR_MEDIUM;
+		_angleVariation = AI_VAR_MEDIUM;
+		_powerVariation = AI_VAR_LARGE;
+		break;
+
+	case EL_GATO:
+		warning("El Gato de la Noche");
+		_id = id;
+		_nameString = new char[64];
+		strcpy(_nameString, "El Gato de la Noche");
+		_behaviorVariation = AI_VAR_SMALL;
+		_targetVariation = AI_VAR_SMALL;
+		_angleVariation = AI_VAR_SMALL;
+		_powerVariation = AI_VAR_MEDIUM;
+		break;
+
+	case PIXELAHT:
+		warning("Pixelaht");
+		_id = id;
+		_nameString = new char[64];
+		strcpy(_nameString, "Pixelaht");
+		_behaviorVariation = AI_VAR_SMALL;
+		_targetVariation = AI_VAR_LARGE;
+		_angleVariation = AI_VAR_MEDIUM;
+		_powerVariation = AI_VAR_SMALL;
+		break;
+
+	case CYBALL:
+		warning("cYbaLL");
+		_id = id;
+		_nameString = new char[64];
+		strcpy(_nameString, "cYbaLL");
+		_behaviorVariation = AI_VAR_LARGE;
+		_targetVariation = AI_VAR_LARGE;
+		_angleVariation = AI_VAR_SMALL;
+		_powerVariation = AI_VAR_SMALL;
+		break;
+
+	case NEEP:
+		warning("Neep! Neep!");
+		_id = id;
+		_nameString = new char[64];
+		strcpy(_nameString, "Neep! Neep!");
+		_behaviorVariation = AI_VAR_MEDIUM;
+		_targetVariation = AI_VAR_SMALL;
+		_angleVariation = AI_VAR_SMALL;
+		_powerVariation = AI_VAR_LARGE;
+		break;
+
+	case WARCUPINE:
+		warning("WARcupine");
+		_id = id;
+		_nameString = new char[64];
+		strcpy(_nameString, "WARcupine");
+		_behaviorVariation = AI_VAR_SMALL;
+		_targetVariation = AI_VAR_SMALL;
+		_angleVariation = AI_VAR_LARGE;
+		_powerVariation = AI_VAR_MEDIUM;
+		break;
+
+	case AONE:
+		warning("aone");
+		_id = id;
+		_nameString = new char[64];
+		strcpy(_nameString, "aone");
+		_behaviorVariation = AI_VAR_MEDIUM;
+		_targetVariation = AI_VAR_MEDIUM;
+		_angleVariation = AI_VAR_MEDIUM;
+		_powerVariation = AI_VAR_MEDIUM;
+		break;
+
+	case SPANDO:
+		warning("S p a n d o");
+		_id = id;
+		_nameString = new char[64];
+		strcpy(_nameString, "S p a n d o");
+		_behaviorVariation = AI_VAR_LARGE;
+		_targetVariation = AI_VAR_LARGE;
+		_angleVariation = AI_VAR_SMALL;
+		_powerVariation = AI_VAR_SMALL;
+		break;
+
+	case ORBNU_LUNATEK:
+		warning("Bonur J Lunatek");
+		_id = id;
+		_nameString = new char[64];
+		strcpy(_nameString, "Bonur J Lunatek");
+		_behaviorVariation = AI_VAR_HUGE;
+		_targetVariation = AI_VAR_HUGE;
+		_angleVariation = AI_VAR_HUGE;
+		_powerVariation = AI_VAR_HUGE;
+		break;
+
+	case CRAWLER_CHUCKER:
+		warning("Le Chuckre des Crawlres");
+		_id = id;
+		_nameString = new char[64];
+		strcpy(_nameString, "Le Chuckre des Crawlres");
+		_behaviorVariation = AI_VAR_SMALL;
+		_targetVariation = AI_VAR_MEDIUM;
+		_angleVariation = AI_VAR_MEDIUM;
+		_powerVariation = AI_VAR_LARGE;
+		break;
+
+	case ENERGY_HOG:
+		warning("Energy Hog");
+		_id = id;
+		_nameString = new char[64];
+		strcpy(_nameString, "Energy Hog\n");
+		_behaviorVariation = AI_VAR_SMALL;
+		_targetVariation = AI_VAR_SMALL;
+		_angleVariation = AI_VAR_SMALL;
+		_powerVariation = AI_VAR_SMALL;
+		break;
+
+	case RANGER:
+		warning("Ranger");
+		_id = id;
+		_nameString = new char[64];
+		strcpy(_nameString, "Ranger\n");
+		_behaviorVariation = AI_VAR_SMALL;
+		_targetVariation = AI_VAR_SMALL;
+		_angleVariation = AI_VAR_SMALL;
+		_powerVariation = AI_VAR_SMALL;
+		break;
+	}
+}
+
+} // End of namespace Scumm
diff --git a/engines/scumm/he/moonbase/ai_types.h b/engines/scumm/he/moonbase/ai_types.h
new file mode 100644
index 0000000..1e8c829
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_types.h
@@ -0,0 +1,97 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef SCUMM_HE_MOONBASE_AI_TYPES_H
+#define SCUMM_HE_MOONBASE_AI_TYPES_H
+
+namespace Scumm {
+
+enum {
+	AGI = 1,
+	AONE = 2,
+	BRUTAKAS = 3,
+	CYBALL = 4,
+	EL_GATO = 5,
+	NEEP = 6,
+	ORBNU_LUNATEK = 7,
+	PIXELAHT = 8,
+	SPANDO = 9,
+	WARCUPINE = 10
+};
+
+enum {
+	CRAWLER_CHUCKER = 11,
+	ENERGY_HOG = 12,
+	RANGER = 13
+};
+
+enum {
+	AI_VAR_NONE = -1,
+	AI_VAR_SMALL = 0,
+	AI_VAR_MEDIUM = 1,
+	AI_VAR_LARGE = 2,
+	AI_VAR_HUGE = 5
+};
+
+enum {
+	AI_VAR_BASE_BEHAVIOR = 10,
+	AI_VAR_BASE_TARGET = 10,
+	AI_VAR_BASE_ANGLE = 2,
+	AI_VAR_BASE_POWER = 5
+};
+
+class AIEntity {
+private:
+	int _id;
+	char *_nameString;
+	int _behaviorVariation;
+	int _targetVariation;
+	int _angleVariation;
+	int _powerVariation;
+
+public:
+	AIEntity(int id);
+	~AIEntity() {
+		if (_nameString) {
+			delete _nameString;
+			_nameString = 0;
+		}
+	}
+
+	int GetID() const { return _id; }
+	char *GetNameString() const { return _nameString; }
+	int GetBehaviorVariation() const { return _behaviorVariation; }
+	int GetTargetVariation() const { return _targetVariation; }
+	int GetAngleVariation() const { return _angleVariation; }
+	int GetPowerVariation() const { return _powerVariation; }
+
+	void SetID(int id) { _id = id; }
+	void SetNameString(char *nameString) { _nameString = nameString; }
+	void SetBehaviorVariation(int behaviorVariation) { _behaviorVariation = behaviorVariation; }
+	void SetTargetVariation(int targetVariation) { _targetVariation = targetVariation; }
+	void SetAngleVariation(int angleVariation) { _angleVariation = angleVariation; }
+	void SetPowerVariation(int powerVariation) { _powerVariation = powerVariation; }
+};
+
+} // End of namespace Scumm
+
+#endif
diff --git a/engines/scumm/module.mk b/engines/scumm/module.mk
index f1551b2..717ca81 100644
--- a/engines/scumm/module.mk
+++ b/engines/scumm/module.mk
@@ -140,6 +140,7 @@ MODULE_OBJS += \
 	he/logic/puttrace.o \
 	he/logic/soccer.o \
 	he/moonbase/ai_defenseunit.o \
+	he/moonbase/ai_types.o \
 	he/moonbase/moonbase.o \
 	he/moonbase/moonbase_fow.o
 endif


Commit: 33a0afc8f850fdc226ac65e7b4da107f3e36b805
    https://github.com/scummvm/scummvm/commit/33a0afc8f850fdc226ac65e7b4da107f3e36b805
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2016-05-22T00:45:03+02:00

Commit Message:
SCUMM HE: Added Weapon class

Changed paths:
  A engines/scumm/he/moonbase/ai_weapon.cpp
  A engines/scumm/he/moonbase/ai_weapon.h
    engines/scumm/he/moonbase/ai_main.h
    engines/scumm/module.mk



diff --git a/engines/scumm/he/moonbase/ai_main.h b/engines/scumm/he/moonbase/ai_main.h
index ca85ff1..d35cf8e 100644
--- a/engines/scumm/he/moonbase/ai_main.h
+++ b/engines/scumm/he/moonbase/ai_main.h
@@ -27,6 +27,8 @@
 
 namespace Scumm {
 
+class ScummEngine;
+
 extern ScummEngine *_vm;
 
 typedef Common::List<int>::iterator intVecItr;
diff --git a/engines/scumm/he/moonbase/ai_weapon.cpp b/engines/scumm/he/moonbase/ai_weapon.cpp
new file mode 100644
index 0000000..b13d1ef
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_weapon.cpp
@@ -0,0 +1,87 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "scumm/he/moonbase/ai_weapon.h"
+#include "scumm/he/moonbase/ai_main.h"
+
+namespace Scumm {
+
+Weapon::Weapon(int typeID) { //, float damage, int radius)
+	switch (typeID) {
+	case ITEM_BOMB:
+		becomeBomb();
+		break;
+
+	case ITEM_CLUSTER:
+		becomeCluster();
+		break;
+
+	case ITEM_CRAWLER:
+		becomeCrawler();
+		break;
+
+	case ITEM_EMP:
+		becomeEMP();
+		break;
+
+	case ITEM_SPIKE:
+		becomeSpike();
+		break;
+	}
+}
+
+void Weapon::becomeBomb() {
+	_typeID = ITEM_BOMB;
+	_damage = 3;
+	_radius = 30;
+	_cost = 1;
+}
+
+void Weapon::becomeCluster() {
+	_typeID = ITEM_CLUSTER;
+	_damage = 1.5;
+	_radius = 20;
+	_cost = 1;
+}
+
+void Weapon::becomeCrawler() {
+	_typeID = ITEM_CRAWLER;
+	_damage = 4;
+	_radius = 180;
+	_cost = 7;
+}
+
+void Weapon::becomeEMP() {
+	_typeID = ITEM_EMP;
+	_damage = .1f;
+	_radius = 215;
+	_cost = 3;
+}
+
+void Weapon::becomeSpike() {
+	_typeID = ITEM_SPIKE;
+	_damage = 6;
+	_radius = 180;
+	_cost = 3;
+}
+
+} // End of namespace Scumm
diff --git a/engines/scumm/he/moonbase/ai_weapon.h b/engines/scumm/he/moonbase/ai_weapon.h
new file mode 100644
index 0000000..55c710c
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_weapon.h
@@ -0,0 +1,59 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef SCUMM_HE_MOONBASE_AI_WEAPON_H
+#define SCUMM_HE_MOONBASE_AI_WEAPON_H
+
+namespace Scumm {
+
+class Weapon {
+private:
+	int _typeID;
+	float _damage;
+	int _radius;
+	int _cost;
+
+public:
+	Weapon() {}
+	Weapon(int typeID);
+	virtual ~Weapon() {}
+
+	void setTypeID(int typeID) { _typeID = typeID; }
+	void setDamage(float damage) { _damage = damage; }
+	void setRadius(int radius) { _radius = radius; }
+	void setCost(int cost) { _cost = cost; }
+
+	int getTypeID() { return _typeID; }
+	float getDamage() { return _damage; }
+	int getRadius() { return _radius; }
+	int getCost() { return _cost; }
+
+	void becomeBomb();
+	void becomeCluster();
+	void becomeCrawler();
+	void becomeEMP();
+	void becomeSpike();
+};
+
+} // End of namespace Scumm
+
+#endif
diff --git a/engines/scumm/module.mk b/engines/scumm/module.mk
index 717ca81..582411f 100644
--- a/engines/scumm/module.mk
+++ b/engines/scumm/module.mk
@@ -141,6 +141,7 @@ MODULE_OBJS += \
 	he/logic/soccer.o \
 	he/moonbase/ai_defenseunit.o \
 	he/moonbase/ai_types.o \
+	he/moonbase/ai_weapon.o \
 	he/moonbase/moonbase.o \
 	he/moonbase/moonbase_fow.o
 endif


Commit: 412ae07efb505ce2e0e18c3aa2a47abe1c01e504
    https://github.com/scummvm/scummvm/commit/412ae07efb505ce2e0e18c3aa2a47abe1c01e504
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2016-05-22T00:45:03+02:00

Commit Message:
SCUMM HE: Added Moonbase Node class

Changed paths:
  A engines/scumm/he/moonbase/ai_node.cpp
    engines/scumm/he/moonbase/ai_node.h
    engines/scumm/module.mk



diff --git a/engines/scumm/he/moonbase/ai_node.cpp b/engines/scumm/he/moonbase/ai_node.cpp
new file mode 100644
index 0000000..083a156
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_node.cpp
@@ -0,0 +1,153 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "scumm/he/moonbase/ai_node.h"
+
+namespace Scumm {
+
+IContainedObject::IContainedObject(IContainedObject &sourceContainedObject) {
+	_objID = sourceContainedObject.getObjID();
+	_valueG = sourceContainedObject.getG();
+}
+
+int Node::_nodeCount = 0;
+
+Node::Node() {
+	_parent = NULL;
+	_depth = 0;
+	_nodeCount++;
+	_contents = NULL;
+}
+
+Node::Node(Node *sourceNode) {
+	_parent = NULL;
+	_children = sourceNode->getChildren();
+
+	_depth = sourceNode->getDepth();
+
+	_contents = sourceNode->getContainedObject()->duplicate();
+}
+
+Node::~Node() {
+	if (_contents != NULL) {
+		delete _contents;
+		_contents = NULL;
+	}
+
+	_nodeCount--;
+}
+
+int Node::generateChildren() {
+	int numChildren = _contents->numChildrenToGen();
+
+	int numChildrenGenerated = numChildren;
+	int errorCode = -1;
+	static int i = 0;
+
+	while (i < numChildren) {
+		Node *tempNode = new Node;
+		_children.push_back(tempNode);
+		tempNode->setParent(this);
+		tempNode->setDepth(_depth + 1);
+
+		int completionFlag;
+
+		IContainedObject *thisContObj = _contents->createChildObj(i, completionFlag);
+		assert(!(thisContObj != NULL && completionFlag == 0));
+
+		if (!completionFlag) {
+			_children.pop_back();
+			delete tempNode;
+			return 0;
+		}
+
+		i++;
+
+		if (thisContObj != NULL) {
+			tempNode->setContainedObject(thisContObj);
+		} else {
+			_children.pop_back();
+			delete tempNode;
+			numChildrenGenerated--;
+		}
+	}
+
+	i = 0;
+
+	if (numChildrenGenerated > 0)
+		return numChildrenGenerated;
+
+	return errorCode;
+}
+
+
+int Node::generateNextChild() {
+	int numChildren = _contents->numChildrenToGen();
+
+	static int i = 0;
+
+	Node *tempNode = new Node;
+	_children.push_back(tempNode);
+	tempNode->setParent(this);
+	tempNode->setDepth(_depth + 1);
+
+	int compFlag;
+	IContainedObject *thisContObj = _contents->createChildObj(i, compFlag);
+
+	if (thisContObj != NULL) {
+		tempNode->setContainedObject(thisContObj);
+	} else {
+		_children.pop_back();
+		delete tempNode;
+	}
+
+	++i;
+
+	if (i > numChildren)
+		i = 0;
+
+	return i;
+}
+
+Node *Node::popChild() {
+	Node *temp;
+
+	temp = _children.back();
+	_children.pop_back();
+	return temp;
+}
+
+Node *Node::getFirstStep() {
+	Node *currentNode = this;
+
+	if (currentNode->getParent() == NULL)
+		return currentNode;
+
+	while (currentNode->getParent()->getParent() != NULL)
+		currentNode = currentNode->getParent();
+
+	assert(currentNode->getDepth() == 1);
+
+	return currentNode;
+}
+
+} // End of namespace Scumm
diff --git a/engines/scumm/he/moonbase/ai_node.h b/engines/scumm/he/moonbase/ai_node.h
index 87b6b96..00800c2 100644
--- a/engines/scumm/he/moonbase/ai_node.h
+++ b/engines/scumm/he/moonbase/ai_node.h
@@ -32,27 +32,26 @@ const float FAILURE = 1e20;
 
 class IContainedObject {
 private:
-	int objID;
-	float valueG;
+	int _objID;
+	float _valueG;
 
 protected:
-	virtual float getG() const { return valueG; }
+	virtual float getG() const { return _valueG; }
 	virtual float calcH() { return 0; }
 
-
 public:
-	IContainedObject() { valueG = 0; }
-	IContainedObject(float inG) { valueG = inG; }
+	IContainedObject() { _valueG = 0; }
+	IContainedObject(float inG) { _valueG = inG; }
 	IContainedObject(IContainedObject &sourceContainedObject);
 	virtual ~IContainedObject() {}
 
 	virtual IContainedObject *duplicate() = 0;
 
-	void setValueG(float inG) { valueG = inG; }
-	float getValueG() { return valueG; }
+	void setValueG(float inG) { _valueG = inG; }
+	float getValueG() { return _valueG; }
 
-	int getObjID() const { return objID; }
-	void setObjID(int inputObjID) { objID = inputObjID; }
+	int getObjID() const { return _objID; }
+	void setObjID(int inputObjID) { _objID = inputObjID; }
 
 	virtual int numChildrenToGen() = 0;
 	virtual IContainedObject *createChildObj(int index, int &completionFlag) = 0;
@@ -65,40 +64,38 @@ public:
 
 class Node {
 private:
-	Node *pParent;
-	Common::List<Node *> vpChildren;
+	Node *_parent;
+	Common::List<Node *> _children;
 
-	int m_depth;
-	static int m_nodeCount;
+	int _depth;
+	static int _nodeCount;
 
-	IContainedObject *pContents;
+	IContainedObject *_contents;
 
 public:
 	Node();
 	Node(Node *sourceNode);
 	~Node();
 
-	void setParent(Node *parentPtr) { pParent = parentPtr; }
-	Node *getParent() const { return pParent; }
+	void setParent(Node *parentPtr) { _parent = parentPtr; }
+	Node *getParent() const { return _parent; }
 
-	void setDepth(int depth) { m_depth = depth; }
-	int getDepth() const { return m_depth; }
+	void setDepth(int depth) { _depth = depth; }
+	int getDepth() const { return _depth; }
 
-	static int getNodeCount() { return m_nodeCount; }
+	static int getNodeCount() { return _nodeCount; }
 
-	void setContainedObject(IContainedObject *pValue) { pContents = pValue; }
-	IContainedObject *getContainedObject() { return pContents; }
+	void setContainedObject(IContainedObject *value) { _contents = value; }
+	IContainedObject *getContainedObject() { return _contents; }
 
-	Common::List<Node *> getChildren() const { return vpChildren; }
+	Common::List<Node *> getChildren() const { return _children; }
 	int generateChildren();
 	int generateNextChild();
 	Node *popChild();
 
-	float getObjectT() { return pContents->calcT(); }
+	float getObjectT() { return _contents->calcT(); }
 
 	Node *getFirstStep();
-
-	void printPath();
 };
 
 } // End of namespace Scumm
diff --git a/engines/scumm/module.mk b/engines/scumm/module.mk
index 582411f..28153f5 100644
--- a/engines/scumm/module.mk
+++ b/engines/scumm/module.mk
@@ -140,6 +140,7 @@ MODULE_OBJS += \
 	he/logic/puttrace.o \
 	he/logic/soccer.o \
 	he/moonbase/ai_defenseunit.o \
+	he/moonbase/ai_node.o \
 	he/moonbase/ai_types.o \
 	he/moonbase/ai_weapon.o \
 	he/moonbase/moonbase.o \


Commit: e4de5bf9ce8d447e5ab000aa354aafa513dc080b
    https://github.com/scummvm/scummvm/commit/e4de5bf9ce8d447e5ab000aa354aafa513dc080b
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2016-05-22T00:45:04+02:00

Commit Message:
SCUMM HE: Added implementation for Sortie and DefenderUnit classes

Changed paths:
  A engines/scumm/he/moonbase/ai_targetacquisition.cpp
  A engines/scumm/he/moonbase/ai_targetacquisition.h
    engines/scumm/he/moonbase/ai_defenseunit.cpp
    engines/scumm/he/moonbase/ai_main.h
    engines/scumm/he/moonbase/ai_node.h
    engines/scumm/he/moonbase/moonbase.cpp
    engines/scumm/he/moonbase/moonbase.h
    engines/scumm/he/moonbase/moonbase_fow.cpp
    engines/scumm/module.mk
    engines/scumm/scumm_v6.h



diff --git a/engines/scumm/he/moonbase/ai_defenseunit.cpp b/engines/scumm/he/moonbase/ai_defenseunit.cpp
index 1312752..783c7c7 100644
--- a/engines/scumm/he/moonbase/ai_defenseunit.cpp
+++ b/engines/scumm/he/moonbase/ai_defenseunit.cpp
@@ -22,7 +22,7 @@
 
 #include "common/rect.h"
 #include "common/util.h"
-#include "scumm/scumm.h"
+#include "scumm/he/intern_he.h"
 #include "scumm/he/moonbase/ai_defenseunit.h"
 #include "scumm/he/moonbase/ai_main.h"
 
diff --git a/engines/scumm/he/moonbase/ai_main.h b/engines/scumm/he/moonbase/ai_main.h
index d35cf8e..cfd3aad 100644
--- a/engines/scumm/he/moonbase/ai_main.h
+++ b/engines/scumm/he/moonbase/ai_main.h
@@ -27,11 +27,11 @@
 
 namespace Scumm {
 
-class ScummEngine;
+class ScummEngine_v71he;
 
-extern ScummEngine *_vm;
+extern ScummEngine_v71he *_vm;
 
-typedef Common::List<int>::iterator intVecItr;
+typedef Common::Array<int>::iterator intVecItr;
 
 enum {
 	TERRAIN_TYPE_GOOD = 0,
@@ -182,8 +182,8 @@ int TempChooseTarget(int behavior);
 
 int GetEnergyHogType();
 
-extern Common::List<int> lastXCoord[];
-extern Common::List<int> lastYCoord[];
+extern Common::Array<int> lastXCoord[];
+extern Common::Array<int> lastYCoord[];
 
 } // End of namespace Scumm
 
diff --git a/engines/scumm/he/moonbase/ai_node.h b/engines/scumm/he/moonbase/ai_node.h
index 00800c2..454b98e 100644
--- a/engines/scumm/he/moonbase/ai_node.h
+++ b/engines/scumm/he/moonbase/ai_node.h
@@ -23,7 +23,7 @@
 #ifndef SCUMM_HE_MOONBASE_AI_NODE_H
 #define SCUMM_HE_MOONBASE_AI_NODE_H
 
-#include "common/list.h"
+#include "common/array.h"
 
 namespace Scumm {
 
@@ -65,7 +65,7 @@ public:
 class Node {
 private:
 	Node *_parent;
-	Common::List<Node *> _children;
+	Common::Array<Node *> _children;
 
 	int _depth;
 	static int _nodeCount;
@@ -88,7 +88,7 @@ public:
 	void setContainedObject(IContainedObject *value) { _contents = value; }
 	IContainedObject *getContainedObject() { return _contents; }
 
-	Common::List<Node *> getChildren() const { return _children; }
+	Common::Array<Node *> getChildren() const { return _children; }
 	int generateChildren();
 	int generateNextChild();
 	Node *popChild();
diff --git a/engines/scumm/he/moonbase/ai_targetacquisition.cpp b/engines/scumm/he/moonbase/ai_targetacquisition.cpp
new file mode 100644
index 0000000..0eebaef
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_targetacquisition.cpp
@@ -0,0 +1,557 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "scumm/he/intern_he.h"
+#include "scumm/he/moonbase/moonbase.h"
+
+#include "scumm/he/moonbase/ai_targetacquisition.h"
+#include "scumm/he/moonbase/ai_main.h"
+#include "scumm/he/moonbase/ai_weapon.h"
+
+namespace Scumm {
+
+int Sortie::_sSourceX = 0;
+int Sortie::_sSourceY = 0;
+
+int Sortie::_sTargetX = 0;
+int Sortie::_sTargetY = 0;
+
+Sortie::~Sortie() {
+	for (Common::Array<DefenseUnit *>::iterator k = _enemyDefenses.begin(); k != _enemyDefenses.end(); ++k) {
+		delete *k;
+	}
+}
+
+void Sortie::setEnemyDefenses(int enemyDefensesScummArray, int defendX, int defendY) {
+	DefenseUnit *thisUnit;
+	int currentPlayer = GetCurrentPlayer();
+
+	for (int i = 0; i < 200; ++i) {
+		int thisElement = _vm->_moonbase->readFromArray(enemyDefensesScummArray, 0, i);
+
+		if (thisElement) {
+			if (GetBuildingOwner(thisElement)) {
+				if (GetPlayerTeam(currentPlayer) != GetBuildingTeam(thisElement)) {
+					int type = GetBuildingType(thisElement);
+
+					switch (type) {
+					case BUILDING_ANTI_AIR:
+						thisUnit = new AntiAirUnit();
+						break;
+
+					case BUILDING_SHIELD:
+						thisUnit = new ShieldUnit();
+						break;
+
+					case BUILDING_EXPLOSIVE_MINE:
+						if (GetDistance(GetHubX(thisElement), GetHubY(thisElement), defendX, defendY) < 90)
+							thisUnit = new MineUnit();
+						else
+							thisUnit = NULL;
+
+						break;
+
+					case BUILDING_CRAWLER:
+						thisUnit = NULL;
+						break;
+
+					default:
+						thisUnit = NULL;
+						break;
+					}
+
+					if (thisUnit != NULL) {
+						thisUnit->setID(thisElement);
+						thisUnit->setPos(GetHubX(thisElement), GetHubY(thisElement));
+
+						if (GetBuildingState(thisElement)) thisUnit->setState(DUS_OFF);
+
+						_enemyDefenses.push_back(thisUnit);
+					}
+				}
+			}
+		} else {
+			i = 200;
+		}
+	}
+}
+
+int *Sortie::getShotPos() const {
+	int *retVal = new int[2];
+
+	retVal[0] = _shotPosX;
+	retVal[1] = _shotPosY;
+
+	return retVal;
+}
+
+int Sortie::numChildrenToGen() {
+	int retVal = MAX<uint>(_enemyDefenses.size(), 1) * NUM_SHOT_POSITIONS * NUM_WEAPONS;
+	return retVal;
+}
+
+IContainedObject *Sortie::createChildObj(int index, int &completionFlag) {
+	float thisDamage;
+	Sortie *retSortie = new Sortie;
+	int activeDefenses = 0;
+
+	Common::Array<DefenseUnit *> thisEnemyDefenses;
+
+	// Copy the defensive unit list from the parent
+	for (Common::Array<DefenseUnit *>::iterator k = _enemyDefenses.begin(); k != _enemyDefenses.end(); ++k) {
+		DefenseUnit *temp;
+
+		switch ((*k)->getType()) {
+		case DUT_ANTI_AIR:
+			temp = new AntiAirUnit(*k);
+			break;
+
+		case DUT_SHIELD:
+			temp = new ShieldUnit(*k);
+			break;
+
+		case DUT_MINE:
+			temp = new MineUnit(*k);
+			break;
+
+		case DUT_CRAWLER:
+			temp = new CrawlerUnit(*k);
+			break;
+
+		default:
+			temp = new ShieldUnit(*k);
+			break;
+		}
+
+		thisEnemyDefenses.push_back(temp);
+	}
+
+	// Calculate the current target from the index
+	DefenseUnit *currentTarget = *(thisEnemyDefenses.begin() + static_cast<int>(index / (NUM_WEAPONS * NUM_SHOT_POSITIONS)));
+
+	assert(currentTarget);
+
+	// Pick correct weapon according to index
+	Weapon *currentWeapon = new Weapon(currentTarget->selectWeapon(index % NUM_WEAPONS));
+	retSortie->setUnitType(currentWeapon->getTypeID());
+
+	// Calculate distance from target to source hub
+	int distance = GetDistance(currentTarget->getPosX(), currentTarget->getPosY(), getSourcePosX(), getSourcePosY());
+
+	// Pick correct shot position according to index
+	Common::Point *targetCoords;
+	targetCoords = currentTarget->createTargetPos((static_cast<int>(index / NUM_WEAPONS) % NUM_SHOT_POSITIONS), distance, currentWeapon->getTypeID(), getSourcePosX(), getSourcePosY());
+	retSortie->setShotPos(targetCoords->x, targetCoords->y);
+
+	// Set the g value based on cost of the weapon
+	retSortie->setValueG(getG() + currentWeapon->getCost());
+
+	int AAcounter = 3;
+
+	// Loop through defensive units, toggling anti-air units and deciding if this weapon will land safely
+	for (Common::Array<DefenseUnit *>::iterator i = thisEnemyDefenses.begin(); i != thisEnemyDefenses.end(); ++i) {
+		distance = GetDistance((*i)->getPosX(), (*i)->getPosY(), targetCoords->x, targetCoords->y);
+
+		// Check to see if we're within an active defense's radius
+		if ((distance < (*i)->getRadius()) && ((*i)->getState() == DUS_ON)) {
+			activeDefenses++;
+
+			// Turn off this anti-air and drop the coverage count
+			if (((*i)->getType() == DUT_ANTI_AIR)) {
+				(*i)->setState(DUS_OFF);
+
+				if (currentWeapon->getTypeID() == ITEM_CLUSTER)
+					AAcounter--;
+				else
+					AAcounter = 0;
+			}
+
+			// Essentially disable this weapon choice, due to its impact with a shield, or untriggered anti-air
+			if (((*i)->getType() == DUT_SHIELD)  || !AAcounter) {
+				retSortie->setValueG(1000);
+				i = thisEnemyDefenses.end() - 1;
+			}
+		} else {
+			// Turn on any anti-airs that were off the previous turn
+			if (((*i)->getType() == DUT_ANTI_AIR) && ((*i)->getState() == DUS_OFF))
+				(*i)->setState(DUS_ON);
+		}
+	}
+
+	// Turn on all the non-anti-air units in preparation for emp's and the next turn
+	for (Common::Array<DefenseUnit *>::iterator i = thisEnemyDefenses.begin(); i != thisEnemyDefenses.end(); ++i) {
+		if ((*i)->getType() != DUT_ANTI_AIR) {
+			(*i)->setState(DUS_ON);
+		}
+	}
+
+	// If this weapon is still valid
+	if (retSortie->getValueG() < 1000) {
+		// Apply emp effects and damage to all units in range of weapon
+		for (Common::Array<DefenseUnit *>::iterator i = thisEnemyDefenses.begin(); i != thisEnemyDefenses.end(); ) {
+			// Special simulated crawler detonation location used, since it walks a bit
+			if (currentWeapon->getTypeID() == ITEM_CRAWLER)
+				distance = GetDistance((*i)->getPosX(), (*i)->getPosY(), currentTarget->getPosX(), currentTarget->getPosY());
+			// Normal detonation location used here
+			else {
+				distance = GetDistance((*i)->getPosX(), (*i)->getPosY(), targetCoords->x, targetCoords->y);
+			}
+
+			if (distance < currentWeapon->getRadius()) {
+				// Apply damage
+				thisDamage = currentWeapon->getDamage();
+
+				if ((AAcounter != 3) && (currentWeapon->getTypeID() == ITEM_CLUSTER))
+					thisDamage = 0;
+
+				if (!_vm->_rnd.getRandomNumber(4))
+					currentWeapon->setTypeID(ITEM_MINE);
+
+				(*i)->setDamage(thisDamage);
+
+				// Apply emp effect
+				if (currentWeapon->getTypeID() == ITEM_EMP) {
+					(*i)->setState(DUS_OFF);
+				}
+
+				// Remove destroyed defenses
+				if ((*i)->getArmor() <= 0) {
+					delete *i;
+					i = thisEnemyDefenses.erase(i);
+				} else {
+					++i;
+				}
+			} else {
+				++i;
+			}
+		}
+	}
+
+	retSortie->setEnemyDefenses(thisEnemyDefenses);
+
+	delete targetCoords;
+	delete currentWeapon;
+	return retSortie;
+}
+
+float Sortie::calcH() {
+	float retValue = 0;
+	Common::Array<DefenseUnit *> thisEnemyDefenses = getEnemyDefenses();
+
+	for (Common::Array<DefenseUnit *>::iterator i = thisEnemyDefenses.begin(); i != thisEnemyDefenses.end(); ++i) {
+		if ((*i)->getState() == DUS_ON) {
+			switch ((*i)->getType()) {
+			case DUT_ANTI_AIR:
+				retValue += 1;
+
+			case DUT_MINE:
+				retValue += 1;
+				break;
+
+			case DUT_SHIELD:
+				retValue += 1;
+				break;
+			}
+		}
+	}
+
+	return retValue;
+}
+
+int Sortie::checkSuccess() {
+	if (!_enemyDefenses.size()) return SUCCESS;
+
+	int targetX = getTargetPosX();
+	int targetY = getTargetPosY();
+
+	int targetCheck = 0;
+
+	for (Common::Array<DefenseUnit *>::iterator i = _enemyDefenses.begin(); i != _enemyDefenses.end(); ++i) {
+		if (((*i)->getState() == DUS_ON) && ((*i)->getType() != DUT_HUB)) {
+			return 0;
+		}
+
+		if (((*i)->getPosX() == targetX) && ((*i)->getPosY() == targetY)) targetCheck = 1;
+	}
+
+	if (!targetCheck)
+		return SUCCESS;
+
+	// If shot pos == target pos return SUCCESS;
+	if ((targetX == getShotPosX()) && (getTargetPosY() == getShotPosY())) {
+		return SUCCESS;
+	}
+
+	return 0;
+}
+
+float Sortie::calcT() {
+	return (checkSuccess() != SUCCESS) ? (getG() + calcH()) : SUCCESS;
+}
+
+IContainedObject *Sortie::duplicate() {
+	return this;
+}
+
+
+void Sortie::printEnemyDefenses() {
+	for (Common::Array<DefenseUnit *>::iterator i = _enemyDefenses.begin(); i != _enemyDefenses.end(); ++i) {
+		warning("Unit %d - Type: %d, Armor: %d, Status: %d", (*i)->getID(), (*i)->getType(), static_cast<int>((*i)->getArmor()), (*i)->getState());
+	}
+}
+
+int Defender::calculateDefenseUnitPosition(int targetX, int targetY, int index) {
+	int currentPlayer = GetCurrentPlayer();
+
+	//Get list of near hubs
+	int unitsArray = GetUnitsWithinRadius(targetX + 5, targetY, 480);
+
+	const int NUM_HUBS = 10;
+	//Order on dist
+	int hubArray[NUM_HUBS] = { 0 };
+	int hubIndex = 0;
+
+	for (int i = 0; i < 200; ++i) {
+		int thisUnit = _vm->_moonbase->readFromArray(unitsArray, 0, i);
+
+		if (thisUnit) {
+			if (((GetBuildingType(thisUnit) == BUILDING_MAIN_BASE) || (GetBuildingType(thisUnit) == BUILDING_OFFENSIVE_LAUNCHER))  && (GetBuildingOwner(thisUnit) == currentPlayer)) {
+				for (int j = 0; j < NUM_HUBS; ++j) {
+					if (hubArray[j]) {
+						int distCurrent = GetDistance(targetX, targetY, GetHubX(thisUnit), GetHubY(thisUnit));
+						int distSaved = GetDistance(targetX, targetY, GetHubX(hubArray[j]), GetHubY(hubArray[j]));
+
+						if (distCurrent < distSaved) {
+							hubArray[hubIndex] = hubArray[j];
+							hubArray[j] = thisUnit;
+							++hubIndex;
+							j = 100;
+						}
+					} else {
+						hubArray[j] = thisUnit;
+						++hubIndex;
+						j = 100;
+					}
+				}
+			}
+		}
+
+		if (hubIndex >= NUM_HUBS) {
+			hubIndex = NUM_HUBS;
+			i = 200;
+		}
+	}
+
+	_vm->nukeArray(unitsArray);
+
+	//Check if repair is needed
+	int targetUnit = GetClosestUnit(targetX + 5, targetY, 15, currentPlayer, 1, 0, 0, 0);
+
+	if (targetUnit && (targetUnit != BUILDING_CRAWLER) && (GetBuildingTeam(targetUnit) == GetPlayerTeam(currentPlayer))) {
+		int armor = GetBuildingArmor(targetUnit);
+
+		if (armor < GetBuildingMaxArmor(targetUnit)) {
+			unitsArray = GetUnitsWithinRadius(targetX + 5, targetY, 170);
+			int defCount = 0;
+
+			for (int i = 0; i < 200; ++i) {
+				int thisUnit = _vm->_moonbase->readFromArray(unitsArray, 0, i);
+
+				if (thisUnit) {
+					if (((GetBuildingType(thisUnit) == BUILDING_SHIELD) || (GetBuildingType(thisUnit) == BUILDING_ANTI_AIR)) && (GetBuildingOwner(thisUnit) == currentPlayer) && (GetBuildingState(thisUnit) == 0)) {
+						++defCount;
+						i = 200;
+					}
+				}
+			}
+
+			_vm->nukeArray(unitsArray);
+
+			if (defCount) {
+				//repair
+				int hubUnit = GetClosestUnit(targetX, targetY, 480, currentPlayer, 1, BUILDING_MAIN_BASE, 1, 110);
+
+				if (hubUnit && (hubUnit != targetUnit)) {
+					int powAngle = abs(GetPowerAngleFromPoint(GetHubX(hubUnit), GetHubY(hubUnit), targetX, targetY, 20));
+					int power = powAngle / 360;
+					int angle = powAngle - (power * 360);
+
+					setTargetX(targetX);
+					setTargetY(targetY);
+
+					setSourceUnit(hubUnit);
+					setUnit(ITEM_REPAIR);
+					setPower(power);
+					setAngle(angle);
+
+					return 1;
+				}
+			}
+		}
+	}
+
+	//For each hub
+	for (int i = 0; i < MIN(NUM_HUBS, hubIndex); ++i) {
+		int hubX = GetHubX(hubArray[i]);
+		int hubY = GetHubY(hubArray[i]);
+		//Get angle to hub
+		int directAngleToHub = 0;
+
+		//If this hub is the target
+		if ((hubX == targetX) && (hubY == targetY)) {
+			//make the angle seed point at the closest enemy
+			int enemyUnit = GetClosestUnit(hubX, hubY, GetMaxX(), currentPlayer, 0, 0, 0);
+			directAngleToHub = GetAngle(targetX, targetY, GetHubX(enemyUnit), GetHubY(enemyUnit));
+		} else {
+			directAngleToHub = GetAngle(targetX, targetY, hubX, hubY);
+		}
+
+		//Number of random chances to land
+		for (int j = 0; j < 3; ++j) {
+			//Pick random angle and dist within semicircle (-90 to +90) and (40 to 150)
+			int randAngle = directAngleToHub + _vm->_rnd.getRandomNumber(179) - 90;
+			int randDist = _vm->_rnd.getRandomNumber(109) + 40;
+
+			int x = targetX + randDist * cos(degToRad(randAngle));
+			int y = targetY + randDist * sin(degToRad(randAngle));
+
+			int powAngle = GetPowerAngleFromPoint(hubX, hubY, x, y, 20);
+
+			if (powAngle < 0)
+				continue;
+
+			int power = powAngle / 360;
+			int angle = powAngle - (power * 360);
+
+			int coords = 0;
+			coords = SimulateBuildingLaunch(hubX, hubY, power, angle, 100, 0);
+
+			//if valid, return
+			if (coords > 0) {
+				//warning("The prospective launching hub for this defensive unit is: %d", hubArray[i]);
+
+				setSourceX(hubX);
+				setSourceY(hubY);
+				setTargetX((x + GetMaxX()) % GetMaxX());
+				setTargetY((y + GetMaxY()) % GetMaxY());
+				setSourceUnit(hubArray[i]);
+
+				int unitsArray2 = GetUnitsWithinRadius(targetX + 5, targetY, 200);
+				int shieldCount = 0;
+
+				for (int k = 0; k < 200; ++k) {
+					int thisUnit = _vm->_moonbase->readFromArray(unitsArray2, 0, k);
+
+					if (thisUnit) {
+						if ((GetBuildingType(thisUnit) == BUILDING_SHIELD) && (GetBuildingOwner(thisUnit) == currentPlayer))
+							shieldCount++;
+
+						if ((GetBuildingType(thisUnit) == BUILDING_BRIDGE) && (GetBuildingOwner(thisUnit) == currentPlayer)) {
+							shieldCount--;
+							shieldCount = MAX(-1, shieldCount);
+						}
+					}
+				}
+
+				if ((_vm->_rnd.getRandomNumber((int)pow(3, shieldCount + 1) - 1) == 0) && (GetPlayerEnergy() > 6))
+					setUnit(ITEM_SHIELD);
+				else
+					setUnit(ITEM_ANTIAIR);
+
+				setPower(power);
+				setAngle(angle);
+
+				_vm->nukeArray(unitsArray2);
+				return 1;
+			}
+
+			if (coords < 0) {
+				//drop a bridge for the cord
+				int yCoord  = -coords / GetMaxX();
+				int xCoord = -coords - (yCoord * GetMaxX());
+
+				if (CheckIfWaterState(xCoord, yCoord)) {
+
+					int terrainSquareSize = GetTerrainSquareSize();
+					xCoord = ((xCoord / terrainSquareSize * terrainSquareSize) + (terrainSquareSize / 2));
+					yCoord = ((yCoord / terrainSquareSize * terrainSquareSize) + (terrainSquareSize / 2));
+
+					int xDist = xCoord - x;
+					int yDist = yCoord - y;
+					x = xCoord + (terrainSquareSize * 1.414 * (xDist / (abs(xDist) + 1)));
+					y = yCoord + (terrainSquareSize * 1.414 * (yDist / (abs(yDist) + 1)));
+
+					setTargetX(x);
+					setTargetY(y);
+
+					int nextUnit = GetClosestUnit(x, y, 480, GetCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, 120);
+					powAngle = GetPowerAngleFromPoint(GetHubX(nextUnit), GetHubY(nextUnit), x, y, 15);
+
+					powAngle = abs(powAngle);
+					power = powAngle / 360;
+					angle = powAngle - (power * 360);
+
+					setSourceUnit(nextUnit);
+					setUnit(ITEM_BRIDGE);
+					setPower(power);
+					setAngle(angle);
+
+					return 1;
+				}
+			}
+		}
+	}
+
+	// Else create new hub
+	int count = 0;
+	int coords = 0;
+
+	if (hubIndex == 0) return -3;
+
+	do {
+		int sourceHub = hubArray[_vm->_rnd.getRandomNumber(hubIndex - 1)];
+
+		setSourceX(GetHubX(sourceHub));
+		setSourceY(GetHubY(sourceHub));
+		setSourceUnit(sourceHub);
+		setUnit(ITEM_HUB);
+		setPower(_vm->_rnd.getRandomNumber(299) + 200);
+		setAngle(_vm->_rnd.getRandomNumber(359));
+		count++;
+
+		if (count > (NUM_HUBS * 3)) break;
+
+		coords = SimulateBuildingLaunch(getSourceX(), getSourceY(), getPower(), getAngle(), 100, 0);
+	} while (coords <= 0);
+
+	if (coords > 0) {
+		setTargetX(coords % GetMaxX());
+		setTargetY(coords / GetMaxX());
+	} else {
+		setTargetX(0);
+		setTargetY(0);
+	}
+
+	return -1;
+}
+
+} // End of namespace Scumm
diff --git a/engines/scumm/he/moonbase/ai_targetacquisition.h b/engines/scumm/he/moonbase/ai_targetacquisition.h
new file mode 100644
index 0000000..cf8f295
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_targetacquisition.h
@@ -0,0 +1,150 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef SCUMM_HE_MOONBASE_AI_TARGETACQUISITION_H
+#define SCUMM_HE_MOONBASE_AI_TARGETACQUISITION_H
+
+#include "scumm/he/moonbase/ai_defenseunit.h"
+#include "scumm/he/moonbase/ai_node.h"
+#include "scumm/he/moonbase/ai_tree.h"
+
+namespace Scumm {
+
+const int NUM_IMPT_UNITS = 3;
+const int NUM_SHOT_POSITIONS = 1;
+const int NUM_WEAPONS = 3;
+
+class Sortie : public IContainedObject {
+private:
+	static int _sSourceX;
+	static int _sSourceY;
+
+	static int _sTargetX;
+	static int _sTargetY;
+
+	int _unitType;
+	int _shotPosX, _shotPosY;
+	Common::Array<DefenseUnit *> _enemyDefenses;
+
+
+public:
+	Sortie() {}
+	virtual ~Sortie();
+
+	static void setSourcePos(int x, int y) {
+		_sSourceX = x;
+		_sSourceY = y;
+	}
+	static void setTargetPos(int x, int y) {
+		_sTargetX = x;
+		_sTargetY = y;
+	}
+
+	void setUnitType(int unitType) { _unitType = unitType; }
+
+	void setShotPosX(int shotPosX) { _shotPosX = shotPosX; }
+	void setShotPosY(int shotPosY) { _shotPosY = shotPosY; }
+	void setShotPos(int shotPosX, int shotPosY) {
+		_shotPosX = shotPosX;
+		_shotPosY = shotPosY;
+	}
+
+	void setEnemyDefenses(Common::Array<DefenseUnit *> enemyDefenses) {
+		_enemyDefenses = enemyDefenses;
+	}
+	void setEnemyDefenses(int enemyDefensesScummArray, int defendX, int defendY);
+
+	void printEnemyDefenses();
+
+	static int getSourcePosX() { return _sSourceX; }
+	static int getSourcePosY() { return _sSourceY; }
+	static int getTargetPosX() { return _sTargetX; }
+	static int getTargetPosY() { return _sTargetY; }
+
+	int getUnitType() const { return _unitType; }
+
+	int getShotPosX() const { return _shotPosX; }
+	int getShotPosY() const { return _shotPosY; }
+	int *getShotPos() const;
+
+	Common::Array<DefenseUnit *> getEnemyDefenses() const { return _enemyDefenses; }
+
+	virtual IContainedObject *duplicate();
+
+	virtual int numChildrenToGen();
+	virtual IContainedObject *createChildObj(int, int &completionFlag);
+
+
+	virtual float calcH();
+	virtual int checkSuccess();
+	virtual float calcT();
+};
+
+class Defender {
+private:
+	int _sourceX;
+	int _sourceY;
+	int _targetX;
+	int _targetY;
+	int _sourceUnit;
+	int _power;
+	int _angle;
+	int _unit;
+
+public:
+	void setSourceX(int sourceX) { _sourceX = sourceX; }
+	void setSourceY(int sourceY) { _sourceY = sourceY; }
+	void setTargetX(int targetX) { _targetX = targetX; }
+	void setTargetY(int targetY) { _targetY = targetY; }
+	void setSourceUnit(int sourceUnit) { _sourceUnit = sourceUnit; }
+	void setPower(int power) { _power = power; }
+	void setAngle(int angle) { _angle = angle; }
+	void setUnit(int unit) { _unit = unit; }
+
+	int getSourceX() const { return _sourceX; }
+	int getSourceY() const { return _sourceY; }
+	int getTargetX() const { return _targetX; }
+	int getTargetY() const { return _targetY; }
+	int getSourceUnit() const { return _sourceUnit; }
+	int getPower() const { return _power; }
+	int getAngle() const { return _angle; }
+	int getUnit() const { return _unit; }
+
+	int calculateDefenseUnitPosition(int targetX, int targetY, int index);
+};
+
+class defenseUnitCompare {
+public:
+	bool operator()(DefenseUnit *x, DefenseUnit *y) {
+		//disabled units go at the end
+		if (x->getState() == DUS_OFF) {
+			warning("OFF");
+			return 0;
+		}
+
+		return x->getDistanceTo() < y->getDistanceTo();
+	}
+};
+
+} // End of namespace Scumm
+
+#endif
diff --git a/engines/scumm/he/moonbase/moonbase.cpp b/engines/scumm/he/moonbase/moonbase.cpp
index 34d4368..9cc5040 100644
--- a/engines/scumm/he/moonbase/moonbase.cpp
+++ b/engines/scumm/he/moonbase/moonbase.cpp
@@ -32,6 +32,12 @@ Moonbase::Moonbase(ScummEngine_v71he *vm) : _vm(vm) {
 Moonbase::~Moonbase() {
 }
 
+int Moonbase::readFromArray(int array, int y, int x) {
+	_vm->VAR(116) = array;
+
+	return _vm->readArray(116, y, x);
+}
+
 void Moonbase::blitT14WizImage(uint8 *dst, int dstw, int dsth, int dstPitch, const Common::Rect *clipBox,
 		 uint8 *wizd, int x, int y, int rawROP, int paramROP) {
 	bool premulAlpa = false;
diff --git a/engines/scumm/he/moonbase/moonbase.h b/engines/scumm/he/moonbase/moonbase.h
index 0b47ba6..7b2bdeb 100644
--- a/engines/scumm/he/moonbase/moonbase.h
+++ b/engines/scumm/he/moonbase/moonbase.h
@@ -34,6 +34,8 @@ public:
 	Moonbase(ScummEngine_v71he *vm);
 	~Moonbase();
 
+	int readFromArray(int array, int y, int x);
+
 	void blitT14WizImage(uint8 *dst, int dstw, int dsth, int dstPitch, const Common::Rect *clipBox,
 			 uint8 *wizd, int srcx, int srcy, int rawROP, int paramROP);
 
diff --git a/engines/scumm/he/moonbase/moonbase_fow.cpp b/engines/scumm/he/moonbase/moonbase_fow.cpp
index 3f3730b..48c2219 100644
--- a/engines/scumm/he/moonbase/moonbase_fow.cpp
+++ b/engines/scumm/he/moonbase/moonbase_fow.cpp
@@ -158,9 +158,7 @@ enum FOWElement {
 };
 
 int Moonbase::readFOWVisibilityArray(int array, int y, int x) {
-	_vm->VAR(116) = array;
-
-	if (_vm->readArray(116, y, x) > 0)
+	if (readFromArray(array, y, x) > 0)
 		return FOW_EMPTY;
 
 	return FOW_SOLID;
diff --git a/engines/scumm/module.mk b/engines/scumm/module.mk
index 28153f5..d6199f5 100644
--- a/engines/scumm/module.mk
+++ b/engines/scumm/module.mk
@@ -141,6 +141,7 @@ MODULE_OBJS += \
 	he/logic/soccer.o \
 	he/moonbase/ai_defenseunit.o \
 	he/moonbase/ai_node.o \
+	he/moonbase/ai_targetacquisition.o \
 	he/moonbase/ai_types.o \
 	he/moonbase/ai_weapon.o \
 	he/moonbase/moonbase.o \
diff --git a/engines/scumm/scumm_v6.h b/engines/scumm/scumm_v6.h
index 73268f6..a17bb8f 100644
--- a/engines/scumm/scumm_v6.h
+++ b/engines/scumm/scumm_v6.h
@@ -119,7 +119,10 @@ protected:
 	ArrayHeader *getArray(int array);
 	byte *defineArray(int array, int type, int dim2, int dim1);
 	int findFreeArrayId();
+public:
 	void nukeArray(int array);
+
+protected:
 	virtual int readArray(int array, int index, int base);
 	virtual void writeArray(int array, int index, int base, int value);
 	void shuffleArray(int num, int minIdx, int maxIdx);


Commit: bb88aaf119f2946b7c3fba01c4f7da5d40d2aa5c
    https://github.com/scummvm/scummvm/commit/bb88aaf119f2946b7c3fba01c4f7da5d40d2aa5c
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2016-05-22T00:45:04+02:00

Commit Message:
SCUMM HE: Added Moonbase Traveller class

Changed paths:
  A engines/scumm/he/moonbase/ai_traveller.cpp
  A engines/scumm/he/moonbase/ai_traveller.h
    engines/scumm/module.mk



diff --git a/engines/scumm/he/moonbase/ai_traveller.cpp b/engines/scumm/he/moonbase/ai_traveller.cpp
new file mode 100644
index 0000000..5437ab1
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_traveller.cpp
@@ -0,0 +1,259 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "scumm/he/moonbase/ai_traveller.h"
+#include "scumm/he/moonbase/ai_main.h"
+
+namespace Scumm {
+
+int Traveller::_targetPosX = 0;
+int Traveller::_targetPosY = 0;
+int Traveller::_maxDist = 0;
+
+int Traveller::_numToGen = 0;
+int Traveller::_sizeAngleStep = 0;
+
+Traveller::Traveller() {
+	_waterFlag = 0;
+	setValueG(0);
+	unsetDisabled();
+}
+
+Traveller::Traveller(int originX, int originY) {
+	_waterFlag = 0;
+	setValueG(0);
+	unsetDisabled();
+
+	_posX = originX;
+	_posY = originY;
+}
+
+void Traveller::adjustPosX(int offsetX) {
+	int maxX = GetMaxX();
+	int deltaX = _posX + offsetX;
+
+	if (deltaX < 0) _posX = maxX + deltaX;
+	else if (deltaX > maxX) _posX = deltaX - maxX;
+	else _posX = deltaX;
+}
+
+void Traveller::adjustPosY(int offsetY) {
+	int maxY = GetMaxX();
+	int deltaY = _posY + offsetY;
+
+	if (deltaY < 0) _posY = maxY + deltaY;
+	else if (deltaY > maxY) _posY = deltaY - maxY;
+	else _posY = deltaY;
+}
+
+void Traveller::adjustXY(int offsetX, int offsetY) {
+	adjustPosX(offsetX);
+	adjustPosY(offsetY);
+}
+
+float Traveller::calcH() {
+	float retVal = 0;
+	// Calc dist from here to target
+	retVal = GetDistance(_posX, _posY, _targetPosX, _targetPosY);
+	// Divide by _maxDist to get minimum number of jumps to goal
+	retVal /= static_cast<float>(_maxDist);
+
+	return retVal * 2.0;
+}
+
+int Traveller::numChildrenToGen() {
+	if (!_numToGen)
+		_numToGen = GetAnimSpeed() + 2;
+
+	return _numToGen;
+}
+
+IContainedObject *Traveller::createChildObj(int index, int &completionFlag) {
+	static int nodeCount = 0;
+	static int completionState = 1;
+
+	if (!index) nodeCount = 0;
+
+	nodeCount++;
+
+	Traveller *retTraveller = new Traveller;
+
+	static int dir, angle, power;
+
+	if (completionState) {
+		// Calculate angle between here and target
+		int directAngle = 0;
+
+		if (GetEnergyHogType())
+			directAngle = GetAngle(_posX, _posY, _targetPosX, _targetPosY, 1);
+		else
+			directAngle = GetAngle(_posX, _posY, _targetPosX, _targetPosY);
+
+		// Calculate the offset angle for this index
+		if (!_sizeAngleStep)
+			_sizeAngleStep = 52 - (GetAnimSpeed() * 7);
+
+		dir = _sizeAngleStep * ((static_cast<int>(index / NUM_POWER_STEPS) + 1) >> 1);
+		// Calculate the sign value for the offset for this index
+		int orientation = dir * (((static_cast<int>(index / NUM_POWER_STEPS) % 2) << 1) - 1);
+		// Add the offset angle to the direct angle to target
+		angle = orientation + directAngle;
+
+		// Calculate power for this index
+		int maxPower = 0;
+		int directDist = GetDistance(_posX, _posY, _targetPosX, _targetPosY);
+
+		if (directDist > _maxDist + 120)
+			maxPower = GetMaxPower();
+		else
+			maxPower = (static_cast<float>(directDist) / static_cast<float>(_maxDist + 120)) * GetMaxPower();
+
+		maxPower -= 70;
+		power = maxPower * (1 - ((index % NUM_POWER_STEPS) * SIZE_POWER_STEP));
+	}
+
+	retTraveller->setAngleTo(angle);
+	retTraveller->setPowerTo(power);
+
+	// Set this object's position to the new one determined by the power and angle from above
+	static int lastSuccessful = 0;
+	int coords = 0;
+
+	if (!(index % NUM_POWER_STEPS) || (!lastSuccessful)) {
+		coords = SimulateBuildingLaunch(_posX, _posY, power, angle, 10, 0);
+		lastSuccessful = 0;
+	} else {
+		completionState = 1;
+		lastSuccessful = 0;
+	}
+
+	if (!coords) {
+		completionFlag = 0;
+		completionState = 0;
+		delete retTraveller;
+		return NULL;
+	} else {
+		completionFlag = 1;
+		completionState = 1;
+	}
+
+	int whoseTurn = GetCurrentPlayer();
+	int maxX = GetMaxX();
+
+	// Check new position to see if landing is clear
+	if (coords > 0) {
+		int yCoord = coords / maxX;
+		int xCoord = coords - (yCoord * maxX);
+
+		int terrain = GetTerrain(xCoord, yCoord);
+		assert(terrain == TERRAIN_TYPE_GOOD);
+
+		float pwr = GetMinPower() * .3;
+		float cosine = cos((static_cast<float>(angle) / 360) * (2 * M_PI));
+		float sine = sin((static_cast<float>(angle) / 360) * (2 * M_PI));
+		int xParam = xCoord + (pwr * cosine);
+		int yParam = yCoord + (pwr * sine);
+
+		if (xParam < 0)
+			xParam += GetMaxX();
+		else if (xParam > GetMaxX())
+			xParam -= GetMaxX();
+
+		if (yParam < 0)
+			yParam += GetMaxY();
+		else if (yParam > GetMaxY())
+			yParam -= GetMaxY();
+
+		if (CheckIfWaterState(xParam, yParam)) {
+			delete retTraveller;
+			return NULL;
+		}
+
+		retTraveller->setPosY(yCoord);
+		retTraveller->setPosX(xCoord);
+
+		// Iterate through the previous action list, making sure this one isn't on it
+		for (intVecItr i = (lastXCoord[whoseTurn]).begin(), j = (lastYCoord[whoseTurn]).begin(); i != (lastXCoord[whoseTurn]).end(); ++i, ++j) {
+			// Check if this shot is the same as the last time we tried
+			if ((*i == retTraveller->getPosX()) && (*j == retTraveller->getPosY())) {
+				retTraveller->setDisabled();
+				delete retTraveller;
+				return NULL;
+			}
+		}
+
+		retTraveller->setValueG(getG() + 7 + (dir * DIRECTION_WEIGHT));
+		lastSuccessful = 1;
+	} else {
+		int yCoord  = -coords / maxX;
+		int xCoord = -coords - (yCoord * maxX);
+
+		// If landing fault is because of water, add 1 extra to g and turn on water flag.  Also set coords, and adjust power to water fault location
+		if (CheckIfWaterState(xCoord, yCoord)) {
+			int terrainSquareSize = GetTerrainSquareSize();
+			xCoord = ((xCoord / terrainSquareSize * terrainSquareSize) + (terrainSquareSize / 2));
+			yCoord = ((yCoord / terrainSquareSize * terrainSquareSize) + (terrainSquareSize / 2));
+
+			int xDist = xCoord - _posX;
+			int yDist = yCoord - _posY;
+			retTraveller->setPosX(xCoord + (terrainSquareSize * 1.414 * (xDist / (abs(xDist) + 1))));
+			retTraveller->setPosY(yCoord + (terrainSquareSize * 1.414 * (yDist / (abs(yDist) + 1))));
+
+			int closestHub = GetClosestUnit(retTraveller->getPosX(), retTraveller->getPosY(), GetMaxX(), GetCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, 110);
+
+			retTraveller->setWaterSourceX(GetHubX(closestHub));
+			retTraveller->setWaterSourceY(GetHubY(closestHub));
+			retTraveller->setWaterDestX(retTraveller->getPosX());
+			retTraveller->setWaterDestY(retTraveller->getPosY());
+
+			retTraveller->setPowerTo(power);
+			retTraveller->setAngleTo(angle);
+
+			retTraveller->setValueG(getG() + 10 + (dir * DIRECTION_WEIGHT));
+			retTraveller->enableWaterFlag();
+		} else {
+			// If not, set G to highest value
+			retTraveller->setDisabled();
+			delete retTraveller;
+			return NULL;
+		}
+	}
+
+	return retTraveller;
+}
+
+int Traveller::checkSuccess() {
+	if (GetDistance(_posX + 1, _posY, _targetPosX, _targetPosY) < _maxDist)
+		return SUCCESS;
+
+	return 0;
+}
+
+float Traveller::calcT() {
+	assert(!_disabled);
+
+	if (_disabled) return FAILURE;
+
+	return (checkSuccess() != SUCCESS) ? (getG() + calcH()) : SUCCESS;
+}
+
+} // End of namespace Scumm
diff --git a/engines/scumm/he/moonbase/ai_traveller.h b/engines/scumm/he/moonbase/ai_traveller.h
new file mode 100644
index 0000000..7b1bad9
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_traveller.h
@@ -0,0 +1,122 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef SCUMM_HE_MOONBASE_AI_TRAVELER_H
+#define SCUMM_HE_MOONBASE_AI_TRAVELER_H
+
+#include "scumm/he/moonbase/ai_node.h"
+
+namespace Scumm {
+
+const int NUM_TO_GEN = 9;
+
+const int NUM_POWER_STEPS = 3;
+const double SIZE_POWER_STEP = .15;
+const int SIZE_ANGLE_STEP = 45;
+const int VARIATION_EXTENT = 3;
+const int DIRECTION_WEIGHT = 5;
+
+class Traveller : public IContainedObject {
+private:
+	static int _targetPosX;
+	static int _targetPosY;
+	static int _maxDist;
+
+	static int _numToGen;
+	static int _sizeAngleStep;
+
+	int _sourceHub;
+
+	int _posX;
+	int _posY;
+	int _angleTo;
+	int _powerTo;
+
+	int _disabled;
+	int _waterFlag;
+	int _waterSourceX;
+	int _waterSourceY;
+	int _waterDestX;
+	int _waterDestY;
+
+
+protected:
+	virtual float calcH();
+
+public:
+	Traveller();
+	Traveller(int originX, int originY);
+	~Traveller() {}
+
+	IContainedObject *duplicate() { return this; }
+
+	static void setTargetPosX(int posX) { _targetPosX = posX; }
+	static void setTargetPosY(int posY) { _targetPosY = posY; }
+	static void setMaxDist(int maxDist) { _maxDist = maxDist; }
+
+	void setSourceHub(int sourceHub) { _sourceHub = sourceHub; }
+
+	void setPosX(int posX) { _posX = posX; }
+	void setPosY(int posY) { _posY = posY; }
+	void setAngleTo(int angleTo) { _angleTo = angleTo; }
+	void setPowerTo(int powerTo) { _powerTo = powerTo; }
+
+	void setWaterSourceX(int waterSourceX) { _waterSourceX = waterSourceX; }
+	void setWaterSourceY(int waterSourceY) { _waterSourceY = waterSourceY; }
+
+	void setWaterDestX(int waterDestX) { _waterDestX = waterDestX; }
+	void setWaterDestY(int waterDestY) { _waterDestY = waterDestY; }
+
+	int getSourceHub() const { return _sourceHub; }
+
+	int getPosX() const { return _posX; }
+	int getPosY() const { return _posY; }
+	int getAngleTo() const { return _angleTo; }
+	int getPowerTo() const { return _powerTo; }
+
+	int getWaterSourceX() const { return _waterSourceX; }
+	int getWaterSourceY() const { return _waterSourceY; }
+	int getWaterDestX() const { return _waterDestX; }
+	int getWaterDestY() const { return _waterDestY; }
+
+	void setDisabled() { _disabled = 1; }
+	void unsetDisabled() { _disabled = 0; }
+	int getDisabled() { return _disabled; }
+
+	void adjustPosX(int offsetX);
+	void adjustPosY(int offsetY);
+	void adjustXY(int offsetX, int offsetY);
+
+	void enableWaterFlag() { _waterFlag = 1; }
+	void disableWaterFlag() { _waterFlag = 0; }
+	int GetWaterFlag() const { return _waterFlag; }
+
+	virtual int numChildrenToGen();
+	virtual IContainedObject *createChildObj(int, int &);
+
+	virtual int checkSuccess();
+	virtual float calcT();
+};
+
+} // End of namespace Scumm
+
+#endif
diff --git a/engines/scumm/module.mk b/engines/scumm/module.mk
index d6199f5..57b6872 100644
--- a/engines/scumm/module.mk
+++ b/engines/scumm/module.mk
@@ -142,6 +142,7 @@ MODULE_OBJS += \
 	he/moonbase/ai_defenseunit.o \
 	he/moonbase/ai_node.o \
 	he/moonbase/ai_targetacquisition.o \
+	he/moonbase/ai_traveller.o \
 	he/moonbase/ai_types.o \
 	he/moonbase/ai_weapon.o \
 	he/moonbase/moonbase.o \


Commit: 26b5416433ff2d7fa73ce51ede62ebc1236a2c21
    https://github.com/scummvm/scummvm/commit/26b5416433ff2d7fa73ce51ede62ebc1236a2c21
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2016-05-22T00:45:04+02:00

Commit Message:
SCUMM HE: Moved Moonbase stuff to v90he

Changed paths:
    engines/scumm/he/intern_he.h
    engines/scumm/he/moonbase/ai_main.h
    engines/scumm/he/moonbase/moonbase.cpp
    engines/scumm/he/moonbase/moonbase.h
    engines/scumm/he/wiz_he.cpp
    engines/scumm/scumm.cpp
    engines/scumm/scumm.h
    engines/scumm/scumm_v2.h
    engines/scumm/scumm_v6.h



diff --git a/engines/scumm/he/intern_he.h b/engines/scumm/he/intern_he.h
index 06e6b24..023b46d 100644
--- a/engines/scumm/he/intern_he.h
+++ b/engines/scumm/he/intern_he.h
@@ -247,10 +247,6 @@ public:
 	void queueAuxEntry(int actorNum, int subIndex);
 
 	void remapHEPalette(const uint8 *src, uint8 *dst);
-
-public:
-	/* Moonbase stuff */
-	Moonbase *_moonbase;
 };
 
 class ScummEngine_v72he : public ScummEngine_v71he {
@@ -430,6 +426,7 @@ protected:
 
 class ScummEngine_v90he : public ScummEngine_v80he {
 	friend class LogicHE;
+	friend class Moonbase;
 	friend class MoviePlayer;
 	friend class Sprite;
 
@@ -458,6 +455,9 @@ protected:
 	Sprite *_sprite;
 
 public:
+	Moonbase *_moonbase;
+
+public:
 	ScummEngine_v90he(OSystem *syst, const DetectorResult &dr);
 	~ScummEngine_v90he();
 
diff --git a/engines/scumm/he/moonbase/ai_main.h b/engines/scumm/he/moonbase/ai_main.h
index cfd3aad..1317f62 100644
--- a/engines/scumm/he/moonbase/ai_main.h
+++ b/engines/scumm/he/moonbase/ai_main.h
@@ -27,9 +27,9 @@
 
 namespace Scumm {
 
-class ScummEngine_v71he;
+class ScummEngine_v90he;
 
-extern ScummEngine_v71he *_vm;
+extern ScummEngine_v90he *_vm;
 
 typedef Common::Array<int>::iterator intVecItr;
 
diff --git a/engines/scumm/he/moonbase/moonbase.cpp b/engines/scumm/he/moonbase/moonbase.cpp
index 9cc5040..46d60ec 100644
--- a/engines/scumm/he/moonbase/moonbase.cpp
+++ b/engines/scumm/he/moonbase/moonbase.cpp
@@ -33,7 +33,7 @@ Moonbase::~Moonbase() {
 }
 
 int Moonbase::readFromArray(int array, int y, int x) {
-	_vm->VAR(116) = array;
+	_vm->VAR(((ScummEngine_v90he *)_vm)->VAR_U32_ARRAY_UNK) = array;
 
 	return _vm->readArray(116, y, x);
 }
diff --git a/engines/scumm/he/moonbase/moonbase.h b/engines/scumm/he/moonbase/moonbase.h
index 7b2bdeb..a056b54 100644
--- a/engines/scumm/he/moonbase/moonbase.h
+++ b/engines/scumm/he/moonbase/moonbase.h
@@ -40,6 +40,10 @@ public:
 			 uint8 *wizd, int srcx, int srcy, int rawROP, int paramROP);
 
 	// FOW Stuff
+	bool isFOW(int resNum, int state, uint32 conditionBits) {
+		return resNum == _fowSentinelImage && state == _fowSentinelState && conditionBits == _fowSentinelConditionBits;
+	}
+
 	void initFOW();
 	void releaseFOWResources();
 
diff --git a/engines/scumm/he/wiz_he.cpp b/engines/scumm/he/wiz_he.cpp
index 0976a53..0ebfe67 100644
--- a/engines/scumm/he/wiz_he.cpp
+++ b/engines/scumm/he/wiz_he.cpp
@@ -1573,10 +1573,8 @@ uint8 *Wiz::drawWizImage(int resNum, int state, int maskNum, int maskState, int
 	}
 
 	if (_vm->_game.id == GID_MOONBASE &&
-			resNum == _vm->_moonbase->_fowSentinelImage &&
-			state == _vm->_moonbase->_fowSentinelState &&
-			conditionBits == _vm->_moonbase->_fowSentinelConditionBits) {
-		_vm->_moonbase->renderFOW(dst, dstPitch, dstType, cw, ch, flags);
+			((ScummEngine_v90he *)_vm)->_moonbase->isFOW(resNum, state, conditionBits)) {
+		((ScummEngine_v90he *)_vm)->_moonbase->renderFOW(dst, dstPitch, dstType, cw, ch, flags);
 		x1 = 0;
 		y1 = 0;
 		width = rScreen.width();
@@ -1816,7 +1814,7 @@ void Wiz::copy555WizImage(uint8 *dst, uint8 *wizd, int dstPitch, int dstType,
 	uint32 compID = READ_LE_UINT32(wizd);
 
 	if (compID == 0x12340102) {
-		_vm->_moonbase->blitT14WizImage(dst, dstw, dsth, dstPitch, clipBox, wizd, srcx, srcy, rawROP, paramROP);
+		((ScummEngine_v90he *)_vm)->_moonbase->blitT14WizImage(dst, dstw, dsth, dstPitch, clipBox, wizd, srcx, srcy, rawROP, paramROP);
 	} else if (compID == 0x12340802) {
 		warning("Distorion codec");
 	} else if (compID == 0x12340902) {
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index 1f8a85b..cfb0c70 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -833,16 +833,9 @@ ScummEngine_v71he::ScummEngine_v71he(OSystem *syst, const DetectorResult &dr)
 	_skipProcessActors = 0;
 
 	VAR_WIZ_TCOLOR = 0xFF;
-
-	/* Moonbase stuff */
-	_moonbase = 0;
-
-	if (_game.id == GID_MOONBASE)
-		_moonbase = new Moonbase(this);
 }
 
 ScummEngine_v71he::~ScummEngine_v71he() {
-	delete _moonbase;
 	delete _wiz;
 }
 
@@ -892,6 +885,12 @@ ScummEngine_v90he::ScummEngine_v90he(OSystem *syst, const DetectorResult &dr)
 
 	VAR_U32_VERSION = 0xFF;
 	VAR_U32_ARRAY_UNK = 0xFF;
+
+	/* Moonbase stuff */
+	_moonbase = 0;
+
+	if (_game.id == GID_MOONBASE)
+		_moonbase = new Moonbase(this);
 }
 
 ScummEngine_v90he::~ScummEngine_v90he() {
@@ -903,6 +902,7 @@ ScummEngine_v90he::~ScummEngine_v90he() {
 	if (_game.heversion >= 99) {
 		free(_hePalettes);
 	}
+	delete _moonbase;
 }
 
 ScummEngine_vCUPhe::ScummEngine_vCUPhe(OSystem *syst, const DetectorResult &dr) : Engine(syst){
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index 62386d3..e519fd9 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -701,9 +701,11 @@ protected:
 	void ignoreScriptByte() { fetchScriptByte(); }
 	void push(int a);
 	int pop();
+public: // TODO. FIXME
 	virtual int readVar(uint var);
 	virtual void writeVar(uint var, int value);
 
+protected:
 	void beginCutscene(int *args);
 	void endCutscene();
 	void abortCutscene();
diff --git a/engines/scumm/scumm_v2.h b/engines/scumm/scumm_v2.h
index e438008..339964b 100644
--- a/engines/scumm/scumm_v2.h
+++ b/engines/scumm/scumm_v2.h
@@ -77,9 +77,11 @@ protected:
 
 	void getResultPosIndirect();
 	virtual void getResultPos();
+public: // TODO. FIXME
 	virtual int readVar(uint var);
 	virtual void writeVar(uint var, int value);
 
+protected:
 	virtual int getActiveObject();
 	void ifStateCommon(byte type);
 	void ifNotStateCommon(byte type);
diff --git a/engines/scumm/scumm_v6.h b/engines/scumm/scumm_v6.h
index a17bb8f..83b9f2f 100644
--- a/engines/scumm/scumm_v6.h
+++ b/engines/scumm/scumm_v6.h
@@ -119,7 +119,7 @@ protected:
 	ArrayHeader *getArray(int array);
 	byte *defineArray(int array, int type, int dim2, int dim1);
 	int findFreeArrayId();
-public:
+public: // FIXME. TODO
 	void nukeArray(int array);
 
 protected:


Commit: 44333f74533f4d5a6c519923e31072fd7d87ac02
    https://github.com/scummvm/scummvm/commit/44333f74533f4d5a6c519923e31072fd7d87ac02
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2016-05-22T00:45:05+02:00

Commit Message:
SCUMM HE: Added main Moonbase AI code

Changed paths:
  A engines/scumm/he/moonbase/ai_main.cpp
  A engines/scumm/he/moonbase/ai_pattern.h
    engines/scumm/he/intern_he.h
    engines/scumm/he/moonbase/ai_defenseunit.cpp
    engines/scumm/he/moonbase/ai_main.h
    engines/scumm/he/moonbase/ai_targetacquisition.cpp
    engines/scumm/he/moonbase/ai_traveller.cpp
    engines/scumm/he/moonbase/ai_traveller.h
    engines/scumm/he/moonbase/ai_tree.h
    engines/scumm/he/moonbase/ai_types.h
    engines/scumm/he/moonbase/moonbase.cpp
    engines/scumm/he/moonbase/moonbase.h
    engines/scumm/module.mk
    engines/scumm/scumm.cpp
    engines/scumm/scumm.h
    engines/scumm/scumm_v2.h
    engines/scumm/vars.cpp



diff --git a/engines/scumm/he/intern_he.h b/engines/scumm/he/intern_he.h
index 023b46d..72c11c9 100644
--- a/engines/scumm/he/intern_he.h
+++ b/engines/scumm/he/intern_he.h
@@ -553,8 +553,15 @@ protected:
 	byte VAR_NUM_PALETTES;
 	byte VAR_NUM_UNK;
 
+public: // FIXME. TODO. Should be protected. Used by Moonbase
 	byte VAR_U32_VERSION;
 	byte VAR_U32_ARRAY_UNK;
+	byte VAR_U32_USER_VAR_A;
+	byte VAR_U32_USER_VAR_B;
+	byte VAR_U32_USER_VAR_C;
+	byte VAR_U32_USER_VAR_D;
+	byte VAR_U32_USER_VAR_E;
+	byte VAR_U32_USER_VAR_F;
 };
 
 class ScummEngine_v99he : public ScummEngine_v90he {
diff --git a/engines/scumm/he/moonbase/ai_defenseunit.cpp b/engines/scumm/he/moonbase/ai_defenseunit.cpp
index 783c7c7..43223dd 100644
--- a/engines/scumm/he/moonbase/ai_defenseunit.cpp
+++ b/engines/scumm/he/moonbase/ai_defenseunit.cpp
@@ -123,13 +123,13 @@ int AntiAirUnit::selectWeapon(int index) {
 
 	case 2:
 		if (getState() == DUS_OFF) {
-			if (GetPlayerEnergy() > 6) {
+			if (getPlayerEnergy() > 6) {
 				if (!_vm->_rnd.getRandomNumber(3)) {
 					return ITEM_VIRUS;
 				}
 			}
 
-			if (GetPlayerEnergy() > 2) {
+			if (getPlayerEnergy() > 2) {
 				if (!_vm->_rnd.getRandomNumber(1)) {
 					return ITEM_SPIKE;
 				}
@@ -169,8 +169,8 @@ Common::Point *ShieldUnit::createTargetPos(int index, int distance, int weaponTy
 		case ITEM_CRAWLER:
 			ratio = MAX(0.0, 1.0 - (static_cast<float>(getRadius()) / static_cast<float>(distance - 20)));
 			{
-				int maxX = GetMaxX();
-				int maxY = GetMaxY();
+				int maxX = getMaxX();
+				int maxY = getMaxY();
 				int thisX = (static_cast<int>(sourceX + ratio * (getPosX() - sourceX)) + maxX) % maxX;
 				int thisY = (static_cast<int>(sourceY + ratio * (getPosY() - sourceY)) + maxY) % maxY;
 				targetPos->x = thisX;
@@ -221,8 +221,8 @@ Common::Point *ShieldUnit::createTargetPos(int index, int distance, int weaponTy
 int ShieldUnit::selectWeapon(int index) {
 	warning("Shield weapon select");
 
-	int myUnit = GetClosestUnit(getPosX(), getPosY(), GetMaxX(), GetCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, 0);
-	int dist = GetDistance(getPosX(), getPosY(), GetHubX(myUnit), GetHubY(myUnit));
+	int myUnit = getClosestUnit(getPosX(), getPosY(), getMaxX(), getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, 0);
+	int dist = getDistance(getPosX(), getPosY(), getHubX(myUnit), getHubY(myUnit));
 
 	if ((dist < (getRadius() - 20)) && (dist > 90)) {
 		return ITEM_SPIKE;
@@ -231,7 +231,7 @@ int ShieldUnit::selectWeapon(int index) {
 	switch (index) {
 	case 0:
 		if (getState() == DUS_OFF)  {
-			if (GetPlayerEnergy() < 3) {
+			if (getPlayerEnergy() < 3) {
 				return ITEM_BOMB;
 			} else {
 				return ITEM_SPIKE;
@@ -287,11 +287,11 @@ Common::Point *MineUnit::createTargetPos(int index, int distance, int weaponType
 }
 
 int MineUnit::selectWeapon(int index) {
-	int myUnit = GetClosestUnit(getPosX(), getPosY(), GetMaxX(), GetCurrentPlayer(), 1, 0, 0, 0);
+	int myUnit = getClosestUnit(getPosX(), getPosY(), getMaxX(), getCurrentPlayer(), 1, 0, 0, 0);
 	int x = getPosX();
 	int y = getPosY();
 
-	int dist = GetDistance(x, y, GetHubX(myUnit), GetHubY(myUnit));
+	int dist = getDistance(x, y, getHubX(myUnit), getHubY(myUnit));
 
 	if ((getState() == DUS_ON) && (dist < 110)) {
 		return ITEM_EMP;
@@ -334,17 +334,17 @@ Common::Point *HubUnit::createTargetPos(int index, int distance, int weaponType,
 int HubUnit::selectWeapon(int index) {
 	warning("Hub weapon select");
 
-	int energy = GetPlayerEnergy();
+	int energy = getPlayerEnergy();
 
 	if (energy > 6) {
 		//possibly choose crawler
-		if (GetBuildingWorth(getID()) > 21) {
+		if (getBuildingWorth(getID()) > 21) {
 			return ITEM_CRAWLER;
 		}
 	}
 
 	//choose betw/ bomb and cluster
-	if (GetBuildingArmor(getID()) < 1.5) {
+	if (getBuildingArmor(getID()) < 1.5) {
 		return ITEM_CLUSTER;
 	}
 
@@ -483,17 +483,17 @@ Common::Point *EnergyUnit::createTargetPos(int index, int distance, int weaponTy
 int EnergyUnit::selectWeapon(int index) {
 	warning("Energy weapon select");
 
-	int energy = GetPlayerEnergy();
+	int energy = getPlayerEnergy();
 
 	if (energy > 6) {
 		//possibly choose crawler
-		if (GetBuildingWorth(getID()) > 21) {
+		if (getBuildingWorth(getID()) > 21) {
 			return ITEM_CRAWLER;
 		}
 	}
 
 	//choose betw/ bomb and cluster
-	if (GetBuildingArmor(getID()) < 1.5) {
+	if (getBuildingArmor(getID()) < 1.5) {
 		return ITEM_CLUSTER;
 	}
 
@@ -539,17 +539,17 @@ Common::Point *OffenseUnit::createTargetPos(int index, int distance, int weaponT
 int OffenseUnit::selectWeapon(int index) {
 	warning("Offense weapon select");
 
-	int energy = GetPlayerEnergy();
+	int energy = getPlayerEnergy();
 
 	if (energy > 6) {
 		//possibly choose crawler
-		if (GetBuildingWorth(getID()) > 21) {
+		if (getBuildingWorth(getID()) > 21) {
 			return ITEM_CRAWLER;
 		}
 	}
 
 	//choose betw/ bomb and cluster
-	if (GetBuildingArmor(getID()) < 1.5) {
+	if (getBuildingArmor(getID()) < 1.5) {
 		return ITEM_CLUSTER;
 	}
 
@@ -589,13 +589,13 @@ Common::Point *CrawlerUnit::createTargetPos(int index, int distance, int weaponT
 
 int CrawlerUnit::selectWeapon(int index) {
 	warning("Crawler weapon select");
-	int myUnit = GetClosestUnit(getPosX(), getPosY(), GetMaxX(), GetCurrentPlayer(), 1, 0, 0, 0);
-	int dist = GetDistance(GetHubX(myUnit), GetHubY(myUnit), getPosX(), getPosY());
+	int myUnit = getClosestUnit(getPosX(), getPosY(), getMaxX(), getCurrentPlayer(), 1, 0, 0, 0);
+	int dist = getDistance(getHubX(myUnit), getHubY(myUnit), getPosX(), getPosY());
 
 	int x = getPosX();
 	int y = getPosY();
-	int energy = GetPlayerEnergy();
-	int terrain = GetTerrain(x, y);
+	int energy = getPlayerEnergy();
+	int terrain = getTerrain(x, y);
 
 	if (terrain != TERRAIN_TYPE_WATER) {
 		if ((energy > 2) && (dist < 220)) {
diff --git a/engines/scumm/he/moonbase/ai_main.cpp b/engines/scumm/he/moonbase/ai_main.cpp
new file mode 100644
index 0000000..501aab5
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_main.cpp
@@ -0,0 +1,3124 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "scumm/he/intern_he.h"
+
+#include "scumm/he/moonbase/moonbase.h"
+#include "scumm/he/moonbase/ai_main.h"
+#include "scumm/he/moonbase/ai_traveller.h"
+#include "scumm/he/moonbase/ai_targetacquisition.h"
+#include "scumm/he/moonbase/ai_types.h"
+#include "scumm/he/moonbase/ai_pattern.h"
+
+namespace Scumm {
+
+ScummEngine_v90he *_vm;
+
+enum {
+	F_GET_SCUMM_DATA = 0,
+	F_GET_WORLD_DIST = 1,
+	F_GET_WORLD_ANGLE = 2,
+	F_GET_TERRAIN_TYPE = 3,
+	F_GET_CLOSEST_UNIT = 4,
+	F_SIMULATE_BUILDING_LAUNCH = 5,
+	F_GET_POWER_ANGLE_FROM_POINT = 6,
+	F_CHECK_IF_WATER_STATE = 7,
+	F_GET_UNITS_WITHIN_RADIUS = 8,
+	F_GET_LANDING_POINT = 9,
+	F_GET_ENEMY_UNITS_VISIBLE = 10,
+	F_CHECK_IF_WATER_SQUARE = 11,
+	F_GET_GROUND_ALTITUDE = 12,
+	F_CHECK_FOR_CORD_OVERLAP = 13,
+	F_CHECK_FOR_ANGLE_OVERLAP = 14,
+	F_ESTIMATE_NEXT_ROUND_ENERGY = 15,
+	F_CHECK_FOR_UNIT_OVERLAP = 16,
+	F_GET_COORDINATE_VISIBILITY = 17,
+	F_CHECK_FOR_ENERGY_SQUARE = 18,
+	F_AI_CHAT = 19
+};
+
+enum {
+	D_GET_HUB_X = 1,
+	D_GET_HUB_Y = 2,
+	D_GET_WORLD_X_SIZE = 3,
+	D_GET_WORLD_Y_SIZE = 4,
+	D_GET_CURRENT_PLAYER = 5,
+	D_GET_MAX_POWER = 6,
+	D_GET_MIN_POWER = 7,
+	D_GET_TERRAIN_SQUARE_SIZE = 8,
+	D_GET_BUILDING_OWNER = 9,
+	D_GET_BUILDING_STATE = 10,
+	D_GET_BUILDING_TYPE = 11,
+	D_DEBUG_BREAK = 12,
+	D_GET_ENERGY_POOLS_ARRAY = 13,
+	D_GET_COORDINATE_VISIBILITY = 14,
+	D_GET_UNIT_VISIBILITY = 15,
+	D_GET_ENERGY_POOL_VISIBILITY = 16,
+	D_GET_NUMBER_OF_POOLS = 17,
+	D_GET_NUMBER_OF_PLAYERS = 18,
+	D_GET_BUILDING_ARMOR = 19,
+	D_GET_BUILDING_WORTH = 20,
+	D_GET_PLAYER_ENERGY = 21,
+	D_GET_PLAYER_MAX_TIME = 22,
+	D_GET_WIND_X_SPEED = 23,
+	D_GET_WIND_Y_SPEED = 24,
+	D_GET_TOTAL_WIND_SPEED = 25,
+	D_GET_WIND_X_SPEED_MAX = 26,
+	D_GET_WIND_Y_SPEED_MAX = 27,
+	D_GET_BIG_X_SIZE = 28,
+	D_GET_BIG_Y_SIZE = 29,
+	D_GET_ENERGY_POOL_WIDTH = 30,
+	D_GET_BUILDING_MAX_ARMOR = 31,
+	D_GET_TIMER_VALUE = 32,
+	D_GET_LAST_ATTACKED_X = 33,
+	D_GET_LAST_ATTACKED_Y = 34,
+	D_PRINT_DEBUG_TIMER = 35,
+	D_GET_PLAYER_TEAM = 36,
+	D_GET_BUILDING_TEAM = 37,
+	D_GET_FOW = 38,
+	D_GET_ANIM_SPEED = 39,
+	D_GET_BUILDING_STACK_PTR = 40,
+	D_GET_TURN_COUNTER = 41
+};
+
+enum {
+	AI_TYPE_PLAYER_NUM = 0,
+	AI_TYPE_TYPE = 1
+};
+
+enum {
+	ENERGY_MODE = 0,
+	OFFENSE_MODE = 1,
+	DEFENSE_MODE = 2
+};
+
+enum {
+	LAUNCH_SOURCE_HUB = 0,
+	LAUNCH_UNIT = 1,
+	LAUNCH_ANGLE = 2,
+	LAUNCH_POWER = 3,
+
+	MAX_LAUNCH_POWER = 560,
+	MAX_FIRING_DISTANCE = 560
+};
+
+enum {
+	SCALE_X = 50,
+	SCALE_Y = 50,
+	SCALE_Z = 50,
+
+	GRAVITY_CONSTANT = (MAX_LAUNCH_POWER *MAX_LAUNCH_POWER) / MAX_FIRING_DISTANCE,
+
+	HEIGHT_LOW = 20,
+
+	NODE_RADIUS = 7,
+	NODE_DIAMETER = NODE_RADIUS * 2 + 2,
+	NODE_DETECT_RADIUS = NODE_RADIUS - 1,
+
+	BUILDING_HUB_RADIUS = 16
+};
+
+enum {
+	STATE_CHOOSE_BEHAVIOR = 0,
+	STATE_CHOOSE_TARGET = 1,
+	STATE_ATTEMPT_SEARCH = 2,
+	STATE_INIT_APPROACH_TARGET = 3,
+	STATE_APPROACH_TARGET = 4,
+	STATE_INIT_ACQUIRE_TARGET = 5,
+	STATE_ACQUIRE_TARGET = 6,
+	STATE_ENERGIZE_TARGET = 7,
+	STATE_OFFEND_TARGET = 8,
+	STATE_DEFEND_TARGET = 9,
+	STATE_LAUNCH = 10,
+	STATE_CRAWLER_DECISION = 11,
+
+	TREE_DEPTH = 2
+};
+
+AIEntity *AItype[5];
+
+int AIstate = STATE_CHOOSE_BEHAVIOR;
+int behavior = 2;
+
+patternList *moveList[5];
+
+int *storedLaunchAction[5] = {NULL};
+
+const int *MCP_params;
+
+Common::Array<int> lastXCoord[5];
+Common::Array<int> lastYCoord[5];
+
+void resetAI() {
+	AIstate = STATE_CHOOSE_BEHAVIOR;
+	warning("----------------------> Resetting AI");
+
+	for (int i = 1; i != 5; i++) {
+		if (AItype[i]) {
+			delete AItype[i];
+			AItype[i] = NULL;
+		}
+
+		AItype[i] = new AIEntity(BRUTAKAS);
+	}
+
+	for (int i = 1; i != 5; i++) {
+		if (moveList[i]) {
+			delete moveList[i];
+			moveList[i] = NULL;
+		}
+
+		moveList[i] = new patternList;
+	}
+}
+
+void cleanUpAI() {
+	warning("----------------------> Cleaning Up AI");
+
+	for (int i = 1; i != 5; i++) {
+		if (AItype[i]) {
+			delete AItype[i];
+			AItype[i] = NULL;
+		}
+	}
+
+	for (int i = 1; i != 5; i++) {
+		if (moveList[i]) {
+			delete moveList[i];
+			moveList[i] = NULL;
+		}
+	}
+}
+
+void setAIType(const int paramCount, const int *params) {
+	if (AItype[params[AI_TYPE_PLAYER_NUM]]) {
+		delete AItype[params[AI_TYPE_PLAYER_NUM]];
+		AItype[params[AI_TYPE_PLAYER_NUM]] = NULL;
+	}
+
+	AItype[params[AI_TYPE_PLAYER_NUM]] = new AIEntity(params[AI_TYPE_TYPE]);
+
+	if (params[AI_TYPE_TYPE] == ENERGY_HOG) {
+		energyHogType = 1;
+	} else {
+		energyHogType = 0;
+	}
+
+	warning("AI for player %d is %s", params[AI_TYPE_PLAYER_NUM], AItype[params[AI_TYPE_PLAYER_NUM]]->getNameString());
+}
+
+int masterControlProgram(const int paramCount, const int *params) {
+	static Tree *myTree;
+
+	static int index;
+
+	MCP_params = params;
+
+	static int lastSource[5];
+	static int lastAngle[5];
+	static int lastPower[5];
+
+
+	static int sourceHub;
+	static int target;
+
+	static int targetX;
+	static int targetY;
+
+	static int _acquireTarget = 0;
+
+	static int *launchAction = NULL;
+	static int *currentLaunchAction = NULL;
+
+	static int OLflag = 0;
+	static int TAflag = 0;
+
+
+	Node *retNode;
+	static int retNodeFlag;
+
+	// Memory cleanup in case of quit during game
+	if (_vm->readVar(_vm->VAR_U32_USER_VAR_F)) {
+		if (myTree != NULL) {
+			delete myTree;
+			myTree = NULL;
+		}
+
+		if (launchAction != NULL) {
+			delete launchAction;
+			launchAction = NULL;
+		}
+
+		if (currentLaunchAction != NULL) {
+			delete currentLaunchAction;
+			currentLaunchAction = NULL;
+		}
+
+		return 1;
+	}
+
+	int currentPlayer = getCurrentPlayer();
+
+	int maxTime = getPlayerMaxTime();
+	int timerValue = getTimerValue(3);
+
+	// If timer has run out
+	if ((AIstate > STATE_CHOOSE_BEHAVIOR) && ((maxTime) && (timerValue > maxTime))) {
+		if (myTree != NULL) {
+			delete myTree;
+			myTree = NULL;
+		}
+
+		if (launchAction != NULL) {
+			delete launchAction;
+			launchAction = NULL;
+		}
+
+		launchAction = new int[4];
+
+		if (currentLaunchAction != NULL) {
+			launchAction[LAUNCH_SOURCE_HUB] = currentLaunchAction[LAUNCH_SOURCE_HUB];
+			launchAction[LAUNCH_UNIT] = currentLaunchAction[LAUNCH_UNIT];
+			launchAction[LAUNCH_ANGLE] = currentLaunchAction[LAUNCH_ANGLE];
+			launchAction[LAUNCH_POWER] = currentLaunchAction[LAUNCH_POWER];
+			delete currentLaunchAction;
+			currentLaunchAction = NULL;
+		} else {
+			if (!_vm->_rnd.getRandomNumber(1))
+				launchAction[1] = ITEM_TIME_EXPIRED;
+			else
+				launchAction[1] = SKIP_TURN;
+		}
+
+		AIstate = STATE_LAUNCH;
+	}
+
+	static int oldAIstate = 0;
+
+	if (oldAIstate != AIstate) {
+		warning("<<%d>>", AIstate);
+		oldAIstate = AIstate;
+	}
+
+	switch (AIstate) {
+	case STATE_CHOOSE_BEHAVIOR:
+		behavior = chooseBehavior();
+		warning("Behavior mode: %d", behavior);
+
+		if (_vm->_rnd.getRandomNumber(99) < AItype[getCurrentPlayer()]->getBehaviorVariation() * AI_VAR_BASE_BEHAVIOR + 1) {
+			if (_vm->_rnd.getRandomNumber(1)) {
+				behavior--;
+
+				if (behavior < ENERGY_MODE) behavior = DEFENSE_MODE;
+			} else {
+				behavior++;
+
+				if (behavior > DEFENSE_MODE) behavior = ENERGY_MODE;
+			}
+
+			warning("Alternative behavior: %d", behavior);
+		}
+
+		if (behavior == ENERGY_MODE)
+			if (!getNumberOfPools())
+				behavior = OFFENSE_MODE;
+
+		if (AItype[getCurrentPlayer()]->getID() == CRAWLER_CHUCKER)
+			behavior = OFFENSE_MODE;
+
+		if (launchAction != NULL) {
+			delete launchAction;
+			launchAction = NULL;
+		}
+
+		index = 0;
+		AIstate = STATE_CHOOSE_TARGET;
+		break;
+
+	case STATE_CHOOSE_TARGET:
+		target = chooseTarget(behavior);
+
+		if (!target)
+			target = chooseTarget(OFFENSE_MODE);
+
+		if (behavior == ENERGY_MODE) {
+			int energyPoolScummArray = getEnergyPoolsArray();
+			targetX = _vm->_moonbase->readFromArray(energyPoolScummArray, target, ENERGY_POOL_X);
+			targetY = _vm->_moonbase->readFromArray(energyPoolScummArray, target, ENERGY_POOL_Y);
+		} else {
+			targetX = getHubX(target);
+			targetY = getHubY(target);
+		}
+
+		warning("Target (%d, %d) id: %d", targetX, targetY, target);
+
+		if (getFOW())
+			AIstate = STATE_ATTEMPT_SEARCH;
+		else
+			AIstate = STATE_INIT_APPROACH_TARGET;
+
+		break;
+
+	case STATE_ATTEMPT_SEARCH:
+		if (!getCoordinateVisibility(targetX, targetY, currentPlayer)) {
+			int closestHub = getClosestUnit(targetX, targetY, getMaxX(), currentPlayer, 1, BUILDING_MAIN_BASE, 1, 0);
+			int targetAngle = calcAngle(getHubX(closestHub), getHubY(closestHub), targetX, targetY);
+			int testX = static_cast<int>(getHubX(closestHub) + (500 * cos(degToRad(targetAngle))) + getMaxX()) % getMaxX();
+			int testY = static_cast<int>(getHubY(closestHub) + (500 * sin(degToRad(targetAngle))) + getMaxY()) % getMaxY();
+
+			int balloonFlag = 0;
+
+			int unitsArray = getUnitsWithinRadius(testX, testY, 500);
+			int unitsCounter = 0;
+
+			//see if any balloons are already in the area
+			int nextBuilding = _vm->_moonbase->readFromArray(unitsArray, 0, unitsCounter);
+
+			while (nextBuilding) {
+				if (((getBuildingType(nextBuilding) == BUILDING_BALLOON) || (getBuildingType(nextBuilding) == BUILDING_TOWER)) && (getBuildingTeam(nextBuilding) == getPlayerTeam(currentPlayer))) {
+					balloonFlag = 1;
+					nextBuilding = 0;
+					continue;
+				}
+
+				unitsCounter++;
+				nextBuilding = _vm->_moonbase->readFromArray(unitsArray, 0, unitsCounter);
+			}
+
+			_vm->nukeArray(unitsArray);
+
+			if (!balloonFlag) {
+				launchAction = new int[4];
+				launchAction[LAUNCH_SOURCE_HUB] = closestHub;
+
+				if (getPlayerEnergy() > 3) {
+					launchAction[LAUNCH_UNIT] = ITEM_BALLOON;
+					launchAction[LAUNCH_POWER] = getMaxPower();
+				} else {
+					launchAction[LAUNCH_UNIT] = ITEM_TOWER;
+					launchAction[LAUNCH_POWER] = getMinPower();
+				}
+
+				launchAction[LAUNCH_ANGLE] = targetAngle + (_vm->_rnd.getRandomNumber(89) - 45);
+
+				int newTargetPos = abs(fakeSimulateWeaponLaunch(getHubX(closestHub), getHubY(closestHub), launchAction[LAUNCH_POWER], launchAction[LAUNCH_ANGLE]));
+				targetX = newTargetPos % getMaxX();
+				targetY = newTargetPos / getMaxY();
+
+				AIstate = STATE_INIT_ACQUIRE_TARGET;
+				break;
+			}
+		}
+
+		AIstate = STATE_INIT_APPROACH_TARGET;
+		break;
+
+	case STATE_INIT_APPROACH_TARGET:
+	{
+		int closestOL = getClosestUnit(targetX, targetY, 900, currentPlayer, 1, BUILDING_OFFENSIVE_LAUNCHER, 1);
+
+		if (closestOL && (behavior == OFFENSE_MODE)) {
+			AIstate = STATE_OFFEND_TARGET;
+			break;
+		}
+	}
+
+	// get closest hub...if attack mode and almost close enough, maybe throw an offense
+	if ((behavior == OFFENSE_MODE) && (getPlayerEnergy() > 6)) {
+		if (!_vm->_rnd.getRandomNumber(2)) {
+			int closestHub = getClosestUnit(targetX, targetY, getMaxX(), currentPlayer, 1, BUILDING_MAIN_BASE, 1);
+
+			int dist = getDistance(targetX, targetY, getHubX(closestHub), getHubY(closestHub));
+
+			if ((dist > 470) && (dist < 900)) {
+				int closestOL = getClosestUnit(targetX, targetY, 900, currentPlayer, 1, BUILDING_OFFENSIVE_LAUNCHER, 0);
+
+				if (!closestOL) {
+					// Launch an OL
+					OLflag = 1;
+					targetX = getHubX(closestHub);
+					targetY = getHubY(closestHub);
+
+					AIstate = STATE_DEFEND_TARGET;
+					break;
+				}
+			}
+		}
+	}
+
+	if ((behavior == OFFENSE_MODE) && (AItype[currentPlayer]->getID() == RANGER) && (getPlayerEnergy() > 2)) {
+		int closestHub = getClosestUnit(targetX, targetY, getMaxX(), currentPlayer, 1, BUILDING_MAIN_BASE, 1);
+		int dist = getDistance(targetX, targetY, getHubX(closestHub), getHubY(closestHub));
+
+		if (dist < 750) {
+			AIstate = STATE_OFFEND_TARGET;
+			break;
+		}
+	}
+
+	myTree = initApproachTarget(targetX, targetY, &retNode);
+
+	// If no need to approach, apply appropriate behavior
+	if (retNode == myTree->getBaseNode()) {
+		switch (behavior) {
+		case 0:
+			AIstate = STATE_ENERGIZE_TARGET;
+			break;
+
+		case 1:
+			AIstate = STATE_OFFEND_TARGET;
+			break;
+
+		case 2:
+			AIstate = STATE_DEFEND_TARGET;
+			break;
+
+		case -1:
+			AIstate = STATE_LAUNCH;
+			break;
+		}
+
+		delete myTree;
+		myTree = NULL;
+		break;
+	}
+
+	delete retNode;
+	retNode = NULL;
+
+	if (getPlayerEnergy() < 7) {
+		if (!_vm->_rnd.getRandomNumber(3)) {
+			behavior = DEFENSE_MODE;
+			AIstate = STATE_CHOOSE_TARGET;
+		} else {
+			if (launchAction == NULL) {
+				launchAction = new int[4];
+			}
+
+			if (!_vm->_rnd.getRandomNumber(2)) {
+				launchAction[1] = ITEM_TIME_EXPIRED;
+			} else {
+				launchAction[1] = SKIP_TURN;
+			}
+
+			AIstate = STATE_LAUNCH;
+		}
+
+		delete myTree;
+		myTree = NULL;
+		break;
+	}
+
+	AIstate = STATE_CRAWLER_DECISION;
+	break;
+
+	// If behavior is offense, possibly just chuck a crawler
+	case STATE_CRAWLER_DECISION:
+	{
+		// Brace just here to scope throwCrawler
+		int throwCrawler = 0;
+
+		if (behavior == OFFENSE_MODE) {
+			if (getPlayerEnergy() > 6) {
+				int crawlerTest = _vm->_rnd.getRandomNumber(9);
+
+				if (!crawlerTest)
+					throwCrawler = 1;
+			}
+		}
+
+		if (AItype[getCurrentPlayer()]->getID() == CRAWLER_CHUCKER) {
+			if (getPlayerEnergy() > 6) {
+				throwCrawler = 1;
+			} else {
+				launchAction = new int[4];
+
+				if (!_vm->_rnd.getRandomNumber(1))
+					launchAction[1] = ITEM_TIME_EXPIRED;
+				else
+					launchAction[1] = SKIP_TURN;
+
+				AIstate = STATE_LAUNCH;
+				delete myTree;
+				myTree = NULL;
+			}
+		}
+
+		if (throwCrawler) {
+			sourceHub = getClosestUnit(targetX, targetY, getMaxX(), getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1);
+			int powAngle = getPowerAngleFromPoint(getHubX(sourceHub), getHubY(sourceHub), targetX, targetY, 15);
+			powAngle = abs(powAngle);
+			int power = powAngle / 360;
+			int angle = powAngle - (power * 360);
+
+			launchAction = new int[4];
+			launchAction[0] = sourceHub;
+			launchAction[1] = ITEM_CRAWLER;
+			warning("CRAWLER DECISION is launching a crawler");
+			launchAction[2] = angle;
+			launchAction[3] = power;
+			retNodeFlag = 0;
+
+			// Need to update target so acquire can work
+			int targetCoords = fakeSimulateWeaponLaunch(getHubX(launchAction[LAUNCH_SOURCE_HUB]), getHubY(launchAction[LAUNCH_SOURCE_HUB]), launchAction[LAUNCH_POWER], launchAction[LAUNCH_ANGLE]);
+			targetX = targetCoords % getMaxX();
+			targetY = targetCoords / getMaxX();
+			targetX = (targetX + getMaxX()) % getMaxX();
+			targetY = (targetY + getMaxY()) % getMaxY();
+
+			AIstate = STATE_INIT_ACQUIRE_TARGET;
+			delete myTree;
+			myTree = NULL;
+		} else {
+			AIstate = STATE_APPROACH_TARGET;
+		}
+		break;
+	}
+
+	// ApproachTarget returns NULL if target is already reachable
+	case STATE_APPROACH_TARGET:
+		{
+			int x, y;
+			Node *currentNode = NULL;
+			launchAction = approachTarget(myTree, x, y, &currentNode);
+		}
+
+		if (launchAction != NULL) {
+			if (launchAction[0] == -1) {
+				warning("Creating fake target approach hub");
+				TAflag = 1;
+				int closestHub = getClosestUnit(targetX, targetY, getMaxX(), currentPlayer, 1, BUILDING_MAIN_BASE, 1);
+				targetX = getHubX(closestHub);
+				targetY = getHubY(closestHub);
+
+				delete launchAction;
+				launchAction = NULL;
+				AIstate = STATE_DEFEND_TARGET;
+				delete myTree;
+				myTree = NULL;
+				break;
+			}
+
+			// Need to update target so acquire can work
+			int targetCoords = fakeSimulateWeaponLaunch(getHubX(launchAction[LAUNCH_SOURCE_HUB]), getHubY(launchAction[LAUNCH_SOURCE_HUB]), launchAction[LAUNCH_POWER], launchAction[LAUNCH_ANGLE]);
+			targetX = targetCoords % getMaxX();
+			targetY = targetCoords / getMaxX();
+			targetX = (targetX + getMaxX()) % getMaxX();
+			targetY = (targetY + getMaxY()) % getMaxY();
+
+			AIstate = STATE_INIT_ACQUIRE_TARGET;
+			behavior = -1;
+
+			delete myTree;
+			myTree = NULL;
+		}
+
+		break;
+
+	case STATE_ENERGIZE_TARGET:
+		launchAction = energizeTarget(targetX, targetY, index);
+
+		if (launchAction != NULL) {
+			if (launchAction[0]) {
+				assert(launchAction[0] > 0);
+
+				if (launchAction[1] == ITEM_HUB) {
+					index = 0;
+					retNodeFlag = 0;
+					AIstate = STATE_INIT_ACQUIRE_TARGET;
+				} else {
+					index = 0;
+					AIstate = STATE_INIT_ACQUIRE_TARGET;
+				}
+			} else {
+				index++;
+				delete launchAction;
+				launchAction = NULL;
+			}
+		} else {
+			behavior = DEFENSE_MODE;
+			retNodeFlag = 0;
+			index = 0;
+			AIstate = STATE_CHOOSE_TARGET;
+		}
+		break;
+
+	case STATE_OFFEND_TARGET:
+		launchAction = offendTarget(targetX, targetY, index);
+
+		if (launchAction != NULL) {
+			if (launchAction[0]) {
+				retNodeFlag = 0;
+				AIstate = STATE_INIT_ACQUIRE_TARGET;
+			} else {
+				index++;
+				delete launchAction;
+				launchAction = NULL;
+			}
+		}
+		break;
+
+	case STATE_DEFEND_TARGET:
+		launchAction = defendTarget(targetX, targetY, index);
+
+		if (launchAction != NULL) {
+			if (launchAction[0]) {
+				retNodeFlag = 0;
+				AIstate = STATE_INIT_ACQUIRE_TARGET;
+
+				if (launchAction[LAUNCH_UNIT] != ITEM_BRIDGE) {
+					if (OLflag) {
+						OLflag = 0;
+						launchAction[LAUNCH_UNIT] = ITEM_OFFENSE;
+					}
+
+					if (TAflag) {
+						TAflag = 0;
+						warning("replacing defense unit %d with a hub", launchAction[LAUNCH_UNIT]);
+						launchAction[LAUNCH_UNIT] = ITEM_HUB;
+					}
+				}
+			} else {
+				index++;
+				delete launchAction;
+				launchAction = NULL;
+			}
+		}
+		break;
+
+	case STATE_INIT_ACQUIRE_TARGET:
+		myTree = initAcquireTarget(targetX, targetY, &retNode);
+
+		if (myTree == NULL) {
+			AIstate = STATE_LAUNCH;
+			break;
+		}
+
+		// This next line is a questionable fix
+		if (retNode == myTree->getBaseNode())
+			retNodeFlag = 1;
+
+		_acquireTarget = 0;
+
+		AIstate = STATE_ACQUIRE_TARGET;
+		break;
+
+	case STATE_ACQUIRE_TARGET: {
+		// Here to scope tempLaunchAction
+		int *tempLaunchAction = NULL;
+
+		int errCod;
+
+		_acquireTarget++;
+
+		if (!retNodeFlag) {
+			tempLaunchAction = acquireTarget(targetX, targetY, myTree, errCod);
+		} else {
+			warning("NOT acquiring target!!!!!!!");
+			_acquireTarget = 101;
+		}
+
+		if (tempLaunchAction != NULL) {
+			if (launchAction != NULL) {
+				delete launchAction;
+				launchAction = NULL;
+			}
+
+			launchAction = tempLaunchAction;
+		}
+
+		// If no hubs are available for launching...turn must be skipped
+		if (launchAction != NULL) {
+			if (launchAction[LAUNCH_SOURCE_HUB] == 0) {
+				launchAction[LAUNCH_UNIT] = SKIP_TURN;
+			}
+		}
+
+		if ((tempLaunchAction != NULL) || (errCod == 1) || (_acquireTarget > 100)) {
+			if (tempLaunchAction == NULL) {
+				warning("\nABORTING acquire target!!!!!");
+			}
+
+			assert(launchAction != NULL);
+			delete myTree;
+			myTree = NULL;
+			AIstate = STATE_LAUNCH;
+		}
+	}
+	break;
+
+	default:
+		break;
+	}
+
+	if (AIstate == STATE_LAUNCH) {
+		static float randomAttenuation = 1;
+
+		if (((launchAction[LAUNCH_UNIT] == ITEM_REPAIR) || (launchAction[LAUNCH_UNIT] == ITEM_ANTIAIR) || (launchAction[LAUNCH_UNIT] == ITEM_BRIDGE) || (launchAction[LAUNCH_UNIT] == ITEM_TOWER) || (launchAction[LAUNCH_UNIT] == ITEM_RECLAIMER) || (launchAction[LAUNCH_UNIT] == ITEM_BALLOON) || (launchAction[LAUNCH_UNIT] == ITEM_MINE) || (launchAction[LAUNCH_UNIT] == ITEM_ENERGY) || (launchAction[LAUNCH_UNIT] == ITEM_SHIELD) || (launchAction[LAUNCH_UNIT] == ITEM_OFFENSE) || (launchAction[LAUNCH_UNIT] == ITEM_HUB)) && (getBuildingType(launchAction[LAUNCH_SOURCE_HUB]) == BUILDING_OFFENSIVE_LAUNCHER)) {
+			if (getPlayerEnergy() > 2) {
+				launchAction[LAUNCH_UNIT] = ITEM_GUIDED;
+			} else {
+				launchAction[LAUNCH_UNIT] = ITEM_BOMB;
+			}
+		}
+
+		if ((lastSource[currentPlayer] == launchAction[LAUNCH_SOURCE_HUB]) && (lastAngle[currentPlayer] == launchAction[LAUNCH_ANGLE]) && (lastPower[currentPlayer] == launchAction[LAUNCH_POWER])) {
+			randomAttenuation -= .2f;
+			randomAttenuation = MAX(randomAttenuation, 0.0f);
+			warning("Attenuating...");
+		} else {
+			randomAttenuation = 1;
+		}
+
+		lastSource[currentPlayer] = launchAction[LAUNCH_SOURCE_HUB];
+		lastAngle[currentPlayer] = launchAction[LAUNCH_ANGLE];
+		lastPower[currentPlayer] = launchAction[LAUNCH_POWER];
+
+		_vm->writeVar(_vm->VAR_U32_USER_VAR_A, launchAction[LAUNCH_SOURCE_HUB]);
+		int energy = getPlayerEnergy();
+		warning("Computer's energy: %d", energy);
+
+		// Check if there's enough energy to launch this item
+		int n = (launchAction[1] / 6);
+		int energyRequired = (1 + n * n + n);
+
+		if (((energy - energyRequired) < 0) || (!launchAction[LAUNCH_SOURCE_HUB])) {
+			_vm->writeVar(_vm->VAR_U32_USER_VAR_B, SKIP_TURN);
+		} else {
+			assert((launchAction[LAUNCH_UNIT] >= 0) && (launchAction[LAUNCH_UNIT] <= 18));
+
+			if ((launchAction[LAUNCH_UNIT] < 0) || (launchAction[LAUNCH_UNIT] > 18)) launchAction[LAUNCH_UNIT] = 0;
+
+			_vm->writeVar(_vm->VAR_U32_USER_VAR_B, launchAction[LAUNCH_UNIT]);
+		}
+
+		if (launchAction[LAUNCH_UNIT] == ITEM_BOMB) {
+			if (energy > 2) {
+				if (!_vm->_rnd.getRandomNumber(4)) {
+					launchAction[LAUNCH_UNIT] = ITEM_GUIDED;
+				}
+			}
+		}
+
+		{
+			// ANGLE setting
+			int angleAdjustment = 0;
+			angleAdjustment = _vm->_rnd.getRandomNumber(AItype[getCurrentPlayer()]->getAngleVariation() * AI_VAR_BASE_ANGLE) * 3.6;
+			//pos or neg choice
+			angleAdjustment *= ((_vm->_rnd.getRandomNumber(1) * 2) - 1);
+			angleAdjustment *= randomAttenuation;
+
+			int safeAngle = 0;
+			int lu = launchAction[LAUNCH_UNIT];
+
+			if ((lu == ITEM_ANTIAIR) || (lu == ITEM_TOWER) || (lu == ITEM_ENERGY) || (lu == ITEM_SHIELD) || (lu == ITEM_OFFENSE) || (lu == ITEM_HUB)) {
+				for (int i = 1; i < 90; i++) {
+					assert((launchAction[LAUNCH_ANGLE] < 1000) && (angleAdjustment < 360));
+
+					if (checkForAngleOverlap(launchAction[LAUNCH_SOURCE_HUB], launchAction[LAUNCH_ANGLE] + angleAdjustment)) {
+						angleAdjustment += (i % 2 ? i : -i);
+					} else {
+						safeAngle = 1;
+						i = 90;
+					}
+				}
+			} else {
+				safeAngle = 1;
+			}
+
+			if (!safeAngle) angleAdjustment = 0;
+
+			warning("Angle adjustment = %d", angleAdjustment);
+			_vm->writeVar(_vm->VAR_U32_USER_VAR_C, launchAction[LAUNCH_ANGLE] + angleAdjustment);
+		}
+
+		{
+			// POWER setting
+			int powerRangeFactor = (getMaxPower() - getMinPower()) / 100;
+			int powerAdjustment = static_cast<float>(_vm->_rnd.getRandomNumber(AItype[getCurrentPlayer()]->getPowerVariation() * AI_VAR_BASE_POWER)) * powerRangeFactor;
+			//pos or neg choice
+			powerAdjustment *= ((_vm->_rnd.getRandomNumber(1) * 2) - 1);
+			powerAdjustment *= randomAttenuation;
+
+			warning("Power adjustment = %d", powerAdjustment);
+			int newPower = MIN(getMaxPower(), launchAction[LAUNCH_POWER] + powerAdjustment);
+			newPower = MAX(getMinPower(), launchAction[LAUNCH_POWER] + powerAdjustment);
+			_vm->writeVar(_vm->VAR_U32_USER_VAR_D, newPower);
+
+			assert(_vm->readVar(_vm->VAR_U32_USER_VAR_B) != -1);
+
+			if (launchAction[LAUNCH_UNIT] != SKIP_TURN) {
+				if ((launchAction[LAUNCH_SOURCE_HUB] > 0) && (launchAction[LAUNCH_SOURCE_HUB] <= 500)) {
+					if (getBuildingState(launchAction[LAUNCH_SOURCE_HUB]) != 0) {
+						_vm->writeVar(_vm->VAR_U32_USER_VAR_B, SKIP_TURN);
+					}
+				} else {
+					_vm->writeVar(_vm->VAR_U32_USER_VAR_B, SKIP_TURN);
+				}
+			}
+
+			if ((launchAction[LAUNCH_UNIT] == SKIP_TURN) || (launchAction[LAUNCH_POWER] == 0)) {
+				_vm->writeVar(_vm->VAR_U32_USER_VAR_D, -1);
+			}
+		}
+
+
+		if ((launchAction[LAUNCH_SOURCE_HUB] > 0) && (launchAction[LAUNCH_SOURCE_HUB] <= 500)) {
+			int nearbyOpponents = getUnitsWithinRadius(getHubX(launchAction[LAUNCH_SOURCE_HUB]), getHubY(launchAction[LAUNCH_SOURCE_HUB]), 180);
+			int opponentCounter = 0;
+			int opponentBuilding = _vm->_moonbase->readFromArray(nearbyOpponents, 0, opponentCounter);
+			int defenseOn = 0;
+			int defenseOff = 0;
+
+			while (opponentBuilding) {
+				if (getBuildingOwner(opponentBuilding)) {
+					if ((getBuildingType(opponentBuilding) == BUILDING_ANTI_AIR) && (getBuildingTeam(opponentBuilding) != getPlayerTeam(currentPlayer))) {
+						if (getBuildingState(opponentBuilding) == 0) {
+							defenseOn = 1;
+						} else {
+							defenseOff = 1;
+						}
+					}
+				}
+
+				opponentCounter++;
+				opponentBuilding = _vm->_moonbase->readFromArray(nearbyOpponents, 0, opponentCounter);
+			}
+
+			_vm->nukeArray(nearbyOpponents);
+
+			if (defenseOn && defenseOff) {
+				if (!_vm->_rnd.getRandomNumber(1)) {
+					_vm->writeVar(_vm->VAR_U32_USER_VAR_B, ITEM_TIME_EXPIRED);
+				} else {
+					_vm->writeVar(_vm->VAR_U32_USER_VAR_B, SKIP_TURN);
+				}
+			} else {
+				if (defenseOn) {
+					_vm->writeVar(_vm->VAR_U32_USER_VAR_B, ITEM_CLUSTER);
+					int temp = _vm->_rnd.getRandomNumber(2);
+					int tempPower = 0;
+
+					switch (temp) {
+					case 0:
+						tempPower = getMinPower();
+						break;
+
+					case 1:
+						tempPower = getMaxPower();
+						break;
+
+					default:
+						tempPower = launchAction[LAUNCH_POWER];
+					}
+
+					_vm->writeVar(_vm->VAR_U32_USER_VAR_D, tempPower);
+				}
+			}
+		}
+
+		delete launchAction;
+		launchAction = NULL;
+
+		AIstate = STATE_CHOOSE_BEHAVIOR;
+
+		int rSh, rU, rP, rA = 0;
+		rSh = _vm->readVar(_vm->VAR_U32_USER_VAR_A);
+		rU = _vm->readVar(_vm->VAR_U32_USER_VAR_B);
+		rP = _vm->readVar(_vm->VAR_U32_USER_VAR_D);
+		rA = _vm->readVar(_vm->VAR_U32_USER_VAR_C);
+
+		warning("su: %d  unit: %d  power: %d  angle: %d", rSh, rU, rP, rA);
+
+		{
+			// Checking for patterns
+			if ((AItype[currentPlayer]->getID() != CRAWLER_CHUCKER) &&
+					(AItype[currentPlayer]->getID() != ENERGY_HOG) && (getBuildingStackPtr() > 5))
+				moveList[currentPlayer]->addPattern(rSh, rU, rP, rA);
+
+			int patternFound = moveList[currentPlayer]->evaluatePattern(rSh, rU, rP, rA);
+
+			if (!_vm->_rnd.getRandomNumber(9))
+				patternFound = 0;
+
+			if (patternFound) {
+				warning("------------------------------------------>Eliminating pattern");
+
+				if (_vm->_rnd.getRandomNumber(1)) {
+					behavior--;
+
+					if (behavior < ENERGY_MODE)
+						behavior = DEFENSE_MODE;
+				} else {
+					behavior++;
+
+					if (behavior > DEFENSE_MODE)
+						behavior = ENERGY_MODE;
+				}
+
+				if (behavior == ENERGY_MODE)
+					if (!getNumberOfPools())
+						behavior = OFFENSE_MODE;
+
+				_vm->writeVar(_vm->VAR_U32_USER_VAR_A, 0);
+				_vm->writeVar(_vm->VAR_U32_USER_VAR_B, 0);
+				_vm->writeVar(_vm->VAR_U32_USER_VAR_C, 0);
+				_vm->writeVar(_vm->VAR_U32_USER_VAR_D, 0);
+				AIstate = STATE_CHOOSE_TARGET;
+			}
+		}
+
+		if ((rSh > 0) && (rSh < 501)) {
+			if ((rU == ITEM_ANTIAIR) || (rU == ITEM_TOWER) || (rU == ITEM_ENERGY) || (rU == ITEM_SHIELD) || (rU == ITEM_OFFENSE) || (rU == ITEM_HUB)) {
+				int tryCount = 0;
+
+				while (checkForAngleOverlap(rSh, rA) && tryCount < 25) {
+					rA = _vm->_rnd.getRandomNumber(359);
+					tryCount++;
+				}
+
+				if (tryCount < 25) {
+					_vm->writeVar(_vm->VAR_U32_USER_VAR_C, rA);
+				} else {
+					_vm->writeVar(_vm->VAR_U32_USER_VAR_B, SKIP_TURN);
+				}
+			}
+		}
+	} else {
+		_vm->writeVar(_vm->VAR_U32_USER_VAR_A, 0);
+		_vm->writeVar(_vm->VAR_U32_USER_VAR_B, 0);
+		_vm->writeVar(_vm->VAR_U32_USER_VAR_C, 0);
+		_vm->writeVar(_vm->VAR_U32_USER_VAR_D, 0);
+	}
+
+	// Sending behavior to SCUMM side for profiling
+	int selectedUnit = _vm->readVar(_vm->VAR_U32_USER_VAR_B);
+
+	if (selectedUnit) {
+		if (selectedUnit > 0)
+			_vm->writeVar(_vm->VAR_U32_USER_VAR_E, behavior);
+		else
+			_vm->writeVar(_vm->VAR_U32_USER_VAR_E, -999);
+	}
+
+	return 1;
+}
+
+int chooseBehavior() {
+	static int dominantMode = 0;
+
+	int modeValue[3];
+
+	const int DEFAULT_SCALE = 5;
+
+	if (getBuildingStackPtr() < 5)
+		return OFFENSE_MODE;
+
+	int currentPlayer = getCurrentPlayer();
+
+	int AIpersonality = AItype[currentPlayer]->getID();
+
+	switch (AIpersonality) {
+	case BRUTAKAS:
+		modeValue[ENERGY_MODE] = DEFAULT_SCALE;
+		modeValue[OFFENSE_MODE] = 2 * DEFAULT_SCALE;
+		modeValue[DEFENSE_MODE] = 0;
+		dominantMode = OFFENSE_MODE;
+		break;
+
+	case AGI:
+		modeValue[ENERGY_MODE] = DEFAULT_SCALE;
+		modeValue[OFFENSE_MODE] = 0;
+		modeValue[DEFENSE_MODE] = 2 * DEFAULT_SCALE;
+		dominantMode = DEFENSE_MODE;
+		break;
+
+	case EL_GATO:
+		modeValue[ENERGY_MODE] = 2 * DEFAULT_SCALE;
+		modeValue[OFFENSE_MODE] = DEFAULT_SCALE;
+		modeValue[DEFENSE_MODE] = 0;
+		dominantMode = ENERGY_MODE;
+		break;
+
+	case PIXELAHT:
+		modeValue[ENERGY_MODE] = DEFAULT_SCALE;
+		modeValue[OFFENSE_MODE] = 0;
+		modeValue[DEFENSE_MODE] = DEFAULT_SCALE;
+		dominantMode = DEFENSE_MODE;
+		break;
+
+	case CYBALL:
+		modeValue[ENERGY_MODE] = 0;
+		modeValue[OFFENSE_MODE] = 0;
+		modeValue[DEFENSE_MODE] = 0;
+		dominantMode = ENERGY_MODE;
+		break;
+
+	case NEEP:
+		modeValue[ENERGY_MODE] = 0;
+		modeValue[OFFENSE_MODE] = DEFAULT_SCALE;
+		modeValue[DEFENSE_MODE] = DEFAULT_SCALE;
+		dominantMode = DEFENSE_MODE;
+		break;
+
+	case WARCUPINE:
+		modeValue[ENERGY_MODE] = 5 * DEFAULT_SCALE;
+		modeValue[OFFENSE_MODE] = DEFAULT_SCALE;
+		modeValue[DEFENSE_MODE] = 0;
+		dominantMode = ENERGY_MODE;
+		break;
+
+	case AONE:
+		modeValue[ENERGY_MODE] = 0;
+		modeValue[OFFENSE_MODE] = DEFAULT_SCALE;
+		modeValue[DEFENSE_MODE] = 2 * DEFAULT_SCALE;
+		dominantMode = DEFENSE_MODE;
+		break;
+
+	case SPANDO:
+		modeValue[ENERGY_MODE] = DEFAULT_SCALE;
+		modeValue[OFFENSE_MODE] = DEFAULT_SCALE;
+		modeValue[DEFENSE_MODE] = DEFAULT_SCALE;
+		dominantMode = ENERGY_MODE;
+		break;
+
+	case ORBNU_LUNATEK:
+		modeValue[ENERGY_MODE] = 0;
+		modeValue[OFFENSE_MODE] = 0;
+		modeValue[DEFENSE_MODE] = 0;
+		dominantMode = ENERGY_MODE;
+		break;
+
+	case CRAWLER_CHUCKER:
+		modeValue[ENERGY_MODE] = 0;
+		modeValue[OFFENSE_MODE] = 2 * DEFAULT_SCALE;
+		modeValue[DEFENSE_MODE] = 0;
+		dominantMode = OFFENSE_MODE;
+		break;
+
+	case ENERGY_HOG:
+		modeValue[ENERGY_MODE] = 2 * DEFAULT_SCALE;
+		modeValue[OFFENSE_MODE] = 0;
+		modeValue[DEFENSE_MODE] = 0;
+		dominantMode = ENERGY_MODE;
+		{
+			int breakFlag = 0;
+
+			for (int i = 500; i > 0; i--)
+				if ((getBuildingOwner(i) == currentPlayer) && (getBuildingType(i) == BUILDING_ENERGY_COLLECTOR))
+					breakFlag = 1;
+
+			if (!breakFlag)
+				return ENERGY_MODE;
+		}
+		break;
+
+	case RANGER:
+		modeValue[ENERGY_MODE] = 2 * DEFAULT_SCALE;
+		modeValue[OFFENSE_MODE] = 0;
+		modeValue[DEFENSE_MODE] = 0;
+		dominantMode = OFFENSE_MODE;
+
+		//random chance of defense if really early in game, otherwise offense
+		if (_vm->_rnd.getRandomNumber(1) || getTurnCounter() > 4)
+			return OFFENSE_MODE;
+
+		return DEFENSE_MODE;
+		break;
+
+	default:  //BRUTAKAS
+		modeValue[ENERGY_MODE] = DEFAULT_SCALE;
+		modeValue[OFFENSE_MODE] = 2 * DEFAULT_SCALE;
+		modeValue[DEFENSE_MODE] = 0;
+		dominantMode = OFFENSE_MODE;
+		break;
+	}
+
+	// get a list of all the visible enemy units
+	int eneCon = 0;
+	int offCon = 0;
+	int defCon = 0;
+
+	// energy mode
+	{
+		warning("Starting Energy Behavior Selection");
+		int minEnergy = 8;
+		int maxEnergy = 14;
+
+		if (dominantMode == ENERGY_MODE) {
+			eneCon = 3;
+			maxEnergy = 21;
+		} else {
+			eneCon = 5;
+		}
+
+
+		// loop through energy pool array
+		int energyPoolScummArray = getEnergyPoolsArray();
+		int numPools = getNumberOfPools();
+
+		// Prevent energy from being chosen if not enough energy to create
+		int energyAmount = getPlayerEnergy();
+
+		if ((energyAmount < 7))
+			numPools = 0;
+
+		for (int i = 1; i <= numPools; i++) {
+			int poolX = _vm->_moonbase->readFromArray(energyPoolScummArray, i, ENERGY_POOL_X);
+			int poolY = _vm->_moonbase->readFromArray(energyPoolScummArray, i, ENERGY_POOL_Y);
+
+			int radius = energyPoolSize(i) / 2;
+			int poolMaxCount = getMaxCollectors(i);
+
+			int energyCount = 0;
+			int energyUnits = getUnitsWithinRadius(poolX, poolY, radius + 30);
+			int energyCounter = 0;
+			int energyBuilding = _vm->_moonbase->readFromArray(energyUnits, 0, energyCounter);
+
+
+			while (energyBuilding) {
+				energyCounter++;
+
+				if ((getBuildingType(energyBuilding) == BUILDING_ENERGY_COLLECTOR) && (getBuildingOwner(energyBuilding) != currentPlayer))
+					energyCount = poolMaxCount;
+
+				if ((getBuildingType(energyBuilding) == BUILDING_ENERGY_COLLECTOR) && (getBuildingOwner(energyBuilding) == currentPlayer))
+					energyCount++;
+
+				energyBuilding = _vm->_moonbase->readFromArray(energyUnits, 0, energyCounter);
+			}
+
+			_vm->nukeArray(energyUnits);
+
+			if (energyCount < poolMaxCount) {
+				int closestHub = getClosestUnit(poolX, poolY, 300, currentPlayer, 1, BUILDING_MAIN_BASE, 1);
+
+				if (closestHub) {
+					eneCon = MIN(1, eneCon);
+				} else {
+					int secondClosestHub = getClosestUnit(poolX, poolY, 480, currentPlayer, 1, BUILDING_MAIN_BASE, 1);
+
+					if (secondClosestHub)
+						eneCon = MIN(2, eneCon);
+					else
+						eneCon = MIN(3, eneCon);
+				}
+			}
+		}
+
+		int totalEnergy = estimateNextRoundEnergy(currentPlayer);
+
+		if (totalEnergy < minEnergy)
+			eneCon--;
+
+		if (totalEnergy > maxEnergy)
+			eneCon += 2;
+
+		if ((totalEnergy > 34) || (!numPools))
+			eneCon = 10;
+
+		if (dominantMode == ENERGY_MODE)
+			eneCon--;
+	}
+
+
+	// offense mode
+	{
+		warning("Starting Offense Behavior Selection");
+
+		if (dominantMode == OFFENSE_MODE) offCon = 3;
+		else offCon = 5;
+
+		int enemyArray = getEnemyUnitsVisible(currentPlayer);
+		int enemyX = 0;
+		int enemyY = 0;
+		int hubX = 0;
+		int hubY = 0;
+
+		int nearEnemyHub = 0;
+
+		// cycle through the array of buildings
+		for (int i = 0; i < 500; i++) {
+			if (int thisBuilding = _vm->_moonbase->readFromArray(enemyArray, i, 0)) {
+				enemyX = getHubX(thisBuilding);
+				enemyY = getHubY(thisBuilding);
+				int closestHub = getClosestUnit(enemyX, enemyY, 970, currentPlayer, 1, BUILDING_MAIN_BASE, 1);
+				int closestOL = getClosestUnit(enemyX, enemyY, 970, currentPlayer, 1, BUILDING_MAIN_BASE, 1);
+				int dist = 0;
+
+				if (closestOL) {
+					hubX = getHubX(closestOL);
+					hubY = getHubY(closestOL);
+					nearEnemyHub = 1;
+				}
+
+				if (closestHub) {
+					hubX = getHubX(closestHub);
+					hubY = getHubY(closestHub);
+					dist = getDistance(hubX, hubY, enemyX, enemyY);
+
+					if (dist < 480)
+						nearEnemyHub = 1;
+				}
+
+
+				if (closestHub || closestOL) {
+					int numDefenders = 0;
+					int defArray = getUnitsWithinRadius(enemyX, enemyY, 170);
+					int defCounter = 0;
+					int defenseBuilding = _vm->_moonbase->readFromArray(defArray, 0, defCounter);
+
+					while (defenseBuilding) {
+						defCounter++;
+
+						if (((getBuildingType(defenseBuilding) == BUILDING_ANTI_AIR) ||
+								(getBuildingType(defenseBuilding) == BUILDING_SHIELD)) &&
+									(getBuildingOwner(defenseBuilding) != currentPlayer)) {
+							if (getBuildingState(defenseBuilding) == 0)
+								numDefenders++;
+						}
+
+						defenseBuilding = _vm->_moonbase->readFromArray(defArray, 0, defCounter);
+					}
+
+					_vm->nukeArray(defArray);
+
+					if (!numDefenders) {
+						int defArray2 = getUnitsWithinRadius(hubX, hubY, 170);
+						defCounter = 0;
+						int defenseBuilding2 = _vm->_moonbase->readFromArray(defArray2, 0, defCounter);
+
+						while (defenseBuilding2) {
+							defCounter++;
+
+							if (((getBuildingType(defenseBuilding2) == BUILDING_ANTI_AIR) ||
+									(getBuildingType(defenseBuilding2) == BUILDING_SHIELD)) &&
+										(getBuildingOwner(defenseBuilding2) != currentPlayer))
+								if (getBuildingState(defenseBuilding2) == 0)
+									numDefenders++;
+
+							defenseBuilding2 = _vm->_moonbase->readFromArray(defArray, 0, defCounter);
+						}
+
+						_vm->nukeArray(defArray2);
+
+					}
+
+					if ((!numDefenders) && (nearEnemyHub)) {
+						if (thisBuilding > 495)
+							offCon = 1 + _vm->_rnd.getRandomNumber(1);
+						else
+							offCon = MIN(offCon, 2);
+					} else {
+						if (thisBuilding > 495) {
+							if (nearEnemyHub) {
+								offCon = MIN(offCon, 2);
+								break;
+							} else {
+								offCon = MIN(offCon, 3);
+								break;
+							}
+						} else {
+							offCon = MIN(offCon, 4);
+						}
+					}
+				}
+
+				if (getBuildingType(thisBuilding) == BUILDING_CRAWLER) {
+					if (getClosestUnit(enemyX, enemyY, 350, currentPlayer, 1, 0, 0)) {
+						int closestHub1 = getClosestUnit(enemyX, enemyY, 460, currentPlayer, 1, BUILDING_MAIN_BASE, 1);
+						int closestMine = getClosestUnit(enemyX, enemyY, 80, 0, 0, BUILDING_EXPLOSIVE_MINE, 1);
+
+						if (closestHub1 && !closestMine)
+							offCon = -1;
+					}
+				}
+			} else {
+				break;
+			}
+		}
+
+		_vm->nukeArray(enemyArray);
+		offCon--;
+	}
+
+	// defense mode
+	{
+		warning("Starting Defense Behavior Selection");
+
+		if (dominantMode == DEFENSE_MODE)
+			defCon = 3;
+		else
+			defCon = 5;
+
+		int numDefenders = 0;
+		int openFlag = 0;
+
+		int mainHubX = getHubX(0);
+		int mainHubY = getHubY(0);
+		int mainHub = getClosestUnit(mainHubX + 10, mainHubY, 20, currentPlayer, 1, BUILDING_MAIN_BASE, 0);
+
+		int damageFlag = 0;
+
+		// cycle through the array of buildings
+		for (int i = 500; i >= 1; i--) {
+			if ((i < 497) && (defCon < 3))
+				break;
+
+			if (getBuildingOwner(i) == currentPlayer) {
+				int type = getBuildingType(i);
+				int hubX = getHubX(i);
+				int hubY = getHubY(i);
+
+				if (type == BUILDING_MAIN_BASE || type == BUILDING_ENERGY_COLLECTOR || type == BUILDING_OFFENSIVE_LAUNCHER) {
+					int nearEnemy = 0;
+					int closeBuildingsArray = getUnitsWithinRadius(hubX, hubY, 480);
+					int closeBuildingCounter = 0;
+					int closeBuilding = _vm->_moonbase->readFromArray(closeBuildingsArray, 0, closeBuildingCounter);
+
+					while (closeBuilding) {
+						closeBuildingCounter++;
+
+						if ((getBuildingOwner(closeBuilding) != currentPlayer) && (getBuildingType(closeBuilding) == BUILDING_MAIN_BASE)) {
+							nearEnemy = 1;
+							break;
+						}
+
+						closeBuilding = _vm->_moonbase->readFromArray(closeBuildingsArray, 0, closeBuildingCounter);
+					}
+
+					_vm->nukeArray(closeBuildingsArray);
+
+					int defCounter = 0;
+					int defArray = getUnitsWithinRadius(hubX, hubY, 170);
+					int defenseBuilding = _vm->_moonbase->readFromArray(defArray, 0, defCounter);
+					numDefenders = 0;
+
+					while (defenseBuilding) {
+						defCounter++;
+
+						if (((getBuildingType(defenseBuilding) == BUILDING_ANTI_AIR) || (getBuildingType(defenseBuilding) == BUILDING_SHIELD)) && (getBuildingOwner(defenseBuilding) == currentPlayer)) {
+							//main base has enemies near, but is defended
+							if (getBuildingState(defenseBuilding) == 0)
+								numDefenders++;
+						}
+
+						defenseBuilding = _vm->_moonbase->readFromArray(defArray, 0, defCounter);
+					}
+
+					_vm->nukeArray(defArray);
+
+					if (numDefenders > 2)
+						defCon++;
+
+					if (numDefenders < 2)
+						if (dominantMode == DEFENSE_MODE)
+							openFlag = 1;
+
+					if (!numDefenders) {
+						if (nearEnemy) {
+							if (i == mainHub) {
+								defCon = 1;
+								break;
+							} else {
+								defCon = MIN(defCon, 2);
+							}
+						} else {
+							if (i == mainHub)
+								defCon = MIN(defCon, 3);
+							else
+								defCon = MIN(defCon, 4);
+						}
+					}
+
+					if (getBuildingArmor(i) < getBuildingMaxArmor(i))
+						damageFlag = 1;
+				}
+			}
+		}
+
+		if (damageFlag && (defCon > 1))
+			defCon--;
+
+		if (!openFlag && defCon == 3)
+			defCon += 2;
+	}
+
+	warning("%s-------------------------------> Energy: %d     Offense: %d     Defense: %d", AItype[currentPlayer]->getNameString(), eneCon, offCon, defCon);
+
+	if (dominantMode == DEFENSE_MODE)
+		if ((defCon <= offCon) && (defCon <= eneCon))
+			return DEFENSE_MODE;
+
+	if (dominantMode == OFFENSE_MODE)
+		if ((offCon <= eneCon) && (offCon <= defCon))
+			return OFFENSE_MODE;
+
+	if (dominantMode == ENERGY_MODE)
+		if ((eneCon <= offCon) && (eneCon <= defCon))
+			return ENERGY_MODE;
+
+	if ((defCon <= offCon) && (defCon <= eneCon))
+		return DEFENSE_MODE;
+
+	if ((offCon <= eneCon) && (offCon <= defCon))
+		return OFFENSE_MODE;
+
+	if ((eneCon <= offCon) && (eneCon <= defCon))
+		return ENERGY_MODE;
+
+	return -1;
+}
+
+int chooseTarget(int behavior1) {
+	int numPools = getNumberOfPools();
+	int currentPlayer = getCurrentPlayer();
+
+	int selection = 0;
+	int selectionValues[50] = {0};
+	int selectionDist = 10000000;
+
+	if (behavior1 == ENERGY_MODE) {
+		// loop through energy pool array
+		int energyPoolScummArray = getEnergyPoolsArray();
+
+		for (int i = 1; i <= numPools; i++) {
+			// check # units on pool
+			int numPoolSpots = _vm->_moonbase->readFromArray(energyPoolScummArray, i, ENERGY_POOL_UNITS_ON);
+
+			if (numPoolSpots == 0) {
+				// put this one in the middle
+				warning("Empty pool #%d", i);
+				selectionValues[i] = 2;
+			} else {
+				// get units w/in radius of pool
+				int poolUnitsArray = getUnitsWithinRadius(_vm->_moonbase->readFromArray(energyPoolScummArray, i, ENERGY_POOL_X), _vm->_moonbase->readFromArray(energyPoolScummArray, i, ENERGY_POOL_Y), 50);
+				int enemyPool = 0;
+				int j = 1;
+				int thisPoolUnit = _vm->_moonbase->readFromArray(poolUnitsArray, 0, j);
+
+				while (thisPoolUnit) {
+					if (getBuildingOwner(thisPoolUnit) != currentPlayer)
+						enemyPool = 1;
+
+					j++;
+					thisPoolUnit = _vm->_moonbase->readFromArray(poolUnitsArray, 0, j);
+				}
+
+				_vm->nukeArray(poolUnitsArray);
+
+				// if enemy collector, put at bottom
+				if (enemyPool) {
+					selectionValues[i] = 1;
+				} else if (numPoolSpots < getMaxCollectors(i)) {
+					selectionValues[i] = 3;
+				} else {
+					// this pool is filled
+					selectionValues[i] = 0;
+				}
+			}
+
+			if (selectionValues[i] > selectionValues[selection]) {
+				selection = i;
+			} else if (selectionValues[i] == selectionValues[selection]) {
+				int poolX = _vm->_moonbase->readFromArray(energyPoolScummArray, i, ENERGY_POOL_X);
+				int poolY = _vm->_moonbase->readFromArray(energyPoolScummArray, i, ENERGY_POOL_Y);
+
+				int closestHub = getClosestUnit(poolX, poolY, getMaxX(), currentPlayer, 1, BUILDING_MAIN_BASE, 1, 100);
+				int thisDist = getDistance(poolX, poolY, getHubX(closestHub), getHubY(closestHub));
+
+				if (thisDist < selectionDist) {
+					selection = i;
+					selectionDist = thisDist;
+				}
+			}
+
+		}
+
+		warning("Pool selected: %d   dist: %d", selection, selectionDist);
+		return selection;
+	}
+
+	if (behavior1 == OFFENSE_MODE) {
+		int returnBuilding = 0;
+		int attackableArray[500];
+		int nearAttackableArray[500];
+		int attackableIndex = 0;
+		int nearAttackableIndex = 0;
+
+		int enemyArray = getEnemyUnitsVisible(currentPlayer);
+
+		for (int i = 500; i >= 1; i--) {
+			int thisBuilding = _vm->_moonbase->readFromArray(enemyArray, i - 1, 0);
+
+			if (thisBuilding) {
+				if (getBuildingType(thisBuilding) == BUILDING_CRAWLER) {
+					if ((getTerrain(getHubX(thisBuilding), getHubY(thisBuilding)) != TERRAIN_TYPE_WATER) || (getPlayerEnergy() > 6)) {
+						if (getClosestUnit(getHubX(thisBuilding), getHubY(thisBuilding), 380, currentPlayer, 1, BUILDING_MAIN_BASE, 1)) {
+							returnBuilding = thisBuilding;
+							_vm->nukeArray(enemyArray);
+							return returnBuilding;
+						}
+					} else {
+						continue;
+					}
+				}
+
+				int enemyX = getHubX(thisBuilding);
+				int enemyY = getHubY(thisBuilding);
+				int closestHub = getClosestUnit(enemyX, enemyY, 930, currentPlayer, 1, BUILDING_MAIN_BASE, 1);
+
+				int dist = getDistance(enemyX, enemyY, getHubX(closestHub), getHubY(closestHub));
+
+				if (getBuildingType(thisBuilding) != BUILDING_BALLOON) {
+					if (dist < 470) {
+						attackableArray[attackableIndex] = thisBuilding;
+						attackableIndex++;
+					} else {
+						nearAttackableArray[nearAttackableIndex] = thisBuilding;
+						nearAttackableIndex++;
+					}
+				}
+			}
+		}
+
+		_vm->nukeArray(enemyArray);
+
+		if (attackableIndex) {
+			int thisWorth = 0;
+			int savedWorth = 1;
+			int closestSavedShield = 0;
+			int closestSavedAntiAir = 0;
+
+			for (int i = 0; i < attackableIndex; i++) {
+				thisWorth = getBuildingWorth(attackableArray[i]);
+
+				if (thisWorth == savedWorth) {
+					int closestShield = getClosestUnit(getHubX(attackableArray[i]), getHubY(attackableArray[i]), 180, currentPlayer, 0, BUILDING_SHIELD, 1);
+					int closestAntiAir = getClosestUnit(getHubX(attackableArray[i]), getHubY(attackableArray[i]), 180, currentPlayer, 0, BUILDING_ANTI_AIR, 1);
+
+					if (closestSavedShield > closestShield) {
+						savedWorth = thisWorth;
+						closestSavedShield = closestShield;
+						closestSavedAntiAir = closestAntiAir;
+						returnBuilding = attackableArray[i];
+					} else {
+						if (closestSavedAntiAir > closestAntiAir) {
+							savedWorth = thisWorth;
+							closestSavedShield = closestShield;
+							closestSavedAntiAir = closestAntiAir;
+							returnBuilding = attackableArray[i];
+						}
+					}
+				}
+
+				if (thisWorth > savedWorth) {
+					savedWorth = thisWorth;
+					returnBuilding = attackableArray[i];
+				}
+			}
+		} else {
+			if (nearAttackableIndex) {
+				int thisWorth = 0;
+				int savedWorth = 1;
+				int closestSavedShield = 0;
+				int closestSavedAntiAir = 0;
+
+				for (int i = 0; i < nearAttackableIndex; i++) {
+					thisWorth = getBuildingWorth(nearAttackableArray[i]);
+
+					if (thisWorth == savedWorth) {
+						int closestShield = getClosestUnit(getHubX(nearAttackableArray[i]), getHubY(nearAttackableArray[i]), 180, currentPlayer, 0, BUILDING_SHIELD, 1);
+						int closestAntiAir = getClosestUnit(getHubX(nearAttackableArray[i]), getHubY(nearAttackableArray[i]), 180, currentPlayer, 0, BUILDING_ANTI_AIR, 1);
+
+						if (closestSavedShield > closestShield) {
+							savedWorth = thisWorth;
+							closestSavedShield = closestShield;
+							closestSavedAntiAir = closestAntiAir;
+							returnBuilding = nearAttackableArray[i];
+						} else {
+							if (closestSavedAntiAir > closestAntiAir) {
+								savedWorth = thisWorth;
+								closestSavedShield = closestShield;
+								closestSavedAntiAir = closestAntiAir;
+								returnBuilding = nearAttackableArray[i];
+							}
+						}
+					}
+
+					if (thisWorth > savedWorth)  {
+						savedWorth = thisWorth;
+						returnBuilding = nearAttackableArray[i];
+					}
+				}
+			}
+		}
+
+		if (!returnBuilding) {
+			for (int i = 500; i > 496; i--) {
+				if (getBuildingOwner(i)) {
+					if (getBuildingTeam(i) != getPlayerTeam(currentPlayer)) {
+						returnBuilding = i;
+						i = 0;
+					}
+				}
+			}
+		}
+
+		warning("Attack target: %d", returnBuilding);
+
+		assert(returnBuilding);
+		return returnBuilding;
+	}
+
+	if (behavior1 == DEFENSE_MODE) {
+		int returnBuilding = 0;
+
+		int savedTally = 0;
+		int savedDamage;
+		float savedNumDefenses = 0;
+		int savedWorth = 0;
+
+		float numDefenses = 0;
+		int tally = 0;
+		int attackable = 0;
+		int attacked = 0;
+		int damage = 0;
+
+		int type = 0;
+		int worth = 0;
+
+
+		int attackedX = 0;
+		int attackedY = 0;
+		int attackedUnit = 0;
+
+		if (getLastAttacked(attackedX, attackedY)) {
+			(void)getClosestUnit(attackedX + 10, attackedY, 50, currentPlayer, 1, 0, 0); // Unused?
+		}
+
+		// loop through own units
+		for (int i = 1; i <= 500; i++) {
+			numDefenses = 0;
+			attackable = 0;
+			attacked = 0;
+			damage = 0;
+			type = 0;
+			worth = 0;
+
+			int owner = getBuildingOwner(i);
+
+			if (owner == currentPlayer) {
+				type = getBuildingType(i);
+
+				// if current unit in [hub, offense, energy, tower]
+				if ((type == BUILDING_MAIN_BASE) || (type == BUILDING_ENERGY_COLLECTOR) || (type == BUILDING_OFFENSIVE_LAUNCHER) || (type == BUILDING_TOWER)) {
+					worth = getBuildingWorth(i);
+
+					// Calculate current defenses
+					int x = getHubX(i);
+					int y = getHubY(i);
+					assert(x >= 0);
+					assert(y >= 0);
+
+					int defenseArray = getUnitsWithinRadius(x, y, 180);
+					int j = 0;
+					// cycle through the defense units close to the target building
+					int defenseBuilding = _vm->_moonbase->readFromArray(defenseArray, 0, j);
+
+					// loop on all defenses w/in 180
+					while (defenseBuilding != 0) {
+						int defenseType = getBuildingType(defenseBuilding);
+
+						// sub for each
+						if ((defenseType == BUILDING_ANTI_AIR) || (defenseType == BUILDING_SHIELD)) {
+							if (getBuildingState(defenseBuilding) == 0)
+								numDefenses += 1;
+							else
+								numDefenses += .5;
+						}
+
+						j++;
+						defenseBuilding = _vm->_moonbase->readFromArray(defenseArray, 0, j);
+					}
+
+					_vm->nukeArray(defenseArray);
+
+					// Calculate if this unit is attackable
+					// get dist to nearest enemy hub, offense
+					int closestHub = getClosestUnit(x, y, getMaxX(), getCurrentPlayer(), 0, BUILDING_MAIN_BASE, 0);
+					int numStridesToHub = getDistance(getHubX(closestHub), getHubY(closestHub), x, y) / 480;
+					closestHub = getClosestUnit(x, y, getMaxX(), getCurrentPlayer(), 0, BUILDING_OFFENSIVE_LAUNCHER, 0);
+					int numStridesToOL = getDistance(getHubX(closestHub), getHubY(closestHub), x, y) / 800;
+
+					// sub for each stride away
+					if (!numStridesToOL || !numStridesToHub)
+						attackable = 1;
+
+					// Check if this unit was just attacked
+					if (attackedUnit == i)
+						attacked = 1;
+
+					if (!numDefenses) {
+						tally = 1;
+
+						if (attackable) {
+							tally = 4;
+
+							if (attacked) {
+								tally = 5;
+							}
+						}
+					} else {
+						if (attackable) {
+							tally = 2;
+
+							if (attacked) {
+								tally = 3;
+							}
+						}
+					}
+
+					// Check if this unit is damaged
+					int saveFlag = 0;
+
+					if (tally > savedTally) {
+						saveFlag = 1;
+					} else {
+						if (tally == savedTally) {
+							if (worth > savedWorth) {
+								saveFlag = 1;
+
+								if (numDefenses > savedNumDefenses) {
+									saveFlag = 0;
+								}
+							}
+
+							if (damage > savedDamage) {
+								saveFlag = 1;
+
+								if (numDefenses > savedNumDefenses) {
+									saveFlag = 0;
+								}
+							}
+
+							if (numDefenses < savedNumDefenses) {
+								saveFlag = 1;
+							}
+
+							if (numDefenses >= 3) {
+								saveFlag = 0;
+							}
+						}
+					}
+
+					if (saveFlag) {
+						savedTally = tally;
+						savedWorth = worth;
+						savedDamage = damage;
+						savedNumDefenses = numDefenses;
+						returnBuilding = i;
+					}
+				}
+			}
+		}
+
+		return returnBuilding;
+	}
+
+	return 0;
+}
+
+Tree *initApproachTarget(int targetX, int targetY, Node **retNode) {
+	int sourceHub = 0;
+
+	if (behavior == 2)
+		sourceHub = getClosestUnit(targetX + 10, targetY, getMaxX(), getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1);
+	else
+		sourceHub = getClosestUnit(targetX + 10, targetY, getMaxX(), getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, MIN_DIST);
+
+	Traveller *myTraveller = new Traveller(getHubX(sourceHub), getHubY(sourceHub));
+	myTraveller->setSourceHub(sourceHub);
+
+	//target adjustment so that room is allowed for the appropriate shot
+	int tempAngle = calcAngle(getHubX(sourceHub), getHubY(sourceHub), targetX, targetY);
+	int adjX = -120 * cos(degToRad(tempAngle));
+	int adjY = -120 * sin(degToRad(tempAngle));
+
+	Traveller::setTargetPosX(targetX + adjX);
+	Traveller::setTargetPosY(targetY + adjY);
+	Traveller::setMaxDist(340);
+
+	Tree *myTree = new Tree(myTraveller, TREE_DEPTH);
+	*retNode = myTree->aStarSearch_singlePassInit();
+
+	return myTree;
+}
+
+int *approachTarget(Tree *myTree, int &xTarget, int &yTarget, Node **currentNode) {
+	int *retVal = NULL;
+
+	*currentNode = NULL;
+	Node *retNode = myTree->aStarSearch_singlePass(currentNode);
+
+	if (*currentNode != NULL)
+		warning("########################################### Got a possible solution");
+
+	if (myTree->IsBaseNode(retNode)) {
+		warning("########################################### Returning Base Node");
+		retVal = new int[4];
+		retVal[0] = -1;
+		return retVal;
+	}
+
+	if (retNode == NULL) {
+		return retVal;
+	} else {
+		retVal = new int[4];
+
+		Traveller *retTraveller = reinterpret_cast<Traveller *>(retNode->getFirstStep()->getContainedObject());
+
+		// set launching hub, item to launch, angle of launch, power of launch
+		// if water flag is set, launch bridge instead of hub
+		retVal[0] = static_cast<Traveller *>(myTree->getBaseNode()->getContainedObject())->getSourceHub();
+
+		if (retTraveller->getWaterFlag()) {
+			int powAngle = getPowerAngleFromPoint(retTraveller->getWaterSourceX(),
+												retTraveller->getWaterSourceY(),
+												retTraveller->getWaterDestX(),
+												retTraveller->getWaterDestY(),
+												15);
+
+			powAngle = abs(powAngle);
+			int power = powAngle / 360;
+			int angle = powAngle - (power * 360);
+
+			retVal[0] = getClosestUnit(retTraveller->getWaterSourceX() + 10, retTraveller->getWaterSourceY(), getMaxX(), getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, 0);
+
+			retVal[1] = ITEM_BRIDGE;
+			retVal[2] = angle;
+			retVal[3] = power;
+
+			warning("Target Bridge Coords: <%d, %d> ", retTraveller->getWaterDestX(), retTraveller->getWaterDestY());
+		} else {
+			retVal[1] = ITEM_HUB;
+			retVal[2] = retTraveller->getAngleTo();
+			retVal[3] = retTraveller->getPowerTo();
+		}
+
+
+		int whoseTurn = getCurrentPlayer();
+
+		if ((lastXCoord[whoseTurn]).size() >= MAX_MEMORY) {
+			(lastXCoord[whoseTurn]).erase((lastXCoord[whoseTurn]).begin());
+			(lastYCoord[whoseTurn]).erase((lastYCoord[whoseTurn]).begin());
+		}
+
+		(lastXCoord[whoseTurn]).push_back(retTraveller->getPosX());
+		(lastYCoord[whoseTurn]).push_back(retTraveller->getPosY());
+
+		int temp = static_cast<int>(retTraveller->calcT());
+		int temp2 = static_cast<int>(retTraveller->getValueG());
+		int x = static_cast<int>(retTraveller->getPosX());
+		int y = static_cast<int>(retTraveller->getPosY());
+		warning("Target Coords: <%d, %d>  G-value: %d    T-value: %d", x, y, temp2, temp);
+		xTarget = x;
+		yTarget = y;
+	}
+
+	return retVal;
+}
+
+Tree *initAcquireTarget(int targetX, int targetY, Node **retNode) {
+	int sourceHub = getClosestUnit(targetX, targetY, getMaxX(), getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, MIN_DIST);
+	warning("My coords (%d): %d %d", sourceHub, getHubX(sourceHub), getHubY(sourceHub));
+
+	Sortie::setSourcePos(getHubX(sourceHub), getHubY(sourceHub));
+	Sortie::setTargetPos(targetX, targetY);
+	Sortie *myBaseTarget = new Sortie();
+	myBaseTarget->setValueG(0);
+
+	myBaseTarget->setUnitType(ITEM_BOMB);
+	myBaseTarget->setShotPos(-1, -1);
+
+	int unitsArray = getUnitsWithinRadius(targetX + 7, targetY, 211);
+
+	warning("Target Coords: <%d, %d>    Source Coords: <%d, %d>", targetX, targetY, getHubX(sourceHub) , getHubY(sourceHub));
+
+	myBaseTarget->setEnemyDefenses(unitsArray, targetX, targetY);
+
+	int thisElement = _vm->_moonbase->readFromArray(unitsArray, 0, 0);
+
+	_vm->nukeArray(unitsArray);
+
+	if (!thisElement) {
+		delete myBaseTarget;
+		return NULL;
+	}
+
+	Tree *myTree = new Tree(myBaseTarget, 4);
+	*retNode = myTree->aStarSearch_singlePassInit();
+
+	return myTree;
+}
+
+
+int *acquireTarget(int targetX, int targetY, Tree *myTree, int &errorCode) {
+	int currentPlayer = getCurrentPlayer();
+	int *retVal = NULL;
+
+	Node *currentNode = NULL;
+	Node *retNode = myTree->aStarSearch_singlePass(&currentNode);
+
+	if (myTree->IsBaseNode(retNode))
+		return acquireTarget(targetX, targetY);
+
+	if (retNode == NULL) {
+		errorCode = 0;
+		return retVal;
+	}
+
+	Sortie *thisSortie = static_cast<Sortie *>(retNode->getFirstStep()->getContainedObject());
+	int unitToShoot = thisSortie->getUnitType();
+
+	if (unitToShoot < 0) {
+		errorCode = 1;
+		return retVal;
+	}
+
+	if (unitToShoot == ITEM_CRAWLER) {
+		warning("target acquisition is launching a crawler");
+	}
+
+	int shotTargetX = thisSortie->getShotPosX();
+	int shotTargetY = thisSortie->getShotPosY();
+	int theTarget = getClosestUnit(shotTargetX + 5, shotTargetY, getMaxX(), 0, 0, 0, 0, 0);
+
+
+	int sourceOL = 0;
+	int sourceX = thisSortie->getSourcePosX();
+	int sourceY = thisSortie->getSourcePosY();
+
+	int sourceHub = getClosestUnit(sourceX + 5, sourceY, getMaxX(), currentPlayer, 1, BUILDING_MAIN_BASE, 1, 0);
+
+	sourceOL = getClosestUnit(sourceX, sourceY, 900, currentPlayer, 1, BUILDING_OFFENSIVE_LAUNCHER, 1, 110);
+
+	if (sourceOL) {
+		sourceHub = sourceOL;
+		sourceX = getHubX(sourceOL);
+		sourceY = getHubY(sourceOL);
+	}
+
+	if (!sourceHub) sourceHub = getClosestUnit(sourceX + 5, sourceY, getMaxX(), currentPlayer, 1, BUILDING_MAIN_BASE, 1, 0);
+
+	int powAngle = getPowerAngleFromPoint(sourceX, sourceY, shotTargetX, shotTargetY, 15, sourceOL);
+	warning("The source (%d: <%d, %d>)    The target (%d: <%d, %d>)", sourceHub, sourceX, sourceY, theTarget, shotTargetX, shotTargetY);
+
+	powAngle = abs(powAngle);
+	int power = powAngle / 360;
+	int angle = powAngle - (power * 360);
+
+	retVal = new int[4];
+
+	retVal[0] = sourceHub;
+	retVal[1] = unitToShoot;
+	retVal[2] = angle;
+	retVal[3] = power;
+
+	warning("Unit to shoot: %d", unitToShoot);
+
+	return retVal;
+}
+
+int *acquireTarget(int targetX, int targetY) {
+	int *retVal = new int[4];
+	int sourceHub = getClosestUnit(targetX, targetY, getMaxX(), getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, 110);
+
+	if (!sourceHub)
+		sourceHub = getClosestUnit(targetX, targetY, getMaxX(), getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, 0);
+
+	int directAngle = calcAngle(getHubX(sourceHub), getHubY(sourceHub), targetX, targetY);
+	int directDistance = getDistance(getHubX(sourceHub), getHubY(sourceHub), targetX, targetY);
+
+	retVal[0] = sourceHub;
+	retVal[1] = ITEM_OFFENSE;
+	retVal[2] = directAngle;
+	retVal[3] = MAX(MIN(getMaxPower() * directDistance / 500, getMaxPower()), getMinPower());
+
+	return retVal;
+}
+
+int *energizeTarget(int &targetX, int &targetY, int index) {
+	int n = 10;
+	static int currentPlayer = 0;
+	static int pool = 0;
+	static int radius = 0;
+	static int poolUnitsArray = 0;
+	static int j = 0;
+	static int k = 0;
+	static int sameUnit = 0;
+	static int nextUnit = 0;
+	static int attempt = 0;
+
+	if (!index) {
+		warning("index is 0!");
+		currentPlayer = getCurrentPlayer();
+		pool = 0;
+
+		// get the pool that's closest to the target coords
+		for (int i = 1; i <= getNumberOfPools(); i++) {
+			int poolX = _vm->_moonbase->readFromArray(getEnergyPoolsArray(), i, ENERGY_POOL_X);
+			int poolY = _vm->_moonbase->readFromArray(getEnergyPoolsArray(), i, ENERGY_POOL_Y);
+
+			if ((poolX == targetX) && (poolY == targetY)) {
+				pool = i;
+			}
+		}
+
+		// calculate the appropriate radius
+		radius = energyPoolSize(pool) / 2;
+
+		// create test points
+		k = 0;
+		j = 0;
+		nextUnit = 0;
+		sameUnit = 0;
+		attempt = 0;
+	}
+
+	if (poolUnitsArray)
+		_vm->nukeArray(poolUnitsArray);
+
+	poolUnitsArray = getUnitsWithinRadius(targetX, targetY, 450);
+	assert(poolUnitsArray);
+
+	// 0 is for energy collectors, 1 is for circumnavigating hubs
+	if (k < 2) {
+		if (!sameUnit) {
+			sameUnit = 1;
+			attempt = 0;
+			nextUnit = _vm->_moonbase->readFromArray(poolUnitsArray, 0, j);
+			j++;
+		}
+
+		if (nextUnit) {
+			if ((getBuildingType(nextUnit) == BUILDING_MAIN_BASE) && (getBuildingOwner(nextUnit) == currentPlayer)) {
+				int minAngle = 0;
+				int hubToPoolAngle = 0;
+				int testAngle = 0;
+				int testDist = 0;
+				static int xPos = 0;
+				static int yPos = 0;
+				static int newAttempt = 1;
+
+				if (sameUnit) {
+					if (k == 0) {
+						int poolToHubAngle = calcAngle(targetX, targetY, getHubX(nextUnit), getHubY(nextUnit));
+						minAngle = poolToHubAngle - 45;
+					} else {
+						hubToPoolAngle = calcAngle(getHubX(nextUnit), getHubY(nextUnit), targetX, targetY);
+					}
+				}
+
+				if (attempt < n) {
+					static int power = 0;
+					static int angle = 0;
+
+					if (newAttempt) {
+						newAttempt = 0;
+
+						if (k == 0) {
+							testAngle = (_vm->_rnd.getRandomNumber(89) + minAngle) % 360;
+							testDist = radius;
+
+							xPos = targetX + testDist * cos(degToRad(testAngle));
+							yPos = targetY + testDist * sin(degToRad(testAngle));
+						} else {
+							switch (_vm->_rnd.getRandomNumber(1)) {
+							case 0:
+								testAngle = (hubToPoolAngle + (45 + _vm->_rnd.getRandomNumber(19))) % 360;
+								break;
+
+							default:
+								testAngle = (hubToPoolAngle + (315 - _vm->_rnd.getRandomNumber(19))) % 360;
+								break;
+							}
+
+							testDist = ((((n - attempt) / n) * .5) + .5) * (getDistance(getHubX(nextUnit), getHubY(nextUnit), targetX, targetY) / .8);
+							xPos = getHubX(nextUnit) + testDist * cos(degToRad(testAngle));
+							yPos = getHubY(nextUnit) + testDist * sin(degToRad(testAngle));
+						}
+
+						// check if points are good
+						int powAngle = getPowerAngleFromPoint(getHubX(nextUnit), getHubY(nextUnit), xPos, yPos, 15);
+						powAngle = abs(powAngle);
+
+						power = powAngle / 360;
+						angle = powAngle - (power * 360);
+					}
+
+					int result = 0;
+					result = simulateBuildingLaunch(getHubX(nextUnit), getHubY(nextUnit), power, angle, 10, 1);
+
+					if (result) {
+						newAttempt = 1;
+
+						if (result > 0) {
+							xPos = (xPos + getMaxX()) % getMaxX();
+							yPos = (yPos + getMaxY()) % getMaxY();
+
+							result = 1;
+						} else {
+							// Drop a bridge for the cord
+							int yCoord  = -result / getMaxX();
+							int xCoord = -result - (yCoord * getMaxX());
+
+							if (checkIfWaterState(xCoord, yCoord)) {
+								int terrainSquareSize = getTerrainSquareSize();
+								xCoord = ((xCoord / terrainSquareSize * terrainSquareSize) + (terrainSquareSize / 2));
+								yCoord = ((yCoord / terrainSquareSize * terrainSquareSize) + (terrainSquareSize / 2));
+
+								int xDist = xCoord - xPos;
+								int yDist = yCoord - yPos;
+								xPos = xCoord + (terrainSquareSize * 1.414 * (xDist / (abs(xDist) + 1)));
+								yPos = yCoord + (terrainSquareSize * 1.414 * (yDist / (abs(yDist) + 1)));
+
+								nextUnit = getClosestUnit(xPos, yPos, 480, getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, 120);
+								int powAngle = getPowerAngleFromPoint(getHubX(nextUnit), getHubY(nextUnit), xPos, yPos, 15);
+
+								powAngle = abs(powAngle);
+								power = powAngle / 360;
+								angle = powAngle - (power * 360);
+
+								int *retVal = new int[4];
+
+								retVal[0] = nextUnit;
+								retVal[1] = ITEM_BRIDGE;
+								retVal[2] = angle;
+								retVal[3] = power;
+
+								if (nextUnit <= 0)
+									retVal[0] = 0;
+
+								_vm->nukeArray(poolUnitsArray);
+								poolUnitsArray = 0;
+								return retVal;
+							}
+						}
+
+						if (result > 0) {
+							_vm->nukeArray(poolUnitsArray);
+							poolUnitsArray = 0;
+
+							targetX = xPos;
+							targetY = yPos;
+
+							int *retVal = new int[4];
+
+							retVal[0] = nextUnit;
+
+							if (k == 0) {
+								retVal[1] = ITEM_ENERGY;
+							} else {
+								retVal[1] = ITEM_HUB;
+							}
+
+							retVal[2] = angle;
+							retVal[3] = power;
+							return retVal;
+						}
+					} else {
+						int *retVal = new int[4];
+						retVal[0] = 0;
+						_vm->nukeArray(poolUnitsArray);
+						poolUnitsArray = 0;
+
+						return retVal;
+					}
+
+					attempt++;
+				} else {
+					sameUnit = 0;
+				}
+			} else {
+				sameUnit = 0;
+			}
+		} else {
+			sameUnit = 0;
+			k++;
+			j = 0;
+		}
+	} else {
+		_vm->nukeArray(poolUnitsArray);
+		poolUnitsArray = 0;
+		return NULL;
+	}
+
+	_vm->nukeArray(poolUnitsArray);
+	poolUnitsArray = 0;
+	int *retVal = new int[4];
+	retVal[0] = 0;
+
+	return retVal;
+}
+
+int *offendTarget(int &targetX, int &targetY, int index) {
+	int *retVal = NULL;
+
+	int target = getClosestUnit(targetX + 10, targetY, 20, 0, 0, 0, 0);
+
+	if (!target)
+		target = getClosestUnit(targetX + 10, targetY, 0, 0, 0, 0, 0);
+
+	warning("The target inside the offendTarget routine is: %d", target);
+	int type = getBuildingType(target);
+	int unit = 0;
+
+	DefenseUnit *thisUnit;
+
+	switch (type) {
+	case BUILDING_OFFENSIVE_LAUNCHER:
+		thisUnit = new OffenseUnit();
+		break;
+
+	case BUILDING_TOWER:
+		thisUnit = new TowerUnit();
+		break;
+
+	case BUILDING_MAIN_BASE:
+		thisUnit = new HubUnit();
+		break;
+
+	case BUILDING_ENERGY_COLLECTOR:
+		thisUnit = new EnergyUnit();
+		break;
+
+	case BUILDING_CRAWLER:
+		thisUnit = new CrawlerUnit();
+		break;
+
+	case BUILDING_BRIDGE:
+		thisUnit = new BridgeUnit();
+		break;
+
+	case BUILDING_SHIELD:
+		thisUnit = new ShieldUnit();
+		break;
+
+	default:
+		thisUnit = new HubUnit();
+		break;
+	}
+
+	thisUnit->setPos(targetX, targetY);
+	thisUnit->setID(target);
+
+	int sourceHub = getClosestUnit(targetX, targetY, getMaxX(), getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, 110);
+	int sourceOL = 0;
+	sourceOL = getClosestUnit(targetX, targetY, 900, getCurrentPlayer(), 1, BUILDING_OFFENSIVE_LAUNCHER, 1, 110);
+
+	unit = thisUnit->selectWeapon(_vm->_rnd.getRandomNumber(4));
+
+	if (sourceOL) {
+		if ((unit == ITEM_BOMB) || (unit == ITEM_CLUSTER) || (unit == ITEM_GUIDED) || (unit == ITEM_EMP) || (unit == ITEM_SPIKE) || (unit == ITEM_CRAWLER) || (unit == ITEM_VIRUS)) {
+			sourceHub = sourceOL;
+		}
+	}
+
+	if (!sourceHub) {
+		retVal = new int[4];
+
+		retVal[1] = SKIP_TURN;
+		return retVal;
+	}
+
+
+	if ((thisUnit->getType() == BUILDING_CRAWLER) && (unit == SKIP_TURN)) {
+		retVal = new int[4];
+		retVal[1] = unit;
+		delete thisUnit;
+		return retVal;
+	}
+
+	if (unit == ITEM_CRAWLER) {
+		warning("******** offense is launching a crawler ********");
+		warning("The defensive unit is: %d", unit);
+	}
+
+	Common::Point *targetCoords;
+	int dist = getDistance(getHubX(sourceHub), getHubY(sourceHub), targetX, targetY);
+	targetCoords = thisUnit->createTargetPos(0, dist, unit, getHubX(sourceHub), getHubY(sourceHub));
+
+	int powAngle = getPowerAngleFromPoint(getHubX(sourceHub), getHubY(sourceHub), targetCoords->x, targetCoords->y, 15, sourceOL);
+	powAngle = abs(powAngle);
+	int power = powAngle / 360;
+	int angle = powAngle % 360;
+
+	if (unit == ITEM_MINE)
+		power -= 30;
+
+	targetX = targetCoords->x;
+	targetY = targetCoords->y;
+
+	if (targetX < 0)
+		targetX = (targetX + getMaxX()) % getMaxX();
+
+	if (targetY < 0)
+		targetY = (targetY + getMaxY()) % getMaxY();
+
+	assert(targetX >= 0 && targetY >= 0);
+	delete targetCoords;
+	delete thisUnit;
+
+	retVal = new int[4];
+
+	retVal[0] = sourceHub;
+	retVal[1] = unit;
+	retVal[2] = angle;
+	retVal[3] = power;
+
+	return retVal;
+}
+
+int *defendTarget(int &targetX, int &targetY, int index) {
+	int *retVal = NULL;
+	Defender *thisDefender = new Defender;
+	int defStatus = thisDefender->calculateDefenseUnitPosition(targetX, targetY, index);
+
+	if (defStatus > 0) {
+		targetX = thisDefender->getTargetX();
+		targetY = thisDefender->getTargetY();
+		retVal = new int[4];
+
+		retVal[0] = thisDefender->getSourceUnit();
+		retVal[1] = thisDefender->getUnit();
+		retVal[2] = thisDefender->getAngle();
+		retVal[3] = thisDefender->getPower();
+	}
+
+	if (defStatus == 0) {
+		retVal = new int[4];
+		retVal[0] = 0;
+	}
+
+	if (defStatus == -1) {
+		if (thisDefender->getTargetX() || thisDefender->getTargetY()) {
+			targetX = thisDefender->getTargetX();
+			targetY = thisDefender->getTargetY();
+		}
+
+		retVal = new int[4];
+		retVal[0] = thisDefender->getSourceUnit();
+		retVal[1] = thisDefender->getUnit();
+		retVal[2] = thisDefender->getAngle();
+		retVal[3] = thisDefender->getPower();
+	}
+
+	if (defStatus == -3) {
+		retVal = new int[4];
+		retVal[0] = 0;
+		retVal[1] = SKIP_TURN;
+		retVal[2] = 0;
+		retVal[3] = 0;
+	}
+
+	assert(targetX >= 0 && targetY >= 0);
+
+	if (retVal[1] == ITEM_CRAWLER) {
+		warning("defend target is launching a crawler");
+	}
+
+	delete thisDefender;
+	return retVal;
+}
+
+int getClosestUnit(int x, int y, int radius, int player, int alignment, int unitType, int checkUnitEnabled) {
+	assert((unitType >= 0) && (unitType <= 12));
+
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_CLOSEST_UNIT], 7, x, y, radius, player, alignment, unitType, checkUnitEnabled);
+	return retVal;
+}
+
+int getClosestUnit(int x, int y, int radius, int player, int alignment, int unitType, int checkUnitEnabled, int minDist) {
+	assert((unitType >= 0) && (unitType <= 12));
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_CLOSEST_UNIT], 8, x, y, radius, player, alignment, unitType, checkUnitEnabled, minDist);
+	return retVal;
+}
+
+int getDistance(int originX, int originY, int endX, int endY) {
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_WORLD_DIST], 4, originX, originY, endX, endY);
+	return retVal;
+}
+
+int calcAngle(int originX, int originY, int endX, int endY) {
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_WORLD_ANGLE], 5, originX, originY, endX, endY, 0);
+	return retVal;
+}
+
+int calcAngle(int originX, int originY, int endX, int endY, int noWrapFlag) {
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_WORLD_ANGLE], 5, originX, originY, endX, endY, noWrapFlag);
+	return retVal;
+}
+
+int getTerrain(int x, int y) {
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_TERRAIN_TYPE], 2, x, y);
+	return retVal;
+}
+
+int estimateNextRoundEnergy(int player) {
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_ESTIMATE_NEXT_ROUND_ENERGY], 1, player);
+	return retVal / 10;
+}
+
+int getHubX(int hub) {
+	assert(hub >= 0 && hub <= 500);
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 2, D_GET_HUB_X, hub);
+	return retVal;
+}
+
+int getHubY(int hub) {
+	assert(hub >= 0 && hub <= 500);
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 2, D_GET_HUB_Y, hub);
+	return retVal;
+}
+
+int getMaxX() {
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 1, D_GET_WORLD_X_SIZE);
+	return retVal;
+}
+
+int getMaxY() {
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 1, D_GET_WORLD_Y_SIZE);
+	return retVal;
+}
+
+int getCurrentPlayer() {
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 1, D_GET_CURRENT_PLAYER);
+	assert(retVal != 0);
+	return retVal;
+}
+
+int getMaxPower() {
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 1, D_GET_MAX_POWER);
+	return retVal;
+}
+
+int getMinPower() {
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 1, D_GET_MIN_POWER);
+	return retVal;
+}
+
+int getTerrainSquareSize() {
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 1, D_GET_TERRAIN_SQUARE_SIZE);
+	return retVal;
+}
+
+int getBuildingOwner(int building) {
+	assert((building > 0) && (building < 501));
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 2, D_GET_BUILDING_OWNER, building);
+	return retVal;
+}
+
+int getBuildingState(int building) {
+	assert((building > 0) && (building < 501));
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 2, D_GET_BUILDING_STATE, building);
+	return retVal;
+}
+
+int getBuildingType(int building) {
+	assert((building > 0) && (building < 501));
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 2, D_GET_BUILDING_TYPE, building);
+	return retVal;
+}
+
+int getBuildingArmor(int building) {
+	assert((building > 0) && (building < 501));
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 2, D_GET_BUILDING_ARMOR, building);
+	return retVal;
+}
+
+int getBuildingWorth(int building) {
+	assert((building > 0) && (building < 501));
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 2, D_GET_BUILDING_WORTH, building);
+	return retVal;
+}
+
+int getEnergyPoolsArray() {
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 1, D_GET_ENERGY_POOLS_ARRAY);
+	return retVal;
+}
+
+int getCoordinateVisibility(int x, int y, int playerNum) {
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 4, D_GET_COORDINATE_VISIBILITY, x, y, playerNum);
+	return retVal;
+}
+
+int getUnitVisibility(int unit, int playerNum) {
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 3, D_GET_UNIT_VISIBILITY, unit, playerNum);
+	return retVal;
+}
+
+int getEnergyPoolVisibility(int pool, int playerNum) {
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 3, D_GET_ENERGY_POOL_VISIBILITY, pool, playerNum);
+	return retVal;
+}
+
+int getNumberOfPools() {
+	int retVal = 0;
+
+	if (AItype[getCurrentPlayer()]->getID() == ENERGY_HOG) {
+		retVal = 1;
+	} else {
+		retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 1, D_GET_NUMBER_OF_POOLS);
+	}
+
+	return retVal;
+}
+
+int getNumberOfPlayers() {
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 1, D_GET_NUMBER_OF_PLAYERS);
+	return retVal;
+}
+
+int getPlayerEnergy() {
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 1, D_GET_PLAYER_ENERGY);
+	return static_cast<int>(static_cast<float>(retVal) / 10.0);
+}
+
+int getPlayerMaxTime() {
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 1, D_GET_PLAYER_MAX_TIME);
+	return retVal;
+}
+
+int getWindXSpeed() {
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 1, D_GET_WIND_X_SPEED);
+	return retVal;
+}
+
+int getWindYSpeed() {
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 1, D_GET_WIND_Y_SPEED);
+	return retVal;
+}
+
+int getTotalWindSpeed() {
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 1, D_GET_TOTAL_WIND_SPEED);
+	return retVal;
+}
+
+int getWindXSpeedMax() {
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 1, D_GET_WIND_X_SPEED_MAX);
+	return retVal;
+}
+
+int getWindYSpeedMax() {
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 1, D_GET_WIND_Y_SPEED_MAX);
+	return retVal;
+}
+
+int getBigXSize() {
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 1, D_GET_BIG_X_SIZE);
+	return retVal;
+}
+
+int getBigYSize() {
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 1, D_GET_BIG_Y_SIZE);
+	return retVal;
+}
+
+int getEnergyPoolWidth(int pool) {
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 2, D_GET_ENERGY_POOL_WIDTH, pool);
+	return retVal;
+}
+
+int getBuildingMaxArmor(int building) {
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 2, D_GET_BUILDING_MAX_ARMOR, building);
+	return retVal;
+}
+
+int getTimerValue(int timerNum) {
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 2, D_GET_TIMER_VALUE, timerNum);
+	return retVal;
+}
+
+int getLastAttacked(int &x, int &y) {
+	int currentPlayer = getCurrentPlayer();
+	x = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 2, D_GET_LAST_ATTACKED_X, currentPlayer);
+	y = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 2, D_GET_LAST_ATTACKED_Y, currentPlayer);
+
+	if (x || y) return 1;
+
+	return 0;
+}
+
+int getPlayerTeam(int player) {
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 2, D_GET_PLAYER_TEAM, player);
+	return retVal;
+}
+
+int getBuildingTeam(int building) {
+	assert((building >= 1) && (building <= 500));
+
+	if (getBuildingOwner(building) == 0) return 0;
+
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 2, D_GET_BUILDING_TEAM, building);
+	return retVal;
+}
+
+int getFOW() {
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 1, D_GET_FOW);
+	return retVal;
+}
+
+int getAnimSpeed() {
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 1, D_GET_ANIM_SPEED);
+	return retVal;
+}
+
+int getBuildingStackPtr() {
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 1, D_GET_BUILDING_STACK_PTR);
+	return retVal;
+}
+
+int getTurnCounter() {
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_SCUMM_DATA], 1, D_GET_TURN_COUNTER);
+	return retVal;
+}
+
+int getGroundAltitude(int x, int y) {
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_GROUND_ALTITUDE], 2, x, y);
+	return retVal;
+}
+
+int checkForCordOverlap(int xStart, int yStart, int affectRadius, int simulateFlag) {
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_CHECK_FOR_CORD_OVERLAP], 4, xStart, yStart, affectRadius, simulateFlag);
+	return retVal;
+}
+
+int checkForAngleOverlap(int unit, int angle) {
+	assert(angle > -721);
+	assert(angle < 721);
+
+	if (!unit) return 0;
+
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_CHECK_FOR_ANGLE_OVERLAP], 2, unit, angle);
+	return retVal;
+}
+
+int checkForUnitOverlap(int x, int y, int radius, int ignoredUnit) {
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_CHECK_FOR_UNIT_OVERLAP], 4, x, y, radius, ignoredUnit);
+	return retVal;
+}
+
+int checkForEnergySquare(int x, int y) {
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_CHECK_FOR_ENERGY_SQUARE], 2, x, y);
+	return retVal;
+}
+
+int aiChat() {
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_AI_CHAT], 0);
+	return retVal;
+}
+
+int getPowerAngleFromPoint(int originX, int originY, int endX, int endY, int threshold, int olFlag) {
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_POWER_ANGLE_FROM_POINT], 6, originX, originY, endX, endY, threshold, olFlag);
+	return retVal;
+}
+
+int getPowerAngleFromPoint(int originX, int originY, int endX, int endY, int threshold) {
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_POWER_ANGLE_FROM_POINT], 5, originX, originY, endX, endY, threshold);
+	return retVal;
+}
+
+int checkIfWaterState(int x, int y) {
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_CHECK_IF_WATER_STATE], 2, x, y);
+	return retVal;
+}
+
+int checkIfWaterSquare(int x, int y) {
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_CHECK_IF_WATER_SQUARE], 2, x, y);
+	return retVal;
+}
+
+int getUnitsWithinRadius(int x, int y, int radius) {
+	assert(x >= 0);
+	assert(y >= 0);
+	assert(radius >= 0);
+
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_UNITS_WITHIN_RADIUS], 3, x, y, radius);
+	return retVal;
+}
+
+int getLandingPoint(int x, int y, int power, int angle) {
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_LANDING_POINT], 4, x, y, power, angle);
+	return retVal;
+}
+
+int getEnemyUnitsVisible(int playerNum) {
+	int retVal = _vm->_moonbase->callScummFunction(MCP_params[F_GET_ENEMY_UNITS_VISIBLE], 1, playerNum);
+	return retVal;
+}
+
+float degToRad(float degrees) {
+	return degrees * M_PI / 180.;
+}
+
+void limitLocation(int &a, int &b, int c, int d) {
+	if (a >= 0) {
+		a = (a % c);
+	} else {
+		a = (c - (abs(a) % c));
+	}
+
+	if (b >= 0) {
+		b = (b % d);
+	} else {
+		b = (d - (abs(b) % d));
+	}
+}
+
+int energyPoolSize(int pool) {
+	int width = getEnergyPoolWidth(pool);
+
+	switch (width) {
+	case 126:
+		return 115;
+
+	case 116:
+		return 100;
+
+	case 63:
+		return 60;
+	}
+
+	return 0;
+}
+
+int getMaxCollectors(int pool) {
+	int width = getEnergyPoolWidth(pool);
+
+	switch (width) {
+	case 126:
+		return 4;
+
+	case 116:
+		return 3;
+
+	case 63:
+		return 2;
+	}
+
+	return 0;
+}
+
+int simulateBuildingLaunch(int x, int y, int power, int angle, int numSteps, int isEnergy) {
+	static int sXSpeed = 0;
+	static int sYSpeed = 0;
+	static int sZSpeed = 0;
+	static int sXLoc = 0;
+	static int sYLoc = 0;
+	static int sZLoc = 0;
+	static int sFrictionCount = 0;
+	static int sWhichRadius = 0;
+	static int sWhichUnit = 0;
+
+	int gWindXSpeed = getWindXSpeed();
+	int gWindYSpeed = getWindYSpeed();
+	int gTotalWindSpeed = getTotalWindSpeed();
+	int gWindXSpeedMax = getWindXSpeedMax();
+	int gWindYSpeedMax = getWindYSpeedMax();
+	int bigXSize = getBigXSize();
+	int bigYSize = getBigYSize();
+
+	int groundAltitude = 0;
+	int totalSpeed = 0;
+	int resultingPoint = 0;
+	int unscaledXLoc = 0;
+	int unscaledYLoc = 0;
+	int terrainType = 0;
+	int passedBeyondUnit = 0;
+	int currentDist = 0;
+
+
+	if (!numSteps)
+		numSteps = 1;
+
+	if (!sXSpeed && !sYSpeed) {
+		sZSpeed = (static_cast<int>(.70711 * power)) ;
+		sXSpeed = (static_cast<int>(cos(degToRad(angle)) * sZSpeed)) ;
+		sYSpeed = (static_cast<int>(sin(degToRad(angle)) * sZSpeed)) ;
+
+		sZSpeed *= SCALE_Z;
+
+		sZLoc = (getGroundAltitude(x, y) + HEIGHT_LOW + 10) * SCALE_Z;
+
+		sXLoc = x * SCALE_X;
+		sYLoc = y * SCALE_Y;
+
+		sFrictionCount = 0;
+		sWhichRadius = NODE_DETECT_RADIUS + 1;
+
+		sWhichUnit = getClosestUnit(x + 10, y, 30, getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 0, 0);
+	}
+
+	int savedUnscaledXLoc = 0;
+	int savedUnscaledYLoc = 0;
+
+	for (int i = 1; i <= numSteps; i++) {
+		unscaledXLoc = sXLoc / SCALE_X;
+		unscaledYLoc = sYLoc / SCALE_Y;
+
+		groundAltitude = getGroundAltitude(unscaledXLoc, unscaledYLoc);
+		groundAltitude *= SCALE_Z;
+
+		sZLoc += sZSpeed / SCALE_Z;
+
+		resultingPoint = MAX(1, unscaledXLoc + unscaledYLoc * getMaxX());
+
+		if (sZLoc <= groundAltitude) {
+			terrainType = getTerrain(unscaledXLoc, unscaledYLoc);
+
+			sXSpeed = 0;
+			sYSpeed = 0;
+			sFrictionCount = 0;
+
+			if (terrainType == TERRAIN_TYPE_GOOD)
+				return resultingPoint;
+			else
+				return 0 - resultingPoint;
+		} else {
+			if (checkIfWaterState(unscaledXLoc, unscaledYLoc)) {
+				sXSpeed = 0;
+				sYSpeed = 0;
+				sFrictionCount = 0;
+
+				return 0 - resultingPoint;
+			} else {
+				int cfco = 0;
+				int cfuo = 0;
+				int cfes = 0;
+				int cfao = 0;
+				cfao = checkForAngleOverlap(sWhichUnit, angle);
+
+				cfco = checkForCordOverlap(unscaledXLoc, unscaledYLoc, sWhichRadius, 1);
+				cfuo = checkForUnitOverlap(unscaledXLoc, unscaledYLoc, sWhichRadius, sWhichUnit);
+
+				if (!isEnergy)
+					cfes = checkForEnergySquare(unscaledXLoc, unscaledYLoc);
+
+				savedUnscaledXLoc = unscaledXLoc;
+				savedUnscaledYLoc = unscaledYLoc;
+
+				if (cfco || cfuo || cfes || cfao) {
+					sXSpeed = 0;
+					sYSpeed = 0;
+					sFrictionCount = 0;
+
+					return 0 - resultingPoint;
+				} else {
+					sFrictionCount++;
+
+					if (sFrictionCount == 10) {
+						sFrictionCount = 0;
+
+						if (!gWindXSpeed)
+							sXSpeed = sXSpeed * .95;
+
+						if (!gWindYSpeed)
+							sYSpeed = sYSpeed * .95;
+					}
+
+					if (passedBeyondUnit) {
+						totalSpeed = getDistance(0, 0, sXSpeed, sYSpeed);
+
+						if (totalSpeed > gTotalWindSpeed) {
+							if (gWindXSpeed > 0) {
+								if (sXSpeed < gWindXSpeedMax)
+									sXSpeed += gWindXSpeed;
+							} else {
+								if (sXSpeed > gWindXSpeedMax)
+									sXSpeed += gWindXSpeed;
+							}
+
+							if (gWindYSpeed > 0) {
+								if (sYSpeed < gWindYSpeedMax)
+									sYSpeed += gWindYSpeed;
+							} else {
+								if (sYSpeed > gWindYSpeedMax)
+									sYSpeed += gWindYSpeed;
+							}
+						}
+					} else {
+						currentDist = getDistance(unscaledXLoc, unscaledYLoc, x, y);
+
+						if (currentDist > BUILDING_HUB_RADIUS + NODE_DIAMETER)
+							passedBeyondUnit = 1;
+					}
+
+					sXLoc += sXSpeed;
+					sYLoc += sYSpeed;
+
+					limitLocation(sXLoc, sYLoc, bigXSize, bigYSize);
+
+					sZSpeed -= GRAVITY_CONSTANT;
+				}
+			}
+		}
+	}
+
+	return 0;
+}
+
+int simulateWeaponLaunch(int x, int y, int power, int angle, int numSteps) {
+	static int sXSpeed = 0;
+	static int sYSpeed = 0;
+	static int sZSpeed = 0;
+	static int sXLoc = 0;
+	static int sYLoc = 0;
+	static int sZLoc = 0;
+	static int sFrictionCount = 0;
+
+	int gWindXSpeed = getWindXSpeed();
+	int gWindYSpeed = getWindYSpeed();
+	int gTotalWindSpeed = getTotalWindSpeed();
+	int gWindXSpeedMax = getWindXSpeedMax();
+	int gWindYSpeedMax = getWindYSpeedMax();
+	int bigXSize = getBigXSize();
+	int bigYSize = getBigYSize();
+
+	int groundAltitude = 0;
+	int totalSpeed = 0;
+	int resultingPoint = 0;
+	int unscaledXLoc = 0;
+	int unscaledYLoc = 0;
+	int terrainType = 0;
+	int passedBeyondUnit = 0;
+	int currentDist = 0;
+
+	if (!numSteps) numSteps = 1;
+
+	if (!sXSpeed && !sYSpeed) {
+		sZSpeed = (static_cast<int>(.70711 * power)) ;
+		sXSpeed = (static_cast<int>(cos(degToRad(angle)) * sZSpeed)) ;
+		sYSpeed = (static_cast<int>(sin(degToRad(angle)) * sZSpeed)) ;
+
+		sZSpeed *= SCALE_Z;
+
+		sZLoc = (getGroundAltitude(x, y) + HEIGHT_LOW + 10) * SCALE_Z;
+
+		sXLoc = x * SCALE_X;
+		sYLoc = y * SCALE_Y;
+
+		sFrictionCount = 0;
+	}
+
+	for (int i = 1; i <= numSteps; i++) {
+		unscaledXLoc = sXLoc / SCALE_X;
+		unscaledYLoc = sYLoc / SCALE_Y;
+
+		groundAltitude = getGroundAltitude(unscaledXLoc, unscaledYLoc);
+		groundAltitude *= SCALE_Z;
+		sZLoc += sZSpeed / SCALE_Z;
+		resultingPoint = MAX(1, unscaledXLoc + unscaledYLoc * getMaxX());
+
+		if (sZLoc <= groundAltitude) {
+			terrainType = getTerrain(unscaledXLoc, unscaledYLoc);
+
+			sXSpeed = 0;
+			sYSpeed = 0;
+			sFrictionCount = 0;
+
+			if (terrainType == TERRAIN_TYPE_GOOD)
+				return resultingPoint;
+			else
+				return 0 - resultingPoint;
+		} else {
+			sFrictionCount++;
+
+			if (sFrictionCount == 10) {
+				sFrictionCount = 0;
+
+				if (!gWindXSpeed)
+					sXSpeed = sXSpeed * .95;
+
+				if (!gWindYSpeed)
+					sYSpeed = sYSpeed * .95;
+			}
+
+			if (passedBeyondUnit) {
+				totalSpeed = getDistance(0, 0, sXSpeed, sYSpeed);
+
+				if (totalSpeed > gTotalWindSpeed) {
+					if (gWindXSpeed > 0) {
+						if (sXSpeed < gWindXSpeedMax)
+							sXSpeed += gWindXSpeed;
+					} else {
+						if (sXSpeed > gWindXSpeedMax)
+							sXSpeed += gWindXSpeed;
+					}
+
+					if (gWindYSpeed > 0) {
+						if (sYSpeed < gWindYSpeedMax)
+							sYSpeed += gWindYSpeed;
+					} else {
+						if (sYSpeed > gWindYSpeedMax)
+							sYSpeed += gWindYSpeed;
+					}
+				}
+			} else {
+				currentDist = getDistance(unscaledXLoc, unscaledYLoc, x, y);
+
+				if (currentDist > BUILDING_HUB_RADIUS + NODE_DIAMETER)
+					passedBeyondUnit = 1;
+			}
+
+			sXLoc += sXSpeed;
+			sYLoc += sYSpeed;
+
+			limitLocation(sXLoc, sYLoc, bigXSize, bigYSize);
+
+			sZSpeed -= GRAVITY_CONSTANT;
+		}
+	}
+
+	return 0;
+}
+
+int fakeSimulateWeaponLaunch(int x, int y, int power, int angle) {
+	int distance = power * 480 / getMaxPower();
+	float radAngle = degToRad(angle);
+	int maxX = getMaxX();
+	int maxY = getMaxY();
+
+	x += distance * cos(radAngle);
+	y += distance * sin(radAngle);
+
+	x = (x + maxX) % maxX;
+	y = (y + maxY) % maxY;
+
+	return MAX(1, x + y * maxX);
+}
+
+int getEnergyHogType() {
+	return energyHogType;
+}
+
+} // End of namespace Scumm
diff --git a/engines/scumm/he/moonbase/ai_main.h b/engines/scumm/he/moonbase/ai_main.h
index 1317f62..4937ece 100644
--- a/engines/scumm/he/moonbase/ai_main.h
+++ b/engines/scumm/he/moonbase/ai_main.h
@@ -86,101 +86,95 @@ enum {
 
 static int energyHogType = 0;
 
-void ResetAI();
-void CleanUpAI();
-void SetAIType(const int paramCount, const int *params);
-int MasterControlProgram(const int paramCount, const int *params);
-
-int ChooseBehavior();
-int ChooseTarget(int behavior);
-
-Tree *InitApproachTarget(int targetX, int targetY, Node **retNode);
-int *ApproachTarget(Tree *myTree, int &x, int &y, Node **currentNode);
-Tree *InitAcquireTarget(int targetX, int targetY, Node **retNode);
-int *AcquireTarget(int targetX, int targetY);
-int *AcquireTarget(int targetX, int targetY, Tree *myTree, int &errorCode);
-int *OffendTarget(int &targetX, int &targetY, int index);
-int *DefendTarget(int &targetX, int &targetY, int index);
-int *EnergizeTarget(int &targetX, int &targetY, int index);
-
-int GetClosestUnit(int x, int y, int radius, int player, int alignment, int unitType, int checkUnitEnabled);
-int GetClosestUnit(int x, int y, int radius, int player, int alignment, int unitType, int checkUnitEnabled, int minDist);
-
-int GetDistance(int originX, int originY, int endX, int endY);
-int GetAngle(int originX, int originY, int endX, int endY);
-int GetAngle(int originX, int originY, int endX, int endY, int noWrapFlag);
-int GetTerrain(int x, int y);
-int GetHubX(int hub);
-int GetHubY(int hub);
-int GetMaxX();
-int GetMaxY();
-int GetCurrentPlayer();
-int GetMaxPower();
-int GetMinPower();
-int GetTerrainSquareSize();
-int GetBuildingOwner(int building);
-int GetBuildingState(int building);
-int GetBuildingType(int building);
-int GetBuildingArmor(int building);
-int GetBuildingWorth(int building);
-void DebugBreak();
-int GetEnergyPoolsArray();
-int GetCoordinateVisibility(int x, int y, int playerNum);
-int GetUnitVisibility(int unit, int playerNum);
-int GetEnergyPoolVisibility(int pool, int playerNum);
-int GetNumberOfPools();
-int GetNumberOfPlayers();
-int GetPlayerEnergy();
-int GetPlayerMaxTime();
-int GetWindXSpeed();
-int GetWindYSpeed();
-int GetTotalWindSpeed();
-int GetWindXSpeedMax();
-int GetWindYSpeedMax();
-int GetBigXSize();
-int GetBigYSize();
-int GetEnergyPoolWidth(int pool);
-int GetBuildingMaxArmor(int building);
-int GetTimerValue(int timerNum);
-int GetLastAttacked(int &x, int &y);
-int PrintDebugTimer(int max, int timerVal);
-int GetPlayerTeam(int player);
-int GetBuildingTeam(int building);
-int GetFOW();
-int GetAnimSpeed();
-int GetBuildingStackPtr();
-int GetTurnCounter();
-
-int GetGroundAltitude(int x, int y);
-int CheckForCordOverlap(int xStart, int yStart, int affectRadius, int simulateFlag);
-int CheckForAngleOverlap(int unit, int angle);
-int EstimateNextRoundEnergy(int player);
-int CheckForUnitOverlap(int x, int y, int radius, int ignoredUnit);
-int CheckForEnergySquare(int x, int y);
-int AIChat();
-
-
-int SimulateBuildingLaunch(int x, int y, int power, int angle, int numSteps, int isEnergy);
-int SimulateWeaponLaunch(int x, int y, int power, int angle, int numSteps);
-int FakeSimulateWeaponLaunch(int x, int y, int power, int angle);
-
-int GetPowerAngleFromPoint(int originX, int originY, int endX, int endY, int threshold, int olFlag);
-int GetPowerAngleFromPoint(int originX, int originY, int endX, int endY, int threshold);
-int CheckIfWaterState(int x, int y);
-int CheckIfWaterSquare(int x, int y);
-int GetUnitsWithinRadius(int x, int y, int radius);
-int GetLandingPoint(int x, int y, int power, int angle);
-int GetEnemyUnitsVisible(int playerNum);
+void resetAI();
+void cleanUpAI();
+void setAIType(const int paramCount, const int *params);
+int masterControlProgram(const int paramCount, const int *params);
+
+int chooseBehavior();
+int chooseTarget(int behavior);
+
+Tree *initApproachTarget(int targetX, int targetY, Node **retNode);
+int *approachTarget(Tree *myTree, int &x, int &y, Node **currentNode);
+Tree *initAcquireTarget(int targetX, int targetY, Node **retNode);
+int *acquireTarget(int targetX, int targetY);
+int *acquireTarget(int targetX, int targetY, Tree *myTree, int &errorCode);
+int *offendTarget(int &targetX, int &targetY, int index);
+int *defendTarget(int &targetX, int &targetY, int index);
+int *energizeTarget(int &targetX, int &targetY, int index);
+
+int getClosestUnit(int x, int y, int radius, int player, int alignment, int unitType, int checkUnitEnabled);
+int getClosestUnit(int x, int y, int radius, int player, int alignment, int unitType, int checkUnitEnabled, int minDist);
+
+int getDistance(int originX, int originY, int endX, int endY);
+int calcAngle(int originX, int originY, int endX, int endY);
+int calcAngle(int originX, int originY, int endX, int endY, int noWrapFlag);
+int getTerrain(int x, int y);
+int getHubX(int hub);
+int getHubY(int hub);
+int getMaxX();
+int getMaxY();
+int getCurrentPlayer();
+int getMaxPower();
+int getMinPower();
+int getTerrainSquareSize();
+int getBuildingOwner(int building);
+int getBuildingState(int building);
+int getBuildingType(int building);
+int getBuildingArmor(int building);
+int getBuildingWorth(int building);
+int getEnergyPoolsArray();
+int getCoordinateVisibility(int x, int y, int playerNum);
+int getUnitVisibility(int unit, int playerNum);
+int getEnergyPoolVisibility(int pool, int playerNum);
+int getNumberOfPools();
+int getNumberOfPlayers();
+int getPlayerEnergy();
+int getPlayerMaxTime();
+int getWindXSpeed();
+int getWindYSpeed();
+int getTotalWindSpeed();
+int getWindXSpeedMax();
+int getWindYSpeedMax();
+int getBigXSize();
+int getBigYSize();
+int getEnergyPoolWidth(int pool);
+int getBuildingMaxArmor(int building);
+int getTimerValue(int timerNum);
+int getLastAttacked(int &x, int &y);
+int getPlayerTeam(int player);
+int getBuildingTeam(int building);
+int getFOW();
+int getAnimSpeed();
+int getBuildingStackPtr();
+int getTurnCounter();
+
+int getGroundAltitude(int x, int y);
+int checkForCordOverlap(int xStart, int yStart, int affectRadius, int simulateFlag);
+int checkForAngleOverlap(int unit, int angle);
+int estimateNextRoundEnergy(int player);
+int checkForUnitOverlap(int x, int y, int radius, int ignoredUnit);
+int checkForEnergySquare(int x, int y);
+int aiChat();
+
+int simulateBuildingLaunch(int x, int y, int power, int angle, int numSteps, int isEnergy);
+int simulateWeaponLaunch(int x, int y, int power, int angle, int numSteps);
+int fakeSimulateWeaponLaunch(int x, int y, int power, int angle);
+
+int getPowerAngleFromPoint(int originX, int originY, int endX, int endY, int threshold, int olFlag);
+int getPowerAngleFromPoint(int originX, int originY, int endX, int endY, int threshold);
+int checkIfWaterState(int x, int y);
+int checkIfWaterSquare(int x, int y);
+int getUnitsWithinRadius(int x, int y, int radius);
+int getLandingPoint(int x, int y, int power, int angle);
+int getEnemyUnitsVisible(int playerNum);
 
 float degToRad(float degrees);
-void MACRO_LimitLocation(int &a, int &b, int c, int d);
+void limitLocation(int &a, int &b, int c, int d);
 int energyPoolSize(int pool);
-int GetMaxCollectors(int pool);
+int getMaxCollectors(int pool);
 
-int TempChooseBehavior();
-int TempChooseTarget(int behavior);
-
-int GetEnergyHogType();
+int getEnergyHogType();
 
 extern Common::Array<int> lastXCoord[];
 extern Common::Array<int> lastYCoord[];
diff --git a/engines/scumm/he/moonbase/ai_pattern.h b/engines/scumm/he/moonbase/ai_pattern.h
new file mode 100644
index 0000000..ae1fa6b
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_pattern.h
@@ -0,0 +1,162 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef SCUMM_HE_MOONBASE_AI_PATTERN_H
+#define SCUMM_HE_MOONBASE_AI_PATTERN_H
+
+namespace Scumm {
+
+const int NO_PATTERN = 0;
+const int PATTERN_FOUND = 1;
+
+class patternInstance {
+private:
+	int _sourceHub;
+	int _unit;
+	int _power;
+	int _angle;
+
+public:
+	patternInstance() {
+		_sourceHub = 0;
+		_unit = 0;
+		_power = 0;
+		_angle = 0;
+	}
+
+	patternInstance(int sh, int unit, int power, int angle) {
+		setSourceHub(sh);
+		setUnit(unit);
+		setPower(power);
+		setAngle(angle);
+	}
+
+	void setSourceHub(int sh) { _sourceHub = sh; }
+	void setUnit(int unit) { _unit = unit; }
+
+	void setPower(int power) {
+		if (power < 300)
+			_power = 1;
+		else if (power < 480)
+			_power = 2;
+		else
+			_power = 3;
+	}
+
+	void setAngle(int angle) {
+		int tempAngle = angle % 360;
+
+		if ((tempAngle >= 0) && (tempAngle < 90))
+			_angle = 1;
+
+		if ((tempAngle >= 90) && (tempAngle < 180))
+			_angle = 2;
+
+		if ((tempAngle >= 180) && (tempAngle < 270))
+			_angle = 3;
+
+		if ((tempAngle >= 270))
+			_angle = 4;
+	}
+
+	int getSourceHub() const { return _sourceHub; }
+	int getUnit() const { return _unit; }
+	int getPowerIndex() const { return _power; }
+	int getAngleIndex() const { return _angle; }
+
+	static int comparePatterns(patternInstance *p1, patternInstance *p2) {
+		if (p1->getSourceHub() != p2->getSourceHub())
+			return 0;
+
+		if (p1->getUnit() != p2->getUnit())
+			return 0;
+
+		if (p1->getUnit() == -999)
+			return 0;
+
+		int temp = abs(p1->getPowerIndex() - p2->getPowerIndex());
+
+		if (temp > 1)
+			return 0;
+
+		temp = abs(p1->getAngleIndex() - p2->getAngleIndex());
+
+		if (temp > 1 && temp < 3)
+			return 0;
+
+		return 1;
+	}
+};
+
+class patternList {
+private:
+	patternInstance *theList[10];
+	int listIndex;
+
+public:
+	patternList() {
+		for (int i = 0; i < 10; i++) {
+			theList[i] = new patternInstance();
+		}
+
+		listIndex = 0;
+	}
+	~patternList() {
+		for (int i = 0; i < 10; i++) {
+			delete theList[i];
+		}
+	}
+
+	void addPattern(int sh, int unit, int power, int angle) {
+		theList[listIndex]->setSourceHub(sh);
+		theList[listIndex]->setUnit(unit);
+		theList[listIndex]->setPower(power);
+		theList[listIndex]->setAngle(angle);
+
+		listIndex++;
+
+		if (listIndex > 9)
+			listIndex = 0;
+	}
+
+	int evaluatePattern(int sh, int unit, int power, int angle) {
+		patternInstance *patternToMatch = new patternInstance(sh, unit, power, angle);
+		int matchCount = 0;
+
+		for (int i = 0; i < 9; i++) {
+			if (patternInstance::comparePatterns(theList[i], patternToMatch)) {
+				matchCount++;
+			}
+		}
+
+		delete patternToMatch;
+
+		if (matchCount > 2)
+			return PATTERN_FOUND;
+
+		return NO_PATTERN;
+	}
+};
+
+} // End of namespace Scumm
+
+#endif
diff --git a/engines/scumm/he/moonbase/ai_targetacquisition.cpp b/engines/scumm/he/moonbase/ai_targetacquisition.cpp
index 0eebaef..6fbd983 100644
--- a/engines/scumm/he/moonbase/ai_targetacquisition.cpp
+++ b/engines/scumm/he/moonbase/ai_targetacquisition.cpp
@@ -36,22 +36,22 @@ int Sortie::_sTargetX = 0;
 int Sortie::_sTargetY = 0;
 
 Sortie::~Sortie() {
-	for (Common::Array<DefenseUnit *>::iterator k = _enemyDefenses.begin(); k != _enemyDefenses.end(); ++k) {
+	for (Common::Array<DefenseUnit *>::iterator k = _enemyDefenses.begin(); k != _enemyDefenses.end(); k++) {
 		delete *k;
 	}
 }
 
 void Sortie::setEnemyDefenses(int enemyDefensesScummArray, int defendX, int defendY) {
 	DefenseUnit *thisUnit;
-	int currentPlayer = GetCurrentPlayer();
+	int currentPlayer = getCurrentPlayer();
 
-	for (int i = 0; i < 200; ++i) {
+	for (int i = 0; i < 200; i++) {
 		int thisElement = _vm->_moonbase->readFromArray(enemyDefensesScummArray, 0, i);
 
 		if (thisElement) {
-			if (GetBuildingOwner(thisElement)) {
-				if (GetPlayerTeam(currentPlayer) != GetBuildingTeam(thisElement)) {
-					int type = GetBuildingType(thisElement);
+			if (getBuildingOwner(thisElement)) {
+				if (getPlayerTeam(currentPlayer) != getBuildingTeam(thisElement)) {
+					int type = getBuildingType(thisElement);
 
 					switch (type) {
 					case BUILDING_ANTI_AIR:
@@ -63,7 +63,7 @@ void Sortie::setEnemyDefenses(int enemyDefensesScummArray, int defendX, int defe
 						break;
 
 					case BUILDING_EXPLOSIVE_MINE:
-						if (GetDistance(GetHubX(thisElement), GetHubY(thisElement), defendX, defendY) < 90)
+						if (getDistance(getHubX(thisElement), getHubY(thisElement), defendX, defendY) < 90)
 							thisUnit = new MineUnit();
 						else
 							thisUnit = NULL;
@@ -81,9 +81,9 @@ void Sortie::setEnemyDefenses(int enemyDefensesScummArray, int defendX, int defe
 
 					if (thisUnit != NULL) {
 						thisUnit->setID(thisElement);
-						thisUnit->setPos(GetHubX(thisElement), GetHubY(thisElement));
+						thisUnit->setPos(getHubX(thisElement), getHubY(thisElement));
 
-						if (GetBuildingState(thisElement)) thisUnit->setState(DUS_OFF);
+						if (getBuildingState(thisElement)) thisUnit->setState(DUS_OFF);
 
 						_enemyDefenses.push_back(thisUnit);
 					}
@@ -117,7 +117,7 @@ IContainedObject *Sortie::createChildObj(int index, int &completionFlag) {
 	Common::Array<DefenseUnit *> thisEnemyDefenses;
 
 	// Copy the defensive unit list from the parent
-	for (Common::Array<DefenseUnit *>::iterator k = _enemyDefenses.begin(); k != _enemyDefenses.end(); ++k) {
+	for (Common::Array<DefenseUnit *>::iterator k = _enemyDefenses.begin(); k != _enemyDefenses.end(); k++) {
 		DefenseUnit *temp;
 
 		switch ((*k)->getType()) {
@@ -155,7 +155,7 @@ IContainedObject *Sortie::createChildObj(int index, int &completionFlag) {
 	retSortie->setUnitType(currentWeapon->getTypeID());
 
 	// Calculate distance from target to source hub
-	int distance = GetDistance(currentTarget->getPosX(), currentTarget->getPosY(), getSourcePosX(), getSourcePosY());
+	int distance = getDistance(currentTarget->getPosX(), currentTarget->getPosY(), getSourcePosX(), getSourcePosY());
 
 	// Pick correct shot position according to index
 	Common::Point *targetCoords;
@@ -168,8 +168,8 @@ IContainedObject *Sortie::createChildObj(int index, int &completionFlag) {
 	int AAcounter = 3;
 
 	// Loop through defensive units, toggling anti-air units and deciding if this weapon will land safely
-	for (Common::Array<DefenseUnit *>::iterator i = thisEnemyDefenses.begin(); i != thisEnemyDefenses.end(); ++i) {
-		distance = GetDistance((*i)->getPosX(), (*i)->getPosY(), targetCoords->x, targetCoords->y);
+	for (Common::Array<DefenseUnit *>::iterator i = thisEnemyDefenses.begin(); i != thisEnemyDefenses.end(); i++) {
+		distance = getDistance((*i)->getPosX(), (*i)->getPosY(), targetCoords->x, targetCoords->y);
 
 		// Check to see if we're within an active defense's radius
 		if ((distance < (*i)->getRadius()) && ((*i)->getState() == DUS_ON)) {
@@ -198,7 +198,7 @@ IContainedObject *Sortie::createChildObj(int index, int &completionFlag) {
 	}
 
 	// Turn on all the non-anti-air units in preparation for emp's and the next turn
-	for (Common::Array<DefenseUnit *>::iterator i = thisEnemyDefenses.begin(); i != thisEnemyDefenses.end(); ++i) {
+	for (Common::Array<DefenseUnit *>::iterator i = thisEnemyDefenses.begin(); i != thisEnemyDefenses.end(); i++) {
 		if ((*i)->getType() != DUT_ANTI_AIR) {
 			(*i)->setState(DUS_ON);
 		}
@@ -210,10 +210,10 @@ IContainedObject *Sortie::createChildObj(int index, int &completionFlag) {
 		for (Common::Array<DefenseUnit *>::iterator i = thisEnemyDefenses.begin(); i != thisEnemyDefenses.end(); ) {
 			// Special simulated crawler detonation location used, since it walks a bit
 			if (currentWeapon->getTypeID() == ITEM_CRAWLER)
-				distance = GetDistance((*i)->getPosX(), (*i)->getPosY(), currentTarget->getPosX(), currentTarget->getPosY());
+				distance = getDistance((*i)->getPosX(), (*i)->getPosY(), currentTarget->getPosX(), currentTarget->getPosY());
 			// Normal detonation location used here
 			else {
-				distance = GetDistance((*i)->getPosX(), (*i)->getPosY(), targetCoords->x, targetCoords->y);
+				distance = getDistance((*i)->getPosX(), (*i)->getPosY(), targetCoords->x, targetCoords->y);
 			}
 
 			if (distance < currentWeapon->getRadius()) {
@@ -238,10 +238,10 @@ IContainedObject *Sortie::createChildObj(int index, int &completionFlag) {
 					delete *i;
 					i = thisEnemyDefenses.erase(i);
 				} else {
-					++i;
+					i++;
 				}
 			} else {
-				++i;
+				i++;
 			}
 		}
 	}
@@ -257,7 +257,7 @@ float Sortie::calcH() {
 	float retValue = 0;
 	Common::Array<DefenseUnit *> thisEnemyDefenses = getEnemyDefenses();
 
-	for (Common::Array<DefenseUnit *>::iterator i = thisEnemyDefenses.begin(); i != thisEnemyDefenses.end(); ++i) {
+	for (Common::Array<DefenseUnit *>::iterator i = thisEnemyDefenses.begin(); i != thisEnemyDefenses.end(); i++) {
 		if ((*i)->getState() == DUS_ON) {
 			switch ((*i)->getType()) {
 			case DUT_ANTI_AIR:
@@ -285,7 +285,7 @@ int Sortie::checkSuccess() {
 
 	int targetCheck = 0;
 
-	for (Common::Array<DefenseUnit *>::iterator i = _enemyDefenses.begin(); i != _enemyDefenses.end(); ++i) {
+	for (Common::Array<DefenseUnit *>::iterator i = _enemyDefenses.begin(); i != _enemyDefenses.end(); i++) {
 		if (((*i)->getState() == DUS_ON) && ((*i)->getType() != DUT_HUB)) {
 			return 0;
 		}
@@ -314,41 +314,41 @@ IContainedObject *Sortie::duplicate() {
 
 
 void Sortie::printEnemyDefenses() {
-	for (Common::Array<DefenseUnit *>::iterator i = _enemyDefenses.begin(); i != _enemyDefenses.end(); ++i) {
+	for (Common::Array<DefenseUnit *>::iterator i = _enemyDefenses.begin(); i != _enemyDefenses.end(); i++) {
 		warning("Unit %d - Type: %d, Armor: %d, Status: %d", (*i)->getID(), (*i)->getType(), static_cast<int>((*i)->getArmor()), (*i)->getState());
 	}
 }
 
 int Defender::calculateDefenseUnitPosition(int targetX, int targetY, int index) {
-	int currentPlayer = GetCurrentPlayer();
+	int currentPlayer = getCurrentPlayer();
 
-	//Get list of near hubs
-	int unitsArray = GetUnitsWithinRadius(targetX + 5, targetY, 480);
+	//get list of near hubs
+	int unitsArray = getUnitsWithinRadius(targetX + 5, targetY, 480);
 
 	const int NUM_HUBS = 10;
 	//Order on dist
 	int hubArray[NUM_HUBS] = { 0 };
 	int hubIndex = 0;
 
-	for (int i = 0; i < 200; ++i) {
+	for (int i = 0; i < 200; i++) {
 		int thisUnit = _vm->_moonbase->readFromArray(unitsArray, 0, i);
 
 		if (thisUnit) {
-			if (((GetBuildingType(thisUnit) == BUILDING_MAIN_BASE) || (GetBuildingType(thisUnit) == BUILDING_OFFENSIVE_LAUNCHER))  && (GetBuildingOwner(thisUnit) == currentPlayer)) {
-				for (int j = 0; j < NUM_HUBS; ++j) {
+			if (((getBuildingType(thisUnit) == BUILDING_MAIN_BASE) || (getBuildingType(thisUnit) == BUILDING_OFFENSIVE_LAUNCHER))  && (getBuildingOwner(thisUnit) == currentPlayer)) {
+				for (int j = 0; j < NUM_HUBS; j++) {
 					if (hubArray[j]) {
-						int distCurrent = GetDistance(targetX, targetY, GetHubX(thisUnit), GetHubY(thisUnit));
-						int distSaved = GetDistance(targetX, targetY, GetHubX(hubArray[j]), GetHubY(hubArray[j]));
+						int distCurrent = getDistance(targetX, targetY, getHubX(thisUnit), getHubY(thisUnit));
+						int distSaved = getDistance(targetX, targetY, getHubX(hubArray[j]), getHubY(hubArray[j]));
 
 						if (distCurrent < distSaved) {
 							hubArray[hubIndex] = hubArray[j];
 							hubArray[j] = thisUnit;
-							++hubIndex;
+							hubIndex++;
 							j = 100;
 						}
 					} else {
 						hubArray[j] = thisUnit;
-						++hubIndex;
+						hubIndex++;
 						j = 100;
 					}
 				}
@@ -364,21 +364,21 @@ int Defender::calculateDefenseUnitPosition(int targetX, int targetY, int index)
 	_vm->nukeArray(unitsArray);
 
 	//Check if repair is needed
-	int targetUnit = GetClosestUnit(targetX + 5, targetY, 15, currentPlayer, 1, 0, 0, 0);
+	int targetUnit = getClosestUnit(targetX + 5, targetY, 15, currentPlayer, 1, 0, 0, 0);
 
-	if (targetUnit && (targetUnit != BUILDING_CRAWLER) && (GetBuildingTeam(targetUnit) == GetPlayerTeam(currentPlayer))) {
-		int armor = GetBuildingArmor(targetUnit);
+	if (targetUnit && (targetUnit != BUILDING_CRAWLER) && (getBuildingTeam(targetUnit) == getPlayerTeam(currentPlayer))) {
+		int armor = getBuildingArmor(targetUnit);
 
-		if (armor < GetBuildingMaxArmor(targetUnit)) {
-			unitsArray = GetUnitsWithinRadius(targetX + 5, targetY, 170);
+		if (armor < getBuildingMaxArmor(targetUnit)) {
+			unitsArray = getUnitsWithinRadius(targetX + 5, targetY, 170);
 			int defCount = 0;
 
-			for (int i = 0; i < 200; ++i) {
+			for (int i = 0; i < 200; i++) {
 				int thisUnit = _vm->_moonbase->readFromArray(unitsArray, 0, i);
 
 				if (thisUnit) {
-					if (((GetBuildingType(thisUnit) == BUILDING_SHIELD) || (GetBuildingType(thisUnit) == BUILDING_ANTI_AIR)) && (GetBuildingOwner(thisUnit) == currentPlayer) && (GetBuildingState(thisUnit) == 0)) {
-						++defCount;
+					if (((getBuildingType(thisUnit) == BUILDING_SHIELD) || (getBuildingType(thisUnit) == BUILDING_ANTI_AIR)) && (getBuildingOwner(thisUnit) == currentPlayer) && (getBuildingState(thisUnit) == 0)) {
+						defCount++;
 						i = 200;
 					}
 				}
@@ -388,10 +388,10 @@ int Defender::calculateDefenseUnitPosition(int targetX, int targetY, int index)
 
 			if (defCount) {
 				//repair
-				int hubUnit = GetClosestUnit(targetX, targetY, 480, currentPlayer, 1, BUILDING_MAIN_BASE, 1, 110);
+				int hubUnit = getClosestUnit(targetX, targetY, 480, currentPlayer, 1, BUILDING_MAIN_BASE, 1, 110);
 
 				if (hubUnit && (hubUnit != targetUnit)) {
-					int powAngle = abs(GetPowerAngleFromPoint(GetHubX(hubUnit), GetHubY(hubUnit), targetX, targetY, 20));
+					int powAngle = abs(getPowerAngleFromPoint(getHubX(hubUnit), getHubY(hubUnit), targetX, targetY, 20));
 					int power = powAngle / 360;
 					int angle = powAngle - (power * 360);
 
@@ -410,23 +410,23 @@ int Defender::calculateDefenseUnitPosition(int targetX, int targetY, int index)
 	}
 
 	//For each hub
-	for (int i = 0; i < MIN(NUM_HUBS, hubIndex); ++i) {
-		int hubX = GetHubX(hubArray[i]);
-		int hubY = GetHubY(hubArray[i]);
-		//Get angle to hub
+	for (int i = 0; i < MIN(NUM_HUBS, hubIndex); i++) {
+		int hubX = getHubX(hubArray[i]);
+		int hubY = getHubY(hubArray[i]);
+		//get angle to hub
 		int directAngleToHub = 0;
 
 		//If this hub is the target
 		if ((hubX == targetX) && (hubY == targetY)) {
 			//make the angle seed point at the closest enemy
-			int enemyUnit = GetClosestUnit(hubX, hubY, GetMaxX(), currentPlayer, 0, 0, 0);
-			directAngleToHub = GetAngle(targetX, targetY, GetHubX(enemyUnit), GetHubY(enemyUnit));
+			int enemyUnit = getClosestUnit(hubX, hubY, getMaxX(), currentPlayer, 0, 0, 0);
+			directAngleToHub = calcAngle(targetX, targetY, getHubX(enemyUnit), getHubY(enemyUnit));
 		} else {
-			directAngleToHub = GetAngle(targetX, targetY, hubX, hubY);
+			directAngleToHub = calcAngle(targetX, targetY, hubX, hubY);
 		}
 
 		//Number of random chances to land
-		for (int j = 0; j < 3; ++j) {
+		for (int j = 0; j < 3; j++) {
 			//Pick random angle and dist within semicircle (-90 to +90) and (40 to 150)
 			int randAngle = directAngleToHub + _vm->_rnd.getRandomNumber(179) - 90;
 			int randDist = _vm->_rnd.getRandomNumber(109) + 40;
@@ -434,7 +434,7 @@ int Defender::calculateDefenseUnitPosition(int targetX, int targetY, int index)
 			int x = targetX + randDist * cos(degToRad(randAngle));
 			int y = targetY + randDist * sin(degToRad(randAngle));
 
-			int powAngle = GetPowerAngleFromPoint(hubX, hubY, x, y, 20);
+			int powAngle = getPowerAngleFromPoint(hubX, hubY, x, y, 20);
 
 			if (powAngle < 0)
 				continue;
@@ -443,7 +443,7 @@ int Defender::calculateDefenseUnitPosition(int targetX, int targetY, int index)
 			int angle = powAngle - (power * 360);
 
 			int coords = 0;
-			coords = SimulateBuildingLaunch(hubX, hubY, power, angle, 100, 0);
+			coords = simulateBuildingLaunch(hubX, hubY, power, angle, 100, 0);
 
 			//if valid, return
 			if (coords > 0) {
@@ -451,28 +451,28 @@ int Defender::calculateDefenseUnitPosition(int targetX, int targetY, int index)
 
 				setSourceX(hubX);
 				setSourceY(hubY);
-				setTargetX((x + GetMaxX()) % GetMaxX());
-				setTargetY((y + GetMaxY()) % GetMaxY());
+				setTargetX((x + getMaxX()) % getMaxX());
+				setTargetY((y + getMaxY()) % getMaxY());
 				setSourceUnit(hubArray[i]);
 
-				int unitsArray2 = GetUnitsWithinRadius(targetX + 5, targetY, 200);
+				int unitsArray2 = getUnitsWithinRadius(targetX + 5, targetY, 200);
 				int shieldCount = 0;
 
-				for (int k = 0; k < 200; ++k) {
+				for (int k = 0; k < 200; k++) {
 					int thisUnit = _vm->_moonbase->readFromArray(unitsArray2, 0, k);
 
 					if (thisUnit) {
-						if ((GetBuildingType(thisUnit) == BUILDING_SHIELD) && (GetBuildingOwner(thisUnit) == currentPlayer))
+						if ((getBuildingType(thisUnit) == BUILDING_SHIELD) && (getBuildingOwner(thisUnit) == currentPlayer))
 							shieldCount++;
 
-						if ((GetBuildingType(thisUnit) == BUILDING_BRIDGE) && (GetBuildingOwner(thisUnit) == currentPlayer)) {
+						if ((getBuildingType(thisUnit) == BUILDING_BRIDGE) && (getBuildingOwner(thisUnit) == currentPlayer)) {
 							shieldCount--;
 							shieldCount = MAX(-1, shieldCount);
 						}
 					}
 				}
 
-				if ((_vm->_rnd.getRandomNumber((int)pow(3, shieldCount + 1) - 1) == 0) && (GetPlayerEnergy() > 6))
+				if ((_vm->_rnd.getRandomNumber((int)pow(3, shieldCount + 1) - 1) == 0) && (getPlayerEnergy() > 6))
 					setUnit(ITEM_SHIELD);
 				else
 					setUnit(ITEM_ANTIAIR);
@@ -486,12 +486,11 @@ int Defender::calculateDefenseUnitPosition(int targetX, int targetY, int index)
 
 			if (coords < 0) {
 				//drop a bridge for the cord
-				int yCoord  = -coords / GetMaxX();
-				int xCoord = -coords - (yCoord * GetMaxX());
+				int yCoord  = -coords / getMaxX();
+				int xCoord = -coords - (yCoord * getMaxX());
 
-				if (CheckIfWaterState(xCoord, yCoord)) {
-
-					int terrainSquareSize = GetTerrainSquareSize();
+				if (checkIfWaterState(xCoord, yCoord)) {
+					int terrainSquareSize = getTerrainSquareSize();
 					xCoord = ((xCoord / terrainSquareSize * terrainSquareSize) + (terrainSquareSize / 2));
 					yCoord = ((yCoord / terrainSquareSize * terrainSquareSize) + (terrainSquareSize / 2));
 
@@ -503,8 +502,8 @@ int Defender::calculateDefenseUnitPosition(int targetX, int targetY, int index)
 					setTargetX(x);
 					setTargetY(y);
 
-					int nextUnit = GetClosestUnit(x, y, 480, GetCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, 120);
-					powAngle = GetPowerAngleFromPoint(GetHubX(nextUnit), GetHubY(nextUnit), x, y, 15);
+					int nextUnit = getClosestUnit(x, y, 480, getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, 120);
+					powAngle = getPowerAngleFromPoint(getHubX(nextUnit), getHubY(nextUnit), x, y, 15);
 
 					powAngle = abs(powAngle);
 					power = powAngle / 360;
@@ -530,8 +529,8 @@ int Defender::calculateDefenseUnitPosition(int targetX, int targetY, int index)
 	do {
 		int sourceHub = hubArray[_vm->_rnd.getRandomNumber(hubIndex - 1)];
 
-		setSourceX(GetHubX(sourceHub));
-		setSourceY(GetHubY(sourceHub));
+		setSourceX(getHubX(sourceHub));
+		setSourceY(getHubY(sourceHub));
 		setSourceUnit(sourceHub);
 		setUnit(ITEM_HUB);
 		setPower(_vm->_rnd.getRandomNumber(299) + 200);
@@ -540,12 +539,12 @@ int Defender::calculateDefenseUnitPosition(int targetX, int targetY, int index)
 
 		if (count > (NUM_HUBS * 3)) break;
 
-		coords = SimulateBuildingLaunch(getSourceX(), getSourceY(), getPower(), getAngle(), 100, 0);
+		coords = simulateBuildingLaunch(getSourceX(), getSourceY(), getPower(), getAngle(), 100, 0);
 	} while (coords <= 0);
 
 	if (coords > 0) {
-		setTargetX(coords % GetMaxX());
-		setTargetY(coords / GetMaxX());
+		setTargetX(coords % getMaxX());
+		setTargetY(coords / getMaxX());
 	} else {
 		setTargetX(0);
 		setTargetY(0);
diff --git a/engines/scumm/he/moonbase/ai_traveller.cpp b/engines/scumm/he/moonbase/ai_traveller.cpp
index 5437ab1..68cf0c0 100644
--- a/engines/scumm/he/moonbase/ai_traveller.cpp
+++ b/engines/scumm/he/moonbase/ai_traveller.cpp
@@ -48,7 +48,7 @@ Traveller::Traveller(int originX, int originY) {
 }
 
 void Traveller::adjustPosX(int offsetX) {
-	int maxX = GetMaxX();
+	int maxX = getMaxX();
 	int deltaX = _posX + offsetX;
 
 	if (deltaX < 0) _posX = maxX + deltaX;
@@ -57,7 +57,7 @@ void Traveller::adjustPosX(int offsetX) {
 }
 
 void Traveller::adjustPosY(int offsetY) {
-	int maxY = GetMaxX();
+	int maxY = getMaxX();
 	int deltaY = _posY + offsetY;
 
 	if (deltaY < 0) _posY = maxY + deltaY;
@@ -73,7 +73,7 @@ void Traveller::adjustXY(int offsetX, int offsetY) {
 float Traveller::calcH() {
 	float retVal = 0;
 	// Calc dist from here to target
-	retVal = GetDistance(_posX, _posY, _targetPosX, _targetPosY);
+	retVal = getDistance(_posX, _posY, _targetPosX, _targetPosY);
 	// Divide by _maxDist to get minimum number of jumps to goal
 	retVal /= static_cast<float>(_maxDist);
 
@@ -82,7 +82,7 @@ float Traveller::calcH() {
 
 int Traveller::numChildrenToGen() {
 	if (!_numToGen)
-		_numToGen = GetAnimSpeed() + 2;
+		_numToGen = getAnimSpeed() + 2;
 
 	return _numToGen;
 }
@@ -103,14 +103,14 @@ IContainedObject *Traveller::createChildObj(int index, int &completionFlag) {
 		// Calculate angle between here and target
 		int directAngle = 0;
 
-		if (GetEnergyHogType())
-			directAngle = GetAngle(_posX, _posY, _targetPosX, _targetPosY, 1);
+		if (getEnergyHogType())
+			directAngle = calcAngle(_posX, _posY, _targetPosX, _targetPosY, 1);
 		else
-			directAngle = GetAngle(_posX, _posY, _targetPosX, _targetPosY);
+			directAngle = calcAngle(_posX, _posY, _targetPosX, _targetPosY);
 
 		// Calculate the offset angle for this index
 		if (!_sizeAngleStep)
-			_sizeAngleStep = 52 - (GetAnimSpeed() * 7);
+			_sizeAngleStep = 52 - (getAnimSpeed() * 7);
 
 		dir = _sizeAngleStep * ((static_cast<int>(index / NUM_POWER_STEPS) + 1) >> 1);
 		// Calculate the sign value for the offset for this index
@@ -120,12 +120,12 @@ IContainedObject *Traveller::createChildObj(int index, int &completionFlag) {
 
 		// Calculate power for this index
 		int maxPower = 0;
-		int directDist = GetDistance(_posX, _posY, _targetPosX, _targetPosY);
+		int directDist = getDistance(_posX, _posY, _targetPosX, _targetPosY);
 
 		if (directDist > _maxDist + 120)
-			maxPower = GetMaxPower();
+			maxPower = getMaxPower();
 		else
-			maxPower = (static_cast<float>(directDist) / static_cast<float>(_maxDist + 120)) * GetMaxPower();
+			maxPower = (static_cast<float>(directDist) / static_cast<float>(_maxDist + 120)) * getMaxPower();
 
 		maxPower -= 70;
 		power = maxPower * (1 - ((index % NUM_POWER_STEPS) * SIZE_POWER_STEP));
@@ -139,7 +139,7 @@ IContainedObject *Traveller::createChildObj(int index, int &completionFlag) {
 	int coords = 0;
 
 	if (!(index % NUM_POWER_STEPS) || (!lastSuccessful)) {
-		coords = SimulateBuildingLaunch(_posX, _posY, power, angle, 10, 0);
+		coords = simulateBuildingLaunch(_posX, _posY, power, angle, 10, 0);
 		lastSuccessful = 0;
 	} else {
 		completionState = 1;
@@ -156,34 +156,34 @@ IContainedObject *Traveller::createChildObj(int index, int &completionFlag) {
 		completionState = 1;
 	}
 
-	int whoseTurn = GetCurrentPlayer();
-	int maxX = GetMaxX();
+	int whoseTurn = getCurrentPlayer();
+	int maxX = getMaxX();
 
 	// Check new position to see if landing is clear
 	if (coords > 0) {
 		int yCoord = coords / maxX;
 		int xCoord = coords - (yCoord * maxX);
 
-		int terrain = GetTerrain(xCoord, yCoord);
+		int terrain = getTerrain(xCoord, yCoord);
 		assert(terrain == TERRAIN_TYPE_GOOD);
 
-		float pwr = GetMinPower() * .3;
+		float pwr = getMinPower() * .3;
 		float cosine = cos((static_cast<float>(angle) / 360) * (2 * M_PI));
 		float sine = sin((static_cast<float>(angle) / 360) * (2 * M_PI));
 		int xParam = xCoord + (pwr * cosine);
 		int yParam = yCoord + (pwr * sine);
 
 		if (xParam < 0)
-			xParam += GetMaxX();
-		else if (xParam > GetMaxX())
-			xParam -= GetMaxX();
+			xParam += getMaxX();
+		else if (xParam > getMaxX())
+			xParam -= getMaxX();
 
 		if (yParam < 0)
-			yParam += GetMaxY();
-		else if (yParam > GetMaxY())
-			yParam -= GetMaxY();
+			yParam += getMaxY();
+		else if (yParam > getMaxY())
+			yParam -= getMaxY();
 
-		if (CheckIfWaterState(xParam, yParam)) {
+		if (checkIfWaterState(xParam, yParam)) {
 			delete retTraveller;
 			return NULL;
 		}
@@ -192,7 +192,7 @@ IContainedObject *Traveller::createChildObj(int index, int &completionFlag) {
 		retTraveller->setPosX(xCoord);
 
 		// Iterate through the previous action list, making sure this one isn't on it
-		for (intVecItr i = (lastXCoord[whoseTurn]).begin(), j = (lastYCoord[whoseTurn]).begin(); i != (lastXCoord[whoseTurn]).end(); ++i, ++j) {
+		for (intVecItr i = (lastXCoord[whoseTurn]).begin(), j = (lastYCoord[whoseTurn]).begin(); i != (lastXCoord[whoseTurn]).end(); i++, j++) {
 			// Check if this shot is the same as the last time we tried
 			if ((*i == retTraveller->getPosX()) && (*j == retTraveller->getPosY())) {
 				retTraveller->setDisabled();
@@ -208,8 +208,8 @@ IContainedObject *Traveller::createChildObj(int index, int &completionFlag) {
 		int xCoord = -coords - (yCoord * maxX);
 
 		// If landing fault is because of water, add 1 extra to g and turn on water flag.  Also set coords, and adjust power to water fault location
-		if (CheckIfWaterState(xCoord, yCoord)) {
-			int terrainSquareSize = GetTerrainSquareSize();
+		if (checkIfWaterState(xCoord, yCoord)) {
+			int terrainSquareSize = getTerrainSquareSize();
 			xCoord = ((xCoord / terrainSquareSize * terrainSquareSize) + (terrainSquareSize / 2));
 			yCoord = ((yCoord / terrainSquareSize * terrainSquareSize) + (terrainSquareSize / 2));
 
@@ -218,10 +218,10 @@ IContainedObject *Traveller::createChildObj(int index, int &completionFlag) {
 			retTraveller->setPosX(xCoord + (terrainSquareSize * 1.414 * (xDist / (abs(xDist) + 1))));
 			retTraveller->setPosY(yCoord + (terrainSquareSize * 1.414 * (yDist / (abs(yDist) + 1))));
 
-			int closestHub = GetClosestUnit(retTraveller->getPosX(), retTraveller->getPosY(), GetMaxX(), GetCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, 110);
+			int closestHub = getClosestUnit(retTraveller->getPosX(), retTraveller->getPosY(), getMaxX(), getCurrentPlayer(), 1, BUILDING_MAIN_BASE, 1, 110);
 
-			retTraveller->setWaterSourceX(GetHubX(closestHub));
-			retTraveller->setWaterSourceY(GetHubY(closestHub));
+			retTraveller->setWaterSourceX(getHubX(closestHub));
+			retTraveller->setWaterSourceY(getHubY(closestHub));
 			retTraveller->setWaterDestX(retTraveller->getPosX());
 			retTraveller->setWaterDestY(retTraveller->getPosY());
 
@@ -242,7 +242,7 @@ IContainedObject *Traveller::createChildObj(int index, int &completionFlag) {
 }
 
 int Traveller::checkSuccess() {
-	if (GetDistance(_posX + 1, _posY, _targetPosX, _targetPosY) < _maxDist)
+	if (getDistance(_posX + 1, _posY, _targetPosX, _targetPosY) < _maxDist)
 		return SUCCESS;
 
 	return 0;
diff --git a/engines/scumm/he/moonbase/ai_traveller.h b/engines/scumm/he/moonbase/ai_traveller.h
index 7b1bad9..63a56d7 100644
--- a/engines/scumm/he/moonbase/ai_traveller.h
+++ b/engines/scumm/he/moonbase/ai_traveller.h
@@ -108,7 +108,7 @@ public:
 
 	void enableWaterFlag() { _waterFlag = 1; }
 	void disableWaterFlag() { _waterFlag = 0; }
-	int GetWaterFlag() const { return _waterFlag; }
+	int getWaterFlag() const { return _waterFlag; }
 
 	virtual int numChildrenToGen();
 	virtual IContainedObject *createChildObj(int, int &);
diff --git a/engines/scumm/he/moonbase/ai_tree.h b/engines/scumm/he/moonbase/ai_tree.h
index c76d03c..cb3c8c5 100644
--- a/engines/scumm/he/moonbase/ai_tree.h
+++ b/engines/scumm/he/moonbase/ai_tree.h
@@ -55,7 +55,7 @@ public:
 
 	void duplicateTree(Node *sourceNode, Node *destNode);
 
-	Node *GetBaseNode() const { return pBaseNode; }
+	Node *getBaseNode() const { return pBaseNode; }
 	void setMaxDepth(int maxDepth) { m_maxDepth = maxDepth; }
 	int getMaxDepth() const { return m_maxDepth; }
 
diff --git a/engines/scumm/he/moonbase/ai_types.h b/engines/scumm/he/moonbase/ai_types.h
index 1e8c829..e2de87d 100644
--- a/engines/scumm/he/moonbase/ai_types.h
+++ b/engines/scumm/he/moonbase/ai_types.h
@@ -77,19 +77,19 @@ public:
 		}
 	}
 
-	int GetID() const { return _id; }
-	char *GetNameString() const { return _nameString; }
-	int GetBehaviorVariation() const { return _behaviorVariation; }
-	int GetTargetVariation() const { return _targetVariation; }
-	int GetAngleVariation() const { return _angleVariation; }
-	int GetPowerVariation() const { return _powerVariation; }
+	int getID() const { return _id; }
+	char *getNameString() const { return _nameString; }
+	int getBehaviorVariation() const { return _behaviorVariation; }
+	int getTargetVariation() const { return _targetVariation; }
+	int getAngleVariation() const { return _angleVariation; }
+	int getPowerVariation() const { return _powerVariation; }
 
-	void SetID(int id) { _id = id; }
-	void SetNameString(char *nameString) { _nameString = nameString; }
-	void SetBehaviorVariation(int behaviorVariation) { _behaviorVariation = behaviorVariation; }
-	void SetTargetVariation(int targetVariation) { _targetVariation = targetVariation; }
-	void SetAngleVariation(int angleVariation) { _angleVariation = angleVariation; }
-	void SetPowerVariation(int powerVariation) { _powerVariation = powerVariation; }
+	void setID(int id) { _id = id; }
+	void setNameString(char *nameString) { _nameString = nameString; }
+	void setBehaviorVariation(int behaviorVariation) { _behaviorVariation = behaviorVariation; }
+	void setTargetVariation(int targetVariation) { _targetVariation = targetVariation; }
+	void setAngleVariation(int angleVariation) { _angleVariation = angleVariation; }
+	void setPowerVariation(int powerVariation) { _powerVariation = powerVariation; }
 };
 
 } // End of namespace Scumm
diff --git a/engines/scumm/he/moonbase/moonbase.cpp b/engines/scumm/he/moonbase/moonbase.cpp
index 46d60ec..cc25c27 100644
--- a/engines/scumm/he/moonbase/moonbase.cpp
+++ b/engines/scumm/he/moonbase/moonbase.cpp
@@ -38,6 +38,22 @@ int Moonbase::readFromArray(int array, int y, int x) {
 	return _vm->readArray(116, y, x);
 }
 
+int Moonbase::callScummFunction(int scriptNumber, int paramCount,...) {
+	va_list va_params;
+	va_start(va_params, paramCount);
+	int args[25];
+
+	for (int i = 0; i < paramCount; i++)
+		args[i] = va_arg(va_params, int);
+
+	va_end(va_params);
+
+	_vm->runScript(scriptNumber, 0, 1, args);
+
+	return _vm->pop();
+}
+
+
 void Moonbase::blitT14WizImage(uint8 *dst, int dstw, int dsth, int dstPitch, const Common::Rect *clipBox,
 		 uint8 *wizd, int x, int y, int rawROP, int paramROP) {
 	bool premulAlpa = false;
diff --git a/engines/scumm/he/moonbase/moonbase.h b/engines/scumm/he/moonbase/moonbase.h
index a056b54..7d93661 100644
--- a/engines/scumm/he/moonbase/moonbase.h
+++ b/engines/scumm/he/moonbase/moonbase.h
@@ -35,6 +35,7 @@ public:
 	~Moonbase();
 
 	int readFromArray(int array, int y, int x);
+	int callScummFunction(int scriptNumber, int paramCount,...);
 
 	void blitT14WizImage(uint8 *dst, int dstw, int dsth, int dstPitch, const Common::Rect *clipBox,
 			 uint8 *wizd, int srcx, int srcy, int rawROP, int paramROP);
diff --git a/engines/scumm/module.mk b/engines/scumm/module.mk
index 57b6872..e6d2d36 100644
--- a/engines/scumm/module.mk
+++ b/engines/scumm/module.mk
@@ -140,6 +140,7 @@ MODULE_OBJS += \
 	he/logic/puttrace.o \
 	he/logic/soccer.o \
 	he/moonbase/ai_defenseunit.o \
+	he/moonbase/ai_main.o \
 	he/moonbase/ai_node.o \
 	he/moonbase/ai_targetacquisition.o \
 	he/moonbase/ai_traveller.o \
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index cfb0c70..4adf0c5 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -891,6 +891,13 @@ ScummEngine_v90he::ScummEngine_v90he(OSystem *syst, const DetectorResult &dr)
 
 	if (_game.id == GID_MOONBASE)
 		_moonbase = new Moonbase(this);
+
+	VAR_U32_USER_VAR_A = 0xFF;
+	VAR_U32_USER_VAR_B = 0xFF;
+	VAR_U32_USER_VAR_C = 0xFF;
+	VAR_U32_USER_VAR_D = 0xFF;
+	VAR_U32_USER_VAR_E = 0xFF;
+	VAR_U32_USER_VAR_F = 0xFF;
 }
 
 ScummEngine_v90he::~ScummEngine_v90he() {
diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h
index e519fd9..a3fa329 100644
--- a/engines/scumm/scumm.h
+++ b/engines/scumm/scumm.h
@@ -700,8 +700,9 @@ protected:
 	void ignoreScriptWord() { fetchScriptWord(); }
 	void ignoreScriptByte() { fetchScriptByte(); }
 	void push(int a);
+
+public: // TODO. FIXME should be protected. Used by Moonbase
 	int pop();
-public: // TODO. FIXME
 	virtual int readVar(uint var);
 	virtual void writeVar(uint var, int value);
 
diff --git a/engines/scumm/scumm_v2.h b/engines/scumm/scumm_v2.h
index 339964b..763bbc0 100644
--- a/engines/scumm/scumm_v2.h
+++ b/engines/scumm/scumm_v2.h
@@ -77,7 +77,8 @@ protected:
 
 	void getResultPosIndirect();
 	virtual void getResultPos();
-public: // TODO. FIXME
+
+public: // TODO. FIXME. Should be protected. Used by Moonbase
 	virtual int readVar(uint var);
 	virtual void writeVar(uint var, int value);
 
diff --git a/engines/scumm/vars.cpp b/engines/scumm/vars.cpp
index a6be5c3..5254aa4 100644
--- a/engines/scumm/vars.cpp
+++ b/engines/scumm/vars.cpp
@@ -340,6 +340,14 @@ void ScummEngine_v90he::setupScummVars() {
 		VAR_NUM_PALETTES = 130;
 		VAR_NUM_UNK = 131;
 	}
+	if (_game.id == GID_MOONBASE) {
+		VAR_U32_USER_VAR_A = 108;
+		VAR_U32_USER_VAR_B = 109;
+		VAR_U32_USER_VAR_C = 110;
+		VAR_U32_USER_VAR_D = 111;
+		VAR_U32_USER_VAR_E = 112;
+		VAR_U32_USER_VAR_F = 113;
+	}
 }
 #endif
 


Commit: 441f630ec53a2ece2f2afe46520cd73801069c5f
    https://github.com/scummvm/scummvm/commit/441f630ec53a2ece2f2afe46520cd73801069c5f
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2016-05-22T00:45:05+02:00

Commit Message:
SCUMM HE: Added stub for Tree class

Changed paths:
  A engines/scumm/he/moonbase/ai_tree.cpp
    engines/scumm/he/moonbase/ai_tree.h
    engines/scumm/module.mk



diff --git a/engines/scumm/he/moonbase/ai_tree.cpp b/engines/scumm/he/moonbase/ai_tree.cpp
new file mode 100644
index 0000000..2335d56
--- /dev/null
+++ b/engines/scumm/he/moonbase/ai_tree.cpp
@@ -0,0 +1,222 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "scumm/he/moonbase/ai_tree.h"
+#include "scumm/he/moonbase/ai_main.h"
+
+namespace Scumm {
+
+Tree::Tree() {
+	pBaseNode = new Node;
+	_maxDepth = MAX_DEPTH;
+	_maxNodes = MAX_NODES;
+}
+
+Tree::Tree(IContainedObject *contents) {
+	pBaseNode = new Node;
+	pBaseNode->setContainedObject(contents);
+	_maxDepth = MAX_DEPTH;
+	_maxNodes = MAX_NODES;
+}
+
+Tree::Tree(IContainedObject *contents, int maxDepth) {
+	pBaseNode = new Node;
+	pBaseNode->setContainedObject(contents);
+	_maxDepth = maxDepth;
+	_maxNodes = MAX_NODES;
+}
+
+Tree::Tree(IContainedObject *contents, int maxDepth, int maxNodes) {
+	pBaseNode = new Node;
+	pBaseNode->setContainedObject(contents);
+	_maxDepth = maxDepth;
+	_maxNodes = maxNodes;
+}
+
+void Tree::duplicateTree(Node *sourceNode, Node *destNode) {
+	Common::Array<Node *> vUnvisited = sourceNode->getChildren();
+
+	while (vUnvisited.size()) {
+		Node *newNode = new Node(*(vUnvisited.end()));
+		newNode->setParent(destNode);
+		(destNode->getChildren()).push_back(newNode);
+		duplicateTree(*(vUnvisited.end()), newNode);
+		vUnvisited.pop_back();
+	}
+}
+
+Tree::Tree(const Tree *sourceTree) {
+	pBaseNode = new Node(sourceTree->getBaseNode());
+	_maxDepth = sourceTree->getMaxDepth();
+	_maxNodes = sourceTree->getMaxNodes();
+
+	duplicateTree(sourceTree->getBaseNode(), pBaseNode);
+}
+
+Tree::~Tree() {
+	// Delete all nodes
+	Node *pNodeItr = pBaseNode;
+
+	// Depth first traversal of nodes to delete them
+	while (pNodeItr != NULL) {
+		// If any children are left, move to one of them
+		if (!(pNodeItr->getChildren().empty())) {
+			int size = (pNodeItr->getChildren()).size();
+			pNodeItr = pNodeItr->popChild();
+		} else {
+			// Delete this node, and move up to the parent for further processing
+			Node *pTemp = pNodeItr;
+			pNodeItr = pNodeItr->getParent();
+			delete pTemp;
+			pTemp = NULL;
+		}
+	}
+}
+
+
+Node *Tree::aStarSearch() {
+	return NULL;
+#if 0
+	fnpMMap mmfpOpen;
+
+	Node *currentNode = NULL;
+	float currentT;
+
+	Node *retNode = NULL;
+
+	float temp = pBaseNode->getContainedObject()->calcT();
+
+	if (static_cast<int>(temp) != SUCCESS) {
+
+		mmfpOpen.insert(fnpMMap::value_type(pBaseNode->getObjectT(), pBaseNode));
+
+		while (mmfpOpen.size() && (retNode == NULL)) {
+			currentNode = mmfpOpen.begin()->second;
+			mmfpOpen.erase(mmfpOpen.begin());
+
+			if ((currentNode->getDepth() < _maxDepth) && (Node::getNodeCount() < _maxNodes)) {
+				// Generate nodes
+				int numChildren = currentNode->generateChildren();
+				Common::Array<Node *> vChildren = currentNode->getChildren();
+
+				for (Common::Array<Node *>::iterator i = vChildren.begin(); i != vChildren.end(); i++) {
+					IContainedObject *pTemp = (*i)->getContainedObject();
+					currentT = pTemp->calcT();
+
+					if (currentT == SUCCESS) retNode = *i;
+					else mmfpOpen.insert(fnpMMap::value_type(currentT, (*i)));
+				}
+			} else {
+				retNode = currentNode;
+			}
+		}
+	} else {
+		retNode = pBaseNode;
+	}
+
+	return retNode;
+#endif
+}
+
+
+Node *Tree::aStarSearch_singlePassInit() {
+	Node *retNode = NULL;
+
+	currentChildIndex = 1;
+
+	float temp = pBaseNode->getContainedObject()->calcT();
+
+	if (static_cast<int>(temp) != SUCCESS) {
+		//_currentMap.insert(fnpMMap::value_type(pBaseNode->getObjectT(), pBaseNode));
+		//assert(_currentMap.size());
+	} else {
+		retNode = pBaseNode;
+	}
+
+	return retNode;
+}
+
+Node *Tree::aStarSearch_singlePass(Node **currentNode) {
+	currentNode = NULL;
+	float currentT;
+
+	Node *retNode = NULL;
+
+#if 0
+	static int maxTime = 0;
+
+	if (currentChildIndex == 1) {
+		maxTime = getPlayerMaxTime();
+	}
+
+	if (currentChildIndex) {
+		if (!(_currentMap.size())) {
+			retNode = _currentNode;
+			return retNode;
+		}
+
+		_currentNode = _currentMap.begin()->second;
+		_currentMap.erase(_currentMap.begin());
+	}
+
+	if ((_currentNode->getDepth() < _maxDepth) && (Node::getNodeCount() < _maxNodes) && ((!maxTime) || (getTimerValue(3) < maxTime))) {
+		// Generate nodes
+		currentChildIndex = _currentNode->generateChildren();
+
+		if (currentChildIndex) {
+			Common::Array<Node *> vChildren = _currentNode->getChildren();
+
+			if (!vChildren.size() && !_currentMap.size()) {
+				currentChildIndex = 0;
+				retNode = _currentNode;
+			}
+
+			for (Common::Array<Node *>::iterator i = vChildren.begin(); i != vChildren.end(); i++) {
+				IContainedObject *pTemp = (*i)->getContainedObject();
+				currentT = pTemp->calcT();
+
+				if (currentT == SUCCESS) {
+					retNode = *i;
+					i = vChildren.end() - 1;
+				} else {
+					_currentMap.insert(fnpMMap::value_type(currentT, (*i)));
+				}
+			}
+
+			if (!(_currentMap.size()) && (currentT != SUCCESS)) {
+				assert(_currentNode != NULL);
+				retNode = _currentNode;
+			}
+		}
+	} else {
+		retNode = _currentNode;
+	}
+#endif
+
+	return retNode;
+}
+
+int Tree::IsBaseNode(Node *thisNode) {
+	return (thisNode == pBaseNode);
+}
+
+} // End of namespace Scumm
diff --git a/engines/scumm/he/moonbase/ai_tree.h b/engines/scumm/he/moonbase/ai_tree.h
index cb3c8c5..1097665 100644
--- a/engines/scumm/he/moonbase/ai_tree.h
+++ b/engines/scumm/he/moonbase/ai_tree.h
@@ -23,6 +23,7 @@
 #ifndef SCUMM_HE_MOONBASE_AI_TREE_H
 #define SCUMM_HE_MOONBASE_AI_TREE_H
 
+#include "common/hash-str.h"
 #include "scumm/he/moonbase/ai_node.h"
 
 namespace Scumm {
@@ -36,14 +37,13 @@ class Tree {
 private:
 	Node *pBaseNode;
 
-	int m_maxDepth;
-	int m_maxNodes;
+	int _maxDepth;
+	int _maxNodes;
 
 	int currentChildIndex;
-	unsigned long m_startTime;
 
-	//fnpMMap m_currentMap;
-	Node *m_currentNode;
+	Common::StringMap _currentMap;
+	Node *_currentNode;
 
 public:
 	Tree();
@@ -56,14 +56,11 @@ public:
 	void duplicateTree(Node *sourceNode, Node *destNode);
 
 	Node *getBaseNode() const { return pBaseNode; }
-	void setMaxDepth(int maxDepth) { m_maxDepth = maxDepth; }
-	int getMaxDepth() const { return m_maxDepth; }
+	void setMaxDepth(int maxDepth) { _maxDepth = maxDepth; }
+	int getMaxDepth() const { return _maxDepth; }
 
-	void setMaxNodes(int maxNodes) { m_maxNodes = maxNodes; }
-	int getMaxNodes() const { return m_maxNodes; }
-
-	void setStartTime(unsigned long sTime) { m_startTime = sTime; }
-	unsigned long getStartTime() const { return m_startTime; }
+	void setMaxNodes(int maxNodes) { _maxNodes = maxNodes; }
+	int getMaxNodes() const { return _maxNodes; }
 
 	Node *aStarSearch();
 
diff --git a/engines/scumm/module.mk b/engines/scumm/module.mk
index e6d2d36..04611ba 100644
--- a/engines/scumm/module.mk
+++ b/engines/scumm/module.mk
@@ -144,6 +144,7 @@ MODULE_OBJS += \
 	he/moonbase/ai_node.o \
 	he/moonbase/ai_targetacquisition.o \
 	he/moonbase/ai_traveller.o \
+	he/moonbase/ai_tree.o \
 	he/moonbase/ai_types.o \
 	he/moonbase/ai_weapon.o \
 	he/moonbase/moonbase.o \


Commit: ad04376054f9734d81099b36b013478498364cb3
    https://github.com/scummvm/scummvm/commit/ad04376054f9734d81099b36b013478498364cb3
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2016-05-22T00:45:05+02:00

Commit Message:
SCUMM HE: Cleanup

Changed paths:
    engines/scumm/he/moonbase/ai_defenseunit.cpp
    engines/scumm/he/moonbase/ai_defenseunit.h



diff --git a/engines/scumm/he/moonbase/ai_defenseunit.cpp b/engines/scumm/he/moonbase/ai_defenseunit.cpp
index 43223dd..f1f0251 100644
--- a/engines/scumm/he/moonbase/ai_defenseunit.cpp
+++ b/engines/scumm/he/moonbase/ai_defenseunit.cpp
@@ -29,17 +29,17 @@
 namespace Scumm {
 
 DefenseUnit::DefenseUnit() {
-	m_state = DUS_ON;
+	_state = DUS_ON;
 }
 
 DefenseUnit::DefenseUnit(DefenseUnit *inUnit) {
-	m_ID = inUnit->getID();
-	m_pos.x = inUnit->getPosX();
-	m_pos.y = inUnit->getPosY();
-	m_distanceTo = inUnit->getDistanceTo();
-	m_state = inUnit->getState();
-	m_radius = inUnit->getRadius();
-	m_armor = inUnit->getArmor();
+	_id = inUnit->getID();
+	_pos.x = inUnit->getPosX();
+	_pos.y = inUnit->getPosY();
+	_distanceTo = inUnit->getDistanceTo();
+	_state = inUnit->getState();
+	_radius = inUnit->getRadius();
+	_armor = inUnit->getArmor();
 }
 
 DefenseUnit::~DefenseUnit() {
diff --git a/engines/scumm/he/moonbase/ai_defenseunit.h b/engines/scumm/he/moonbase/ai_defenseunit.h
index bc4c79a..e658fc3 100644
--- a/engines/scumm/he/moonbase/ai_defenseunit.h
+++ b/engines/scumm/he/moonbase/ai_defenseunit.h
@@ -45,13 +45,13 @@ enum {
 
 class DefenseUnit {
 private:
-	int m_ID;
-	Common::Point m_pos;
-	int m_distanceTo;
-	int m_state;
-	int m_radius;
-	int m_armor;
-	int m_cost;
+	int _id;
+	Common::Point _pos;
+	int _distanceTo;
+	int _state;
+	int _radius;
+	int _armor;
+	int _cost;
 
 public:
 	DefenseUnit();
@@ -59,26 +59,26 @@ public:
 
 	virtual ~DefenseUnit();
 
-	void setID(int id) { m_ID = id; }
-	void setDistanceTo(int distanceTo) { m_distanceTo = distanceTo; }
-	void setState(int state) { m_state = state; }
-	void setRadius(int radius) { m_radius = radius; }
-	void setArmor(int armor) { m_armor = armor; }
-	void setDamage(int damage) { m_armor -= damage; }
+	void setID(int id) { _id = id; }
+	void setDistanceTo(int distanceTo) { _distanceTo = distanceTo; }
+	void setState(int state) { _state = state; }
+	void setRadius(int radius) { _radius = radius; }
+	void setArmor(int armor) { _armor = armor; }
+	void setDamage(int damage) { _armor -= damage; }
 	void setPos(int x, int y) {
-		m_pos.x = x;
-		m_pos.y = y;
+		_pos.x = x;
+		_pos.y = y;
 	}
-	void setCost(int cost) { m_cost = cost; }
-
-	int getID() const { return m_ID; }
-	int getDistanceTo() const { return m_distanceTo; }
-	int getState() const { return m_state; }
-	int getRadius() const { return m_radius; }
-	int getArmor() const { return m_armor; }
-	int getPosX() const { return m_pos.x; }
-	int getPosY() const { return m_pos.y; }
-	int getCost() const { return m_cost; }
+	void setCost(int cost) { _cost = cost; }
+
+	int getID() const { return _id; }
+	int getDistanceTo() const { return _distanceTo; }
+	int getState() const { return _state; }
+	int getRadius() const { return _radius; }
+	int getArmor() const { return _armor; }
+	int getPosX() const { return _pos.x; }
+	int getPosY() const { return _pos.y; }
+	int getCost() const { return _cost; }
 
 	virtual int getType() const = 0;
 






More information about the Scummvm-git-logs mailing list