Merge pull request #229 from devZoGok/imp-222-p2w-cpu-ai

Imp 222 p2w cpu ai
This commit is contained in:
devZoGok
2026-03-15 18:06:10 +00:00
committed by GitHub
36 changed files with 1164 additions and 509 deletions
+3 -3
View File
@@ -6,18 +6,18 @@ metadata = {
impassibleNodeValue = 65535,
spawnPoints = {
{x = -105.929001, y = -0.110725, z = -404.756104},
{x = 17.326164, y = 0.000046, z = 390.545441},
{x = 17.326164, y = 0.000046, z = 360.545441},
},
choosablePlayers = {
{
units = {
{id = 10, pos = {x = -20.000000, y = 0.000000, z = -20.000000}, rot = {w = 1.000000, x = 0.000000, y = 0.000000, z = 0.000000}},
{id = 10, pos = {x = -105.929001, y = -0.110725, z = -404.756104}, rot = {w = 1.000000, x = 0.000000, y = 0.000000, z = 0.000000}},
},
resourceDeposits = {}
},
{
units = {
{id = UnitId.ACS_TANK, pos = {x = -20.000000, y = 0.000000, z = -20.000000}, rot = {w = 1.000000, x = 0.000000, y = 0.000000, z = 0.000000}},
{id = UnitId.ACS_CYBORG_ENGINEER, pos = {x = -20.215218, y = 0.000000, z = 365.251648}, rot = {w = 1.000000, x = 0.000000, y = 0.000000, z = 0.000000}},
},
resourceDeposits = {}
}
+1 -1
View File
@@ -1 +1 @@
game = {players = {}}
game = {cpuPlayers = {}}
File diff suppressed because it is too large Load Diff
+60 -19
View File
@@ -1,41 +1,82 @@
for i = 1, #game.players do
game.players[i].behaviour = {
for i = 1, #game.cpuPlayers do
player = game.cpuPlayers[i]
player:init()
player.behaviour = {
type = BTNodeType.SEQUENCE,
children = {
{type = BTNodeType.FUNCTION, func = 'buildFort'},
{type = BTNodeType.FUNCTION, func = 'trainEngineers'},
{type = BTNodeType.FUNCTION, func = player.buildLandFactory},
{
type = BTNodeType.FUNCTION,
func = player.buildTaskForces,
args = {
factoryClass = UnitClass.LAND_FACTORY,
taskForceData = {{class = UnitClass.CYBORG_ENGINEER, numUnits = 5}}
}
},
{
type = BTNodeType.PARALLEL,
children = {
{type = BTNodeType.FUNCTION, func = player.buildRefinery},
{
type = BTNodeType.SEQUENCE,
children = {
{type = BTNodeType.FUNCTION, func = 'buildHarvester'},
}
},
{type = BTNodeType.FUNCTION, func = 'buildRefinery'},
{
type = BTNodeType.SEQUENCE,
children = {
{type = BTNodeType.FUNCTION, func = 'buildExtractor'},
{type = BTNodeType.FUNCTION, func = 'startHarvesting'},
{type = BTNodeType.FUNCTION, func = player.buildExtractors},
{
type = BTNodeType.FUNCTION,
func = player.buildTaskForces,
args = {
factoryClass = UnitClass.LAND_FACTORY,
taskForceData = {{class = UnitClass.RESOURCE_ROVER, numUnits = 4}}
}
},
}
}
}
},
{type = BTNodeType.FUNCTION, func = player.startHarvesting},
{
type = BTNodeType.SELECTOR,
children = {
{type = BTNodeType.FUNCTION, func = player.canReachAllSpawnPoints},
{
type = BTNodeType.SEQUENCE,
children = {
{type = BTNodeType.FUNCTION, func = player.buildNavalFactory},
{
type = BTNodeType.FUNCTION,
func = player.buildTaskForces,
args = {factoryClass = UnitClass.NAVAL_FACTORY, taskForceData = player.navalTaskForceData}
},
}
},
}
},
{
type = BTNodeType.PARALLEL,
children = {
{type = BTNodeType.FUNCTION, func = 'buildTaskForces'},
{
type = BTNodeType.PARALLEL,
numMinSuccesses = 2,
children = game.players[i]:generateTaskforceActions()
type = BTNodeType.SEQUENCE,
children = {
{
type = BTNodeType.FUNCTION,
func = player.buildTaskForces,
args = {
factoryClass = UnitClass.LAND_FACTORY,
numTaskForces = player:getNumEmptyTaskForces(),
taskForceData = player.landTaskForceData
}
},
{type = BTNodeType.FUNCTION, func = player.formLandTaskForces},
}
},
{type = BTNodeType.FUNCTION, func = player.buildPointDefenseRing},
}
},
--[[
]]--
{
type = BTNodeType.PARALLEL,
children = player:generateTaskForceActions()
}
}
}
end
+49 -46
View File
@@ -73,26 +73,29 @@ UnitId = {
}
WeaponClass = {DAMAGE = 0, FREEZE = 1}
UnitClass = {
WAR_MECH = 0,
MECH = 0,
TANK = 1,
ARTILLERY = 2,
ENGINEER = 3,
TRANSPORT = 4,
RESOURCE_ROVER = 5,
CRUISER = 6,
CARRIER = 7,
SUBMARINE = 8,
ICEBREAKER = 9,
FREEZER = 10,
EMP_BOAT = 11,
LAND_FACTORY = 12,
NAVAL_FACTORY = 13,
TRADE_CENTER = 14,
LAB = 15,
POINT_DEFENSE = 16,
EXTRACTOR = 17,
REFINERY = 18,
ICE_SHEET = 19,
ROBO_ENGINEER = 3,
CYBORG_ENGINEER = 4,
TRANSPORT = 5,
RESOURCE_ROVER = 6,
CRUISER = 7,
ANTI_SUB_CRUISER = 8,
CARRIER = 9,
SUBMARINE = 10,
MISSILE_SUBMARINE = 11,
ICEBREAKER = 12,
FREEZER = 13,
EMP_BOAT = 14,
LAND_FACTORY = 15,
NAVAL_FACTORY = 16,
TRADE_CENTER = 17,
LAB = 18,
POINT_DEFENSE = 19,
EXTRACTOR = 20,
REFINERY = 21,
ICE_SHEET = 22,
}
UnitType = {UNDERWATER = 0, SEA_LEVEL = 1, HOVER = 2, LAND = 3, AIR = 4}
@@ -169,13 +172,13 @@ units = {
},
}
},
unitClass = UnitClass.WAR_MECH,
unitClass = UnitClass.MECH,
unitType = UnitType.LAND,
armor = {ArmorType.MECHANIC},
maxUnevenness = .5,
isVehicle = true,
health = 500,
buildTime = 1000,
buildTime = 600,
cost = 500,
size = {x = 6, y = 9.22, z = 2.42},
hitboxOffset = {x = 0, y = 4.5, z = 0},
@@ -186,7 +189,7 @@ units = {
albedoPath = 'mech.jpg',
colorNodes = {'WarRobotTemplate.001'},
selectionSfx = PATH .. 'Sounds/Units/WarMechs/selection.ogg',
speed = .3,
speed = .4,
destinationOffset = .1,
anglePrecision = .1,
maxTurnAngle = .1,
@@ -242,7 +245,7 @@ units = {
},
}
},
unitClass = UnitClass.WAR_MECH,
unitClass = UnitClass.MECH,
unitType = UnitType.LAND,
armor = {ArmorType.MECHANIC},
maxUnevenness = .5,
@@ -314,7 +317,7 @@ units = {
},
}
},
unitClass = UnitClass.WAR_MECH,
unitClass = UnitClass.MECH,
unitType = UnitType.LAND,
armor = {ArmorType.MECHANIC},
maxUnevenness = .5,
@@ -343,7 +346,7 @@ units = {
{
orderType = OrderType.ATTACK,
rateOfFire = 1000,
damage = 200,
damage = 900,
maxRange = 50,
maxFireAngle = .1,
nodes = {{name = 'TankASHead', rotationSpeed = .05, vertical = false}, {name = 'barell', rotationSpeed = .05, angleConstraints = {min = 0, max = .349}, vertical = true}},
@@ -389,7 +392,7 @@ units = {
albedoPath = 'tank.jpg',
colorNodes = {'TankASHead'},
selectionSfx = PATH .. 'Sounds/Units/Tanks/selection.ogg',
speed = .4,
speed = .5,
destinationOffset = .1,
anglePrecision = .1,
maxTurnAngle = .1,
@@ -553,7 +556,7 @@ units = {
alignToSurface = true,
isVehicle = true,
health = 500,
buildTime = 1000,
buildTime = 1500,
cost = 500,
size = {x = 9.99, y = 15.4, z = 14.},
hitboxOffset = {x = 0, y = 7.69, z = .71},
@@ -564,7 +567,7 @@ units = {
albedoPath = 'artillery.jpg',
colorNodes = {'Asia_Mech.002'},
selectionSfx = PATH .. 'Sounds/Units/Tanks/selection.ogg',
speed = .3,
speed = .35,
destinationOffset = .1,
anglePrecision = .1,
maxTurnAngle = .1,
@@ -699,7 +702,7 @@ units = {
{id = UnitId.POINT_DEFENSE, buildable = true, trigger = 80},
{id = UnitId.EXTRACTOR, buildable = true, trigger = 69},
},
unitClass = UnitClass.ENGINEER,
unitClass = UnitClass.ROBO_ENGINEER,
unitType = UnitType.HOVER,
armor = {ArmorType.MECHANIC},
maxUnevenness = .5,
@@ -744,7 +747,7 @@ units = {
{id = UnitId.EXTRACTOR, buildable = true, trigger = 69},
},
abilityButtons = {{buttonType = ButtonType.ORDER, name = 'Hack', orderType = OrderType.HACK}},
unitClass = UnitClass.ENGINEER,
unitClass = UnitClass.CYBORG_ENGINEER,
unitType = UnitType.HOVER,
armor = {ArmorType.MECHANIC},
maxUnevenness = .5,
@@ -756,14 +759,14 @@ units = {
cost = 500,
size = {x = 4.95, y = 6.59, z = 4.11},
hitboxOffset = {x = .178, y = 3.27, z = 0},
lineOfSight = 200,
lineOfSight = 400,
name = 'Engineer',
basePath = PATH .. vehiclePrefix .. 'Engineers/',
albedoPath = 'engineer.jpg',
colorNodes = {'Engineer_Asia.001'},
meshPath = 'acsCyborgEngineer.xml',
selectionSfx = PATH .. 'Sounds/Units/Engineers/selection.ogg',
speed = .5,
speed = 1,
destinationOffset = .1,
anglePrecision = .1,
maxTurnAngle = .1,
@@ -780,7 +783,7 @@ units = {
{id = UnitId.POINT_DEFENSE, buildable = true, trigger = 80},
{id = UnitId.EXTRACTOR, buildable = true, trigger = 69},
},
unitClass = UnitClass.ENGINEER,
unitClass = UnitClass.ROBO_ENGINEER,
unitType = UnitType.HOVER,
armor = {ArmorType.MECHANIC},
maxUnevenness = .5,
@@ -825,7 +828,7 @@ units = {
{id = UnitId.EXTRACTOR, buildable = true, trigger = 69},
},
abilityButtons = {{buttonType = ButtonType.ORDER, name = 'Hack', orderType = OrderType.HACK}},
unitClass = UnitClass.ENGINEER,
unitClass = UnitClass.CYBORG_ENGINEER,
unitType = UnitType.HOVER,
armor = {ArmorType.MECHANIC},
maxUnevenness = .5,
@@ -837,7 +840,7 @@ units = {
cost = 500,
size = {x = 3.12, y = 5.31, z = 2.82},
hitboxOffset = {x = 0, y = 2.83, z = .4},
lineOfSight = 200,
lineOfSight = 600,
name = 'Engineer',
basePath = PATH .. vehiclePrefix .. 'Engineers/',
albedoPath = 'engineer.jpg',
@@ -861,7 +864,7 @@ units = {
{id = UnitId.POINT_DEFENSE, buildable = true, trigger = 80},
{id = UnitId.EXTRACTOR, buildable = true, trigger = 69},
},
unitClass = UnitClass.ENGINEER,
unitClass = UnitClass.ROBO_ENGINEER,
unitType = UnitType.HOVER,
armor = {ArmorType.MECHANIC},
maxUnevenness = .5,
@@ -906,7 +909,7 @@ units = {
{id = UnitId.EXTRACTOR, buildable = true, trigger = 69},
},
abilityButtons = {{buttonType = ButtonType.ORDER, name = 'Hack', orderType = OrderType.HACK}},
unitClass = UnitClass.ENGINEER,
unitClass = UnitClass.CYBORG_ENGINEER,
unitType = UnitType.HOVER,
armor = {ArmorType.MECHANIC},
maxUnevenness = .5,
@@ -1013,7 +1016,7 @@ units = {
meshPath = 'acsTransport.xml',
albedoPath = 'transport.jpg',
selectionSfx = PATH .. 'Sounds/Units/Transports/selection.ogg',
speed = .1,
speed = .6,
destinationOffset = .1,
anglePrecision = .1,
maxTurnAngle = .1,
@@ -1219,7 +1222,7 @@ units = {
armor = {ArmorType.CAST},
maxUnevenness = .5,
alignToSurface = true,
capacity = 3000,
capacity = 1000,
loadRate = 1,
loadSpeed = 5,
isVehicle = true,
@@ -1377,7 +1380,7 @@ units = {
meshPath = 'heavyAssaultCruiser.xml',
albedoPath = 'cruiser.jpg',
selectionSfx = PATH .. 'Sounds/Units/Cruisers/selection.ogg',
speed = .1,
speed = .4,
destinationOffset = .1,
anglePrecision = .1,
maxTurnAngle = .1,
@@ -1673,7 +1676,7 @@ units = {
hitFx = {}
},
},
unitClass = UnitClass.CRUISER,
unitClass = UnitClass.ANTI_SUB_CRUISER,
unitType = UnitType.SEA_LEVEL,
armor = {ArmorType.STEEL},
isVehicle = true,
@@ -1689,7 +1692,7 @@ units = {
meshPath = 'acsAntiSubCruiser.xml',
albedoPath = 'cruiser.jpg',
selectionSfx = PATH .. 'Sounds/Units/Cruisers/selection.ogg',
speed = .3,
speed = .6,
destinationOffset = .1,
anglePrecision = .1,
maxTurnAngle = .1,
@@ -1803,7 +1806,7 @@ units = {
},
},
},
unitClass = UnitClass.CRUISER,
unitClass = UnitClass.ANTI_SUB_CRUISER,
unitType = UnitType.SEA_LEVEL,
armor = {ArmorType.STEEL},
isVehicle = true,
@@ -1963,7 +1966,7 @@ units = {
},
},
},
unitClass = UnitClass.CRUISER,
unitClass = UnitClass.ANTI_SUB_CRUISER,
unitType = UnitType.SEA_LEVEL,
armor = {ArmorType.STEEL},
isVehicle = true,
@@ -2016,7 +2019,7 @@ units = {
projectile = {id = ProjectileId.CRUISE_MISSILE, pos = {x = 0, y = 15, z = -3.5}, rot = {w = .707, x = -.707, y = 0, z = 0}}
},
},
unitClass = UnitClass.SUBMARINE,
unitClass = UnitClass.MISSILE_SUBMARINE,
unitType = UnitType.UNDERWATER,
isVehicle = true,
health = 500,
@@ -2068,7 +2071,7 @@ units = {
projectile = {id = ProjectileId.CRUISE_MISSILE, pos = {x = 0, y = 15, z = -3.5}, rot = {w = .707, x = -.707, y = 0, z = 0}}
},
},
unitClass = UnitClass.SUBMARINE,
unitClass = UnitClass.MISSILE_SUBMARINE,
unitType = UnitType.UNDERWATER,
isVehicle = true,
health = 500,
@@ -2120,7 +2123,7 @@ units = {
projectile = {id = ProjectileId.CRUISE_MISSILE, pos = {x = 0, y = 15, z = -3.5}, rot = {w = .707, x = -.707, y = 0, z = 0}}
},
},
unitClass = UnitClass.SUBMARINE,
unitClass = UnitClass.MISSILE_SUBMARINE,
unitType = UnitType.UNDERWATER,
isVehicle = true,
health = 500,
+4 -15
View File
@@ -11,11 +11,11 @@ function generateFactionMusic(factionId)
factionTracks = {}
if factionId == 0 then
factionTracks = americanTracks
elseif factionId == 1 then
factionTracks = europeanTracks
elseif factionId == 2 then
factionTracks = asianTracks
elseif factionId == 1 then
factionTracks = americanTracks
elseif factionId == 2 then
factionTracks = europeanTracks
end
return {
@@ -105,17 +105,6 @@ gui = {
size = {x = s, y = s},
imagePath = resIconBasePath .. 'research.png',
},
{
guiType = GuiType.TEXT,
name = 'depth',
text = '',
pos = {x = 0, y = 400, z = 0},
scale = {x = 0, y = 1},
font = 'batang.ttf',
fontFirstChar = 0,
fontLastChar = 256,
color = {x = 1, y = 1, z = 1, w = 1}
},
{
guiType = GuiType.BUTTON,
buttonType = ButtonType.PLAYER_TRADE,
+1 -1
View File
@@ -4,7 +4,7 @@ Size = {x = 150, y = 20}
gap = 10
gapFactor = 3
factions = {'None', "America inc.", "European Republic", "Asian Co-Prosperity Sphere"}
factions = {'None', 'Asian Co-Prosperity Sphere', 'America inc.', 'European Republic'}
difficulties = {"Easy", "Medium", "Hard"}
colors = {'White', 'Black', 'Red'}
teams = {'0', '1', '2', '3', '4'}
+1 -1
View File
@@ -9,7 +9,7 @@ function executeBtNode(agent, btNode)
if btNode.children[i].type == BTNodeType.FUNCTION then
func = btNode.children[i].func
args = btNode.children[i].args
res = agent[func](agent, args)
res = func(agent, args)
else
res = executeBtNode(agent, btNode.children[i])
end
+15 -71
View File
@@ -252,7 +252,7 @@ namespace battleship{
orderPossible = (roverSelected && transferResource);
}
else if(cursorState == CursorState::HACK)
orderPossible = (!ownGameObj && gameObjUnit && mainPlayer->getSelectedUnit(0)->getUnitClass() == UnitClass::ENGINEER);
orderPossible = (!ownGameObj && gameObjUnit && mainPlayer->getSelectedUnit(0)->getUnitClass() == UnitClass::CYBORG_ENGINEER);
else if(controlPressed)
cursorState = CursorState::ATTACK;
else
@@ -285,7 +285,6 @@ namespace battleship{
void ActiveGameState::update() {
ConcreteGuiManager *guiManager = ConcreteGuiManager::getSingleton();
guiManager->getText("depth")->setText(L"Depth: " + to_wstring(depth));
guiManager->getText("refineds")->setText(to_wstring(mainPlayer->getResource(ResourceType::REFINEDS)));
guiManager->getText("wealth")->setText(to_wstring(mainPlayer->getResource(ResourceType::WEALTH)));
guiManager->getText("research")->setText(to_wstring(mainPlayer->getResource(ResourceType::RESEARCH)));
@@ -312,7 +311,7 @@ namespace battleship{
if(!buildableStructSelected)
for(int i = 0; i < selectedUnits.size(); i++)
fc->addGameObjectFrame(GameObjectFrame(selectedUnits[i]->getId(), GameObject::Type::UNIT, selectedUnits[i], targets[0].pos));
fc->addGameObjectFrame(GameObjectFrame(selectedUnits[i]->getId(), GameObject::Type::UNIT, mainPlayer, selectedUnits[i], targets[0].pos));
selectingDestOrient = true;
fc->setRotating(true);
@@ -477,73 +476,20 @@ namespace battleship{
return (numAboveEdges > 0 && numBelowEdges > 0);
}
//TODO fix fog of war for hostile units
void ActiveGameState::renderUnits() {
ConcreteGuiManager *guiManager = ConcreteGuiManager::getSingleton();
vector<Listbox*> listboxes{};
vector<Checkbox*> checkboxes{};
vector<Slider*> sliders{};
vector<Textbox*> textboxes{};
vector<Node*> guiRects = guiManager->getGuiRectangles();
vector<Text*> texts{
guiManager->getText("depth"),
guiManager->getText("refineds"),
guiManager->getText("wealth"),
guiManager->getText("research")
};
vector<Unit*> friendlyUnits = mainPlayer->getFriendlyUnits();
Game *game = Game::getSingleton();
vector<Unit*> units;
for (Player *p : game->getPlayers(true)){
vector<Unit*> units = p->getUnits();
for (Player *p : Game::getSingleton()->getPlayers(true))
for (Unit *u : p->getUnits())
units.push_back(u);
vector<Unit*> selUnits = mainPlayer->getSelectedUnits();
for (Unit *u : units) {
if(u->isVehicle() && ((Vehicle*)u)->getGarrisonable()) continue;
Node *model = u->getModel();
if (u->getPlayer()->getTeam() == mainPlayer->getTeam()){
if(!u->getLosLightNode()) u->initLosLight();
model->setVisible(true);
}
else{
if(u->getLosLightNode()) u->destroyLosLight();
model->setVisible(false);
for (int i = 0; i < units.size(); i++)
if(units[i]->getPlayer() == mainPlayer){
Vector3 obsUnitPos = units[i]->getPos();
obsUnitPos.y = 0;
Vector3 compUnitPos = u->getPos();
compUnitPos.y = 0;
float dist = compUnitPos.getDistanceFrom(obsUnitPos);
if(dist <= units[i]->getLineOfSight()){
model->setVisible(true);
break;
}
}
for (Unit *u : units) {
if(u->isVehicle() && ((Vehicle*)u)->getGarrisonable()) continue;
bool unitVisible = (game->isDebug() || mainPlayer->isObjectVisible((GameObject*)u, friendlyUnits));
u->getModel()->setVisible(unitVisible);
}
}
}
//TODO improve this for greater accuracy
bool ActiveGameState::isInLineOfSight(Vector3 center, float radius, Unit *u) {
bool inside = false;
for (int i = 0; i < 4 && !inside; i++)
if (center.getDistanceFrom(u->getCorner(i)) <= radius){
inside = true;
break;
}
return inside;
}
}
void ActiveGameState::updateDragBox() {
@@ -723,7 +669,8 @@ namespace battleship{
Order::TYPE type;
switch(selectedUnits[0]->getUnitClass()){
case UnitClass::ENGINEER:
case UnitClass::ROBO_ENGINEER:
case UnitClass::CYBORG_ENGINEER:
case UnitClass::FREEZER:
type = Order::TYPE::BUILD;
break;
@@ -740,7 +687,6 @@ namespace battleship{
Unit *buildStruct = GameObjectFactory::createUnit(mainPlayer, gmObjFr.getId(), gmObjFr.getPos(), gmObjFr.getRot());
issueOrder(type, vector<Order::Target>{Order::Target(buildStruct, gmObjFr.getPos())}, shiftPressed);
mainPlayer->addUnit(buildStruct);
}
buildableStructSelected = false;
@@ -806,9 +752,7 @@ namespace battleship{
CameraController::getSingleton()->setLookingAround(isPressed);
break;
case Bind::HALT:
if(isPressed)
for (Unit *u : mainPlayer->getSelectedUnits())
u->halt();
if(isPressed) mainPlayer->haltUnits();
break;
//TODO reimplement submarine diving mechanic
case Bind::LEFT_CONTROL:
-1
View File
@@ -73,7 +73,6 @@ namespace battleship{
void updateStructureFrames();
void castRayToTerrain();
void issueOrder(Order::TYPE, std::vector<Order::Target>, bool);
bool isInLineOfSight(vb01::Vector3, float, Unit*);
void enableUnitState(Unit::State);
void addUnitGui();
inline bool canSelectHoveredOnGameObj(){return gameObjHoveredOn && gameObjHoveredOn->isSelectable() && gameObjHoveredOn->getPlayer() == mainPlayer;}
+1 -1
View File
@@ -29,7 +29,7 @@ namespace battleship{
if(builder->getBuildableUnit(slotId).buildable){
GameObjectFrameController *ufCtr = GameObjectFrameController::getSingleton();
ufCtr->addGameObjectFrame(GameObjectFrame(builder->getBuildableUnit(slotId).id, GameObject::Type::UNIT));
ufCtr->addGameObjectFrame(GameObjectFrame(builder->getBuildableUnit(slotId).id, GameObject::Type::UNIT, player));
ufCtr->setPlacingOnSurface(true);
activeState->setBuildableStructSelected(true);
}
+1 -2
View File
@@ -45,8 +45,7 @@ namespace battleship{
}
void CameraController::orientCamera(Vector3 rotAxis, double str){
float minStr = .001;
Quaternion rotQuat = Quaternion(.5 * (fabs(str) > minStr ? str : 0), rotAxis);
Quaternion rotQuat = Quaternion(.025 * str, rotAxis);
Camera *cam = Root::getSingleton()->getCamera();
Vector3 dir = rotQuat * cam->getDirection(), up = rotQuat * cam->getUp();
cam->lookAt(dir, up);
+1 -1
View File
@@ -21,7 +21,7 @@ namespace battleship{
const std::string DEFAULT_TEXTURE = "Textures/defaultTexture.jpg";
const double camPanSpeed = .5, CAMERA_DISTANCE = 100, CAMERA_ZOOM_INCREMENT = 1, cellLength = 7, cellWidth = 7, cellDepth = 7, DIST_FROM_RAY = 15;
const int maxNumGroups = 10, NUM_MAX_ZOOMS = 75, NUM_SUBDIVS = 100;
const int maxNumGroups = 10, NUM_MAX_ZOOMS = 300, NUM_SUBDIVS = 100;
const vb01::u32 IMPASS_NODE_VAL = 65535;
const static int numAppStates = 5;
+2 -2
View File
@@ -15,7 +15,7 @@ namespace battleship{
using namespace std;
using namespace gameBase;
Factory::Factory(Player *player, int id, Vector3 pos, Quaternion rot, int buildStatus, Unit::State state) : Structure(player, id, pos, rot, buildStatus, state){}
Factory::Factory(Player *player, int id, Vector3 pos, Quaternion rot, int buildStatus, Unit::State state) : Structure(player, id, pos, rot, buildStatus, state), rallyPoint(pos + 30 * dirVec){}
void Factory::update(){
Structure::update();
@@ -70,7 +70,7 @@ namespace battleship{
if(trainingStatus >= 100){
Unit *unit = GameObjectFactory::createUnit(player, unitQueue[0], pos, rot);
player->addUnit(unit);
unit->receiveOrder(Order(Order::TYPE::MOVE, vector<Order::Target>{Order::Target(nullptr, pos + 30 * dirVec)}, Vector3::VEC_ZERO), false);
unit->receiveOrder(Order(Order::TYPE::MOVE, vector<Order::Target>{Order::Target(nullptr, rallyPoint)}, Vector3::VEC_ZERO), false);
unitQueue.erase(unitQueue.begin());
trainingStatus = 0;
+3
View File
@@ -20,11 +20,14 @@ namespace battleship{
void update();
int getNumQueueUnitsById(int);
void appendToQueue(int);
inline void setRallyPoint(vb01::Vector3 rp){this->rallyPoint = rp;}
inline vb01::Vector3 getRallyPoint(){return rallyPoint;}
inline std::vector<int> getQueue(){return unitQueue;}
private:
std::vector<int> unitQueue;
int maxLenQueue, trainingStatus = 0;
vb01::s64 lastTrainTime = 0;
vb01::Vector3 rallyPoint;
void initProperties();
void train();
+1 -1
View File
@@ -33,7 +33,7 @@ namespace battleship{
Vehicle::build(order);
if(targ->getUnitClass() == UnitClass::ICE_SHEET && ((Structure*)targ)->getBuildStatus() >= 100)
if(targ->getUnitClass() == UnitClass::ICE_SHEET && ((Structure*)targ)->isComplete())
removeOrder(0);
}
}
+22 -13
View File
@@ -6,6 +6,7 @@
#include "inGameAppState.h"
#include "concreteGuiManager.h"
#include "fxManager.h"
#include "factory.h"
#include "defConfigs.h"
#include <algorithm>
@@ -43,14 +44,12 @@ namespace battleship{
}
void Game::update(){
updateLuaPlayers(false);
sol::state_view SOL_LUA_VIEW = generateView();
for(int i = 0; i < players.size(); i++)
if(players[i]->isCpuPlayer()){
string plStr = "game.players[" + to_string(i + 1) + "]";
SOL_LUA_VIEW.script("executeBtNode(" + plStr + ", " + plStr + ".behaviour)");
}
for(int i = 0; i < getCpuPlayers().size(); i++) {
string plStr = "game.cpuPlayers[" + to_string(i + 1) + "]";
SOL_LUA_VIEW.script("executeBtNode(" + plStr + ", " + plStr + ".behaviour)");
}
int numPlayersWithUnits = 0;
@@ -76,18 +75,18 @@ namespace battleship{
FxManager::getSingleton()->update();
}
void Game::updateLuaPlayers(bool resetBehaviour){
void Game::initLuaPlayers(){
sol::state_view SOL_LUA_VIEW = generateView();
vector<Player*> cpuPlayers = getCpuPlayers();
for(int i = 0; i < players.size(); i++)
SOL_LUA_VIEW["game"]["players"][i + 1] = players[i];
for(int i = 0; i < cpuPlayers.size(); i++)
SOL_LUA_VIEW["game"]["cpuPlayers"][i + 1] = cpuPlayers[i];
if(resetBehaviour)
SOL_LUA_VIEW.script_file(GameManager::getSingleton()->getPath() + "Scripts/Core/playerInit.lua");
SOL_LUA_VIEW.script_file(GameManager::getSingleton()->getPath() + "Scripts/Core/playerInit.lua");
}
void Game::removeAllElements(){
generateView().script("game.players = {}");
generateView().script("game.cpuPlayers = {}");
while(!players.empty()){
delete players[0];
@@ -113,7 +112,7 @@ namespace battleship{
for(string f : configData::scripts)
SOL_LUA_VIEW.script_file(gm->getPath() + f);
updateLuaPlayers(true);
initLuaPlayers();
guiManager->readLuaScreenScript("inGame.lua", activeState->getGuiButtons());
string gop = SOL_LUA_VIEW["gameObjPrefix"], vfxp = SOL_LUA_VIEW["vfxPrefix"];
@@ -233,4 +232,14 @@ namespace battleship{
return playersVec;
}
vector<Player*> Game::getCpuPlayers(){
vector<Player*> playersVec;
for(Player *pl : players)
if(pl->isCpuPlayer())
playersVec.push_back(pl);
return playersVec;
}
}
+2 -1
View File
@@ -20,13 +20,14 @@ namespace battleship{
public:
static Game* getSingleton();
void update();
void updateLuaPlayers(bool);
void initLuaPlayers();
void togglePause();
void removeAllElements();
void initTechnologies();
float calcAbilFromTech(Ability::Type, std::vector<int>, int, int);
bool isUnitUnlocked(std::vector<int>, int);
std::vector<Player*> getPlayers(bool = false);
std::vector<Player*> getCpuPlayers();
inline void setDebug(bool d){this->debug = d;}
inline void addPlayer(Player *pl){players.push_back(pl);}
inline bool isDebug(){return debug;}
+86 -8
View File
@@ -8,16 +8,20 @@
#include <root.h>
#include "gameManager.h"
#include "gameObjectFrameController.h"
#include "gameObjectFactory.h"
#include "map.h"
#include "game.h"
#include "guiAppState.h"
#include "defConfigs.h"
#include "player.h"
#include "extractor.h"
#include "factory.h"
#include "vehicle.h"
#include "engineer.h"
#include "destructable.h"
#include "pointDefense.h"
#include "pathfinder.h"
#include "resourceDeposit.h"
using namespace std;
@@ -56,23 +60,42 @@ namespace battleship{
"createResourceDeposit", &GameObjectFactory::createResourceDeposit
);
SOL_LUA_STATE.new_usertype<Unit::GarrisonSlot>(
"GarrisonSlot",
"vehicle", &Unit::GarrisonSlot::vehicle,
"category", &Unit::GarrisonSlot::category
);
SOL_LUA_STATE.new_usertype<Unit>(
"Unit", sol::constructors<Unit(Player*, int, Vector3, Quaternion)>(),
"setState", &Unit::setState,
"getDestructable", &Unit::getDestructable,
"getGarrisonSlots", &Unit::getGarrisonSlots,
"getNumFreeGarrisonSlots", &Unit::getNumFreeGarrisonSlots,
"getNumGarrisonSlots", &Unit::getNumGarrisonSlots,
"isGarrisonEmpty", &Unit::isGarrisonEmpty,
"getOrder", &Unit::getOrder,
"getNumOrders", &Unit::getNumOrders,
"getDirVec", &GameObject::getDirVec,
"getLeftVec", &GameObject::getLeftVec,
"getPos", &GameObject::getPos,
"getUnitClass", &Unit::getUnitClass,
"getLineOfSight", &Unit::getLineOfSight,
"toEngineer", &Unit::toEngineer,
"toPointDefense", &Unit::toPointDefense,
"toStructure", &Unit::toStructure,
"toFactory", &Unit::toFactory,
"toGameObject", &Unit::toGameObject,
"getBuildableUnit", &Unit::getBuildableUnit,
"getBuildableUnits", &Unit::getBuildableUnits,
"getNumBuildableUnits", &Unit::getNumBuildableUnits
"getNumBuildableUnits", &Unit::getNumBuildableUnits,
"toGameObject", [](Unit *u){return (GameObject*)u;},
"toVehicle", [](Unit *u){return (Vehicle*)u;},
"toEngineer", [](Unit *u){return (Engineer*)u;},
"toStructure", [](Unit *u){return (Structure*)u;},
"toFactory", [](Unit *u){return (Factory*)u;},
"toExtractor", [](Unit *u){return (Extractor*)u;},
"toPointDefense", [](Unit *u){return (PointDefense*)u;}
);
SOL_LUA_STATE.new_usertype<Vehicle>(
"Engineer", sol::constructors<Vehicle(Player*, int, Vector3, Quaternion, Unit::State)>(),
"getGarrisonable", &Vehicle::getGarrisonable
);
SOL_LUA_STATE.new_usertype<Engineer>(
@@ -85,6 +108,7 @@ namespace battleship{
SOL_LUA_STATE.new_usertype<Structure>(
"Structure", sol::constructors<Structure(Player*, int, Vector3, Quaternion, int)>(),
"getPos", &GameObject::getPos,
"isComplete", &Structure::isComplete,
"getBuildStatus", &Structure::getBuildStatus
);
@@ -99,16 +123,21 @@ namespace battleship{
"getBuildableUnit", &Unit::getBuildableUnit,
"getBuildableUnits", &Unit::getBuildableUnits,
"getNumBuildableUnits", &Unit::getNumBuildableUnits,
"getDirVec", &GameObject::getDirVec,
"getLeftVec", &GameObject::getLeftVec,
"getPos", &GameObject::getPos,
"appendToQueue", &Factory::appendToQueue,
"getBuildStatus", &Structure::getBuildStatus,
"getNumQueueUnitsById", &Factory::getNumQueueUnitsById,
"getRallyPoint", &Factory::getRallyPoint,
"setRallyPoint", &Factory::setRallyPoint,
"getQueue", &Factory::getQueue
);
SOL_LUA_STATE.new_usertype<Player>(
"Player", sol::constructors<Player(int, int, int, Vector3, bool, int, string)>(),
"getSelectedUnits", &Player::getSelectedUnits,
"haltUnits", &Player::haltUnits,
"addUnit", &Player::addUnit,
"getUnit", &Player::getUnit,
"getNumUnits", &Player::getNumUnits,
@@ -120,13 +149,24 @@ namespace battleship{
"getFaction", &Player::getFaction,
"getTeam", &Player::getTeam,
"getUnits", &Player::getUnits,
"getHostileUnits", &Player::getHostileUnits,
"getFriendlyUnits", &Player::getFriendlyUnits,
"getUnitsById", &Player::getUnitsById,
"getUnitsByClass", &Player::getUnitsByClass
"getUnitsByClass", &Player::getUnitsByClass,
"isObjectVisible", &Player::isObjectVisible
);
SOL_LUA_STATE.new_usertype<Extractor>(
"Extractor", sol::constructors<Extractor(Player*, int, Vector3, Quaternion, int, ResourceDeposit*, Unit::State)>(),
"getDeposit", &Extractor::getDeposit
);
SOL_LUA_STATE.new_usertype<ResourceDeposit>(
"ResourceDeposit", sol::constructors<ResourceDeposit(Player*, int, Vector3, Quaternion, int)>(),
"getPos", &GameObject::getPos
"getExtractor", &ResourceDeposit::getExtractor,
"getAmmount", &ResourceDeposit::getAmmount,
"getPos", &GameObject::getPos,
"toGameObject", [](ResourceDeposit *rd){return (GameObject*)rd;}
);
SOL_LUA_STATE.new_usertype<Game>(
@@ -143,6 +183,7 @@ namespace battleship{
"norm", &Vector3::norm,
"getAngleBetween", &Vector3::getAngleBetween,
"getDistanceFrom", &Vector3::getDistanceFrom,
"neg", [](Vector3 v){return -v;},
"add", [](Vector3 v1, Vector3 v2){return v1 + v2;},
"subtr", [](Vector3 v1, Vector3 v2){return v1 - v2;},
"mult", [](Vector3 v1, float s){return v1 * s;},
@@ -155,15 +196,52 @@ namespace battleship{
"x", &Quaternion::x,
"y", &Quaternion::y,
"z", &Quaternion::z,
"getAngle", &Quaternion::getAngle,
"getAxis", &Quaternion::getAxis,
"multVec", [](Quaternion q, Vector3 v){return q * v;}
);
SOL_LUA_STATE.new_usertype<Map::Cell>(
"Cell",
"pos", &Map::Cell::pos,
"type", &Map::Cell::type
);
SOL_LUA_STATE.new_usertype<Map>(
"Map",
"getSingleton", &Map::getSingleton,
"getCell", &Map::getCell,
"getCells", &Map::getCells,
"getCellId", &Map::getCellId,
"getMapSize", &Map::getMapSize,
"getSpawnPoint", &Map::getSpawnPoint,
"getNumSpawnPoints", &Map::getNumSpawnPoints
);
SOL_LUA_STATE.new_usertype<Pathfinder>(
"Pathfinder",
"getSingleton", &Pathfinder::getSingleton,
"calcHeuristics", &Pathfinder::calcHeuristics,
"findPath", &Pathfinder::findPath
);
SOL_LUA_STATE.new_usertype<GameObjectFrame>(
"GameObjectFrame", sol::constructors<GameObjectFrame(int, GameObject::Type, Player*, Unit*, Vector3, Quaternion)>(),
"getOriginalUnit", &GameObjectFrame::getOriginalUnit,
"destroy", &GameObjectFrame::destroy,
"placeAt", &GameObjectFrame::placeAt,
"getDirVec", &GameObjectFrame::getDirVec,
"getLeftVec", &GameObjectFrame::getLeftVec,
"getLength", &GameObjectFrame::getLength,
"getWidth", &GameObjectFrame::getWidth,
"status", &GameObjectFrame::status
);
SOL_LUA_STATE.new_usertype<GameObjectFrameController>(
"GameObjectFrameController",
"getSingleton", &GameObjectFrameController::getSingleton,
"checkPlacement", &GameObjectFrameController::checkPlacement
);
}
void GameManager::initLua(string gameDir){
+1 -1
View File
@@ -153,7 +153,7 @@ namespace battleship{
model->setMaterial(mat);
sol::optional<sol::table> colNodeOpt = gameObjTable["colorNodes"];
if(player && colNodeOpt != sol::nullopt)
if(!(model->isWireframe() || colNodeOpt == sol::nullopt))
useColor(player->getColorMaterial());
root->getRootNode()->attachChild(model);
+3 -2
View File
@@ -34,11 +34,13 @@ namespace battleship{
if(vehicle)
switch((UnitClass)unitClass){
case UnitClass::ENGINEER:
case UnitClass::ROBO_ENGINEER:
case UnitClass::CYBORG_ENGINEER:
return new Engineer(player, id, pos, rot, Unit::State::STAND_GROUND);
case UnitClass::RESOURCE_ROVER:
return new ResourceRover(player, id, pos, rot, Unit::State::STAND_GROUND);
case UnitClass::SUBMARINE:
case UnitClass::MISSILE_SUBMARINE:
return new Submarine(player, id, pos, rot, Unit::State::STAND_GROUND);
case UnitClass::FREEZER:
return new Freezer(player, id, pos, rot, Unit::State::STAND_GROUND);
@@ -47,7 +49,6 @@ namespace battleship{
}
else
switch((UnitClass)unitClass){
case UnitClass::FORT:
case UnitClass::LAND_FACTORY:
case UnitClass::NAVAL_FACTORY:
return new Factory(player, id, pos, rot, buildStatus, Unit::State::STAND_GROUND);
+2 -2
View File
@@ -10,9 +10,9 @@ namespace battleship{
struct GameObjectFrame : public GameObject{
enum Status{PLACEABLE, NOT_PLACEABLE, PLACED};
GameObjectFrame(int i, GameObject::Type t, Unit *ou = nullptr, vb01::Vector3 pos = vb01::Vector3::VEC_ZERO, vb01::Quaternion rot = vb01::Quaternion::QUAT_W) :
GameObjectFrame(int i, GameObject::Type t, Player *pl, Unit *ou = nullptr, vb01::Vector3 pos = vb01::Vector3::VEC_ZERO, vb01::Quaternion rot = vb01::Quaternion::QUAT_W) :
originalUnit(ou),
GameObject(t, i, nullptr, pos, rot)
GameObject(t, i, pl, pos, rot)
{
initModel(false);
initProperties();
+48 -6
View File
@@ -54,7 +54,7 @@ namespace battleship{
buildDir = gameObjectFrames[1].getModel()->getPosition() - gameObjectFrames[0].getModel()->getPosition();
Vector3 pos = paintSelectRowStart + buildDir.norm() * hypothenuse * gameObjectFrames.size();
addGameObjectFrame(GameObjectFrame(structureId, GameObject::Type::UNIT, nullptr, pos));
addGameObjectFrame(GameObjectFrame(structureId, GameObject::Type::UNIT, gameObjectFrames[0].getPlayer(), nullptr, pos));
}
}
@@ -73,15 +73,57 @@ namespace battleship{
}
}
//TODO fix which unit frames light green or red
//TODO include checking if frame is outside of line of sight
void GameObjectFrameController::checkPlacement(GameObjectFrame &s){
s.status = GameObjectFrame::PLACEABLE;
Map *map = Map::getSingleton();
Vector3 mapSize = map->getMapSize();
Vector3 cellSize = map->getCellSize();
int dirMult[][2]{{1, 1}, {1, -1}, {-1, 1}, {-1, -1}};
vector<Map::Cell> &cells = map->getCells();
sol::table tbl = generateView()["units"][s.getId() + 1];
UnitType ut = (UnitType)tbl["unitType"];
vector<Unit*> friendlyUnits = (s.getPlayer() ? s.getPlayer()->getFriendlyUnits() : vector<Unit*>{});
bool withinLos = false;
for(int i = 0; i < 4; i++){
Vector3 cornerPos = (s.getPos() + s.getDirVec() * .5 * dirMult[i][0] * s.getLength() + s.getLeftVec() * .5 * dirMult[i][1] * s.getWidth());
if(!(fabs(cornerPos.x) <= .5 * mapSize.x && fabs(cornerPos.z) <= .5 * mapSize.z)){
s.status = GameObjectFrame::NOT_PLACEABLE;
return;
}
Map::Cell cell = cells[map->getCellId(cornerPos, false)];
bool landUnitOnWater = (ut == UnitType::LAND && cell.type == Map::Cell::Type::WATER);
bool waterUnitOnLand = ((ut == UnitType::SEA_LEVEL || ut == UnitType::UNDERWATER) && cell.type == Map::Cell::Type::LAND);
bool withinCell = (fabs(cell.pos.x - cornerPos.x) < .5 * cellSize.x && fabs(cell.pos.z - cornerPos.z) < .5 * cellSize.z);
if((landUnitOnWater || waterUnitOnLand) && withinCell){
s.status = GameObjectFrame::NOT_PLACEABLE;
return;
}
if(!withinLos)
for(Unit *fu : friendlyUnits)
if(fu->getPos().getDistanceFrom(s.getPos()) < fu->getLineOfSight()){
withinLos = true;
break;
}
}
if(!withinLos){
s.status = GameObjectFrame::NOT_PLACEABLE;
return;
}
MeshData meshData = map->getNodeParent()->getChild(0)->getMesh(0)->getMeshBase();
MeshData::Vertex *verts = meshData.vertices;
int numVerts = 3 * meshData.numTris;
s.status = GameObjectFrame::PLACEABLE;
if(s.getMaxUnevenness() > 0)
for(int i = 0; i < numVerts; i++){
float diffX = fabs(s.getPos().x - verts[i].pos->x);
@@ -90,7 +132,7 @@ namespace battleship{
if(diffX < 0.5 * s.getWidth() && diffZ < 0.5 * s.getLength() && diffY > s.getMaxUnevenness()){
s.status = GameObjectFrame::NOT_PLACEABLE;
break;
return;
}
}
@@ -132,7 +174,7 @@ namespace battleship{
if(intersects){
s.status = GameObjectFrame::NOT_PLACEABLE;
break;
return;
}
}
}
+1 -1
View File
@@ -18,7 +18,7 @@ namespace battleship{
void GameObjectListbox::onClose(){
GameObjectFrameController *ufCtr = GameObjectFrameController::getSingleton();
GameObject::Type type = (unitListbox ? GameObject::Type::UNIT : GameObject::Type::RESOURCE_DEPOSIT);
ufCtr->addGameObjectFrame(GameObjectFrame(gameObjIds[selectedOption], type));
ufCtr->addGameObjectFrame(GameObjectFrame(gameObjIds[selectedOption], type, nullptr));
ufCtr->setPlacingOnSurface(true);
}
}
+2 -2
View File
@@ -74,8 +74,8 @@ namespace battleship{
activeState = new ActiveGameState(guiState, playerId);
stateManager->attachAppState(activeState);
Game::getSingleton()->updateLuaPlayers(true);
Map::Minimap::getSingleton()->updateImage();
Game::getSingleton()->initLuaPlayers();
//Map::Minimap::getSingleton()->updateImage();
}
void InGameAppState::onDettached() {
+2 -3
View File
@@ -747,9 +747,8 @@ namespace battleship{
return cellId;
}
return cellId;
}
else
return surfaceCellId;
}
else return surfaceCellId;
}
}
+1
View File
@@ -83,6 +83,7 @@ namespace battleship{
std::vector<int> getSurroundingCells(vb01::Vector3, int);
void blockCells(Unit*);
void unblockCells(Unit*);
inline Map::Cell getCell(int i){return cells[i];}
inline std::string getMapName(){return mapName;}
inline vb01::Node* getNodeParent(){return terrainNode;}
inline vb01::Vector3 getCellSize(){return CELL_SIZE;}
+12
View File
@@ -16,7 +16,19 @@ namespace battleship{
return pathfinder;
}
vector<float> Pathfinder::calcHeuristics(vector<Map::Cell> &cells, int dest){
vector<float> heuristics;
for(Map::Cell &cell : cells)
heuristics.push_back(145 * (cells[dest].pos.getDistanceFrom(cell.pos)));
return heuristics;
}
vector<int> Pathfinder::findPath(vector<Map::Cell> &cells, vector<float> &heuristics, int source, int dest, Vehicle *vehicle){
if(heuristics.empty() || (heuristics.size() == 1 && heuristics[0] == 0.0))
heuristics = calcHeuristics(cells, dest);
const int size = cells.size();
u32 *distances = new u32[size];
vector<int> *paths = new vector<int>[size];
+1
View File
@@ -13,6 +13,7 @@ namespace battleship{
class Pathfinder{
public:
static Pathfinder* getSingleton();
std::vector<float> calcHeuristics(std::vector<Map::Cell>&, int);
std::vector<int> findPath(std::vector<Map::Cell>&, std::vector<float>&, int, int, Vehicle* = nullptr);
inline vb01::u32 getImpassibleNodeVal(){return impassibleNodeVal;}
inline void setImpassibleNodeVal(vb01::u32 val){this->impassibleNodeVal = val;}
+72 -3
View File
@@ -4,6 +4,7 @@
#include "player.h"
#include "game.h"
#include "structure.h"
#include "vehicle.h"
#include "projectile.h"
#include "tradeOffer.h"
#include "destructable.h"
@@ -71,6 +72,11 @@ namespace battleship{
}
}
void Player::haltUnits(){
for (Unit *u : selectedUnits)
u->halt();
}
int Player::getOrderLineId(Order::TYPE type, Vector3 startPos, Vector3 endPos){
Vector3 color;
@@ -116,7 +122,7 @@ namespace battleship{
break;
}
if(!u->isVehicle() && ((Structure*)u)->getBuildStatus() < 100){
if(!u->isVehicle() && ((Structure*)u)->isComplete()){
structBuilt = false;
break;
}
@@ -148,6 +154,12 @@ namespace battleship{
delete units[id];
units.erase(units.begin() + id);
if(cpuPlayer){
sol::state_view SOL_LUA_VIEW = generateView();
int id = getCpuPlayerId() + 1;
SOL_LUA_VIEW.script("game.cpuPlayers[" + to_string(id) + "]:updateTaskForces()");
}
}
void Player::removeResourceDeposit(int id){
@@ -169,11 +181,15 @@ namespace battleship{
}
void Player::selectUnits(vector<Unit*> selUnits){
for(Unit *u : selUnits)
if(find(selectedUnits.begin(), selectedUnits.end(), u) == selectedUnits.end()){
for(Unit *u : selUnits){
bool garrisonable = (!u->isVehicle() || (u->isVehicle() && !((Vehicle*)u)->getGarrisonable()));
bool selected = (find(selectedUnits.begin(), selectedUnits.end(), u) != selectedUnits.end());
if(garrisonable && !selected){
selectedUnits.push_back(u);
u->select();
}
}
}
vector<Unit*> Player::getUnitsById(int id, int numUnits){
@@ -286,4 +302,57 @@ namespace battleship{
}
}
}
vector<Unit*> Player::getFriendlyUnits(bool includeOwn){
vector<Unit*> friendlyUnits;
for (Player *pl : Game::getSingleton()->getPlayers(true))
for (Unit *u : pl->getUnits())
if((includeOwn && pl == this) || pl->getTeam() == getTeam())
friendlyUnits.push_back(u);
return friendlyUnits;
}
vector<Unit*> Player::getHostileUnits(){
vector<Unit*> hostileUnits, friendlyUnits = getFriendlyUnits(true);
for (Player *pl : Game::getSingleton()->getPlayers(true))
for (Unit *u : pl->getUnits())
if(pl->getTeam() != getTeam() && isObjectVisible(u, friendlyUnits))
hostileUnits.push_back(u);
return hostileUnits;
}
//TODO improve this for greater accuracy
bool Player::isObjectVisible(GameObject *object, std::vector<Unit*> friendlyUnits) {
Player *objPlayer = object->getPlayer();
for(Unit *friendlyUnit : friendlyUnits){
if(objPlayer == this || objPlayer->getTeam() == getTeam())
return true;
Vector3 obsUnitPos = object->getPos();
Vector2 oup2d = Vector2(obsUnitPos.x, obsUnitPos.z);
Vector3 compUnitPos = friendlyUnit->getPos();
Vector2 cup2d = Vector2(compUnitPos.x, compUnitPos.z);
if(cup2d.getDistanceFrom(oup2d) <= friendlyUnit->getLineOfSight())
return true;
}
return false;
}
int Player::getCpuPlayerId(){
vector<Player*> cpuPlayers = Game::getSingleton()->getCpuPlayers();
for(int i = 0; i < cpuPlayers.size(); i++)
if(cpuPlayers[i] == this)
return i;
return -1;
}
}
+5
View File
@@ -22,6 +22,7 @@ namespace battleship{
Player(int, int, int, vb01::Vector3, bool = true, int = -1, std::string = "");
~Player();
void update();
void haltUnits();
void issueOrder(Order::TYPE, vb01::Vector3, std::vector<Order::Target>, bool);
void removeUnit(Unit*);
void removeUnit(int);
@@ -39,6 +40,10 @@ namespace battleship{
void deselectUnit(Unit*);
std::vector<GameObject*> getDestructables();
void updateGameStats(Unit*);
std::vector<Unit*> getFriendlyUnits(bool = true);
std::vector<Unit*> getHostileUnits();
bool isObjectVisible(GameObject*, std::vector<Unit*>);
int getCpuPlayerId();
inline int getResource(ResourceType rt){return resources[(int)rt];}
inline void updateResource(ResourceType rt, int amount, bool add){resources[(int)rt] = (add ? resources[(int)rt] + amount : amount);}
inline Trader* getTrader(){return trader;}
+1 -1
View File
@@ -31,7 +31,7 @@ namespace battleship{
vector<Player*> selectingPlayers = getSelectingPlayers();
bool mainPlayerSelecting = (activeState && find(selectingPlayers.begin(), selectingPlayers.end(), mainPlayer) != selectingPlayers.end());
if(buildStatus < 100)
if(!isComplete())
destructable->displayStats(buildStatusForeground, buildStatusBackground, buildStatus, 100, mainPlayer == player && mainPlayerSelecting, Vector2(0, -10));
else{
buildStatusBackground->setVisible(false);
+31 -4
View File
@@ -171,6 +171,15 @@ namespace battleship{
delete losLightNode;
losLightNode = nullptr;
}
int Unit::getNumFreeGarrisonSlots(){
int numFreeSlots = 0;
for(GarrisonSlot &slot : garrisonSlots)
if(!slot.vehicle) numFreeSlots++;
return numFreeSlots;
}
void Unit::destroySound(){
selectionSfx->stop();
@@ -297,6 +306,20 @@ namespace battleship{
if(!currOrderStarted) startCurrentOrder();
if(!orders[0].targets.empty() && orders[0].targets[0].unit){
vector<Unit*> units;
for(Player *pl : Game::getSingleton()->getPlayers(true)){
vector<Unit*> us = pl->getUnits();
units.insert(units.end(), us.begin(), us.end());
}
if(find(units.begin(), units.end(), orders[0].targets[0].unit) == units.end()){
removeOrder(0);
return;
}
}
switch (orders[0].type) {
case Order::TYPE::ATTACK:
attack(orders[0]);
@@ -413,7 +436,7 @@ namespace battleship{
return destructTarg && !getWeaponsByOrder(Order::TYPE::ATTACK).empty();
}
case Order::TYPE::BUILD:
return (unitClass == UnitClass::ENGINEER || unitClass == UnitClass::FREEZER);
return (unitClass == UnitClass::ROBO_ENGINEER || unitClass == UnitClass::CYBORG_ENGINEER || unitClass == UnitClass::FREEZER);
case Order::TYPE::PATROL:
case Order::TYPE::MOVE:
return vehicle;
@@ -465,6 +488,11 @@ namespace battleship{
}
orders.push_back(order);
if(order.type == Order::TYPE::BUILD && order.targets[0].unit)
player->addUnit((Unit*)order.targets[0].unit);
executeOrders();
}
void Unit::halt() {
@@ -490,7 +518,7 @@ namespace battleship{
Map *map = Map::getSingleton();
if(alignToSurface){
vector<RayCaster::CollisionResult> res = RayCaster::cast(Vector3(p.x, 100, p.z), -Vector3::VEC_J, map->getNodeParent()->getChildren(), 0, 20);
vector<RayCaster::CollisionResult> res = map->raycastTerrain(Vector3(p.x, 100, p.z), -Vector3::VEC_J, true);
if(res.empty() || res[0].mesh->getNode() != map->getNodeParent()->getChild(0))
model->lookAt(Vector3(dirVec.x, 0, dirVec.z).norm(), Vector3::VEC_J);
@@ -511,8 +539,7 @@ namespace battleship{
if(activeState){
map->blockCells(this);
if(activeState->getPlayer())
Map::Minimap::getSingleton()->updateImage();
//if(activeState->getPlayer()) Map::Minimap::getSingleton()->updateImage();
}
}
+9 -17
View File
@@ -28,15 +28,9 @@ namespace vb01{
namespace battleship{
class Player;
class Weapon;
class Unit;
class Vehicle;
class Structure;
class Factory;
class Cruiser;
class Engineer;
class PointDefense;
class Projectile;
class GameObject;
class Vehicle;
class Projectile;
struct Order {
enum class TYPE {ATTACK, BUILD, MOVE, GARRISON, EJECT, PATROL, LAUNCH, SUPPLY, LOAD, UNLOAD, HACK};
@@ -67,15 +61,18 @@ namespace battleship{
enum class Corner {FRONT_LEFT, FRONT_RIGHT, REAR_LEFT, REAR_RIGHT};
enum class UnitType {UNDERWATER, SEA_LEVEL, HOVER, LAND, AIR, NONE = -1};
enum class UnitClass {
WAR_MECH,
MECH,
TANK,
ARTILLERY,
ENGINEER,
ROBO_ENGINEER,
CYBORG_ENGINEER,
TRANSPORT,
RESOURCE_ROVER,
CRUISER,
ANTI_SUB_CRUISER,
CARRIER,
SUBMARINE,
MISSILE_SUBMARINE,
ICEBREAKER,
FREEZER,
EMP_BOAT,
@@ -86,7 +83,6 @@ namespace battleship{
POINT_DEFENSE,
EXTRACTOR,
REFINERY,
FORT,
ICE_SHEET
};
@@ -116,15 +112,11 @@ namespace battleship{
bool canGarrison(Vehicle*);
void initLosLight();
void destroyLosLight();
int getNumFreeGarrisonSlots();
inline void setState(State s){state = s;}
inline State getState(){return state;}
inline Engineer* toEngineer(){return (Engineer*)this;}
inline Structure* toStructure(){return (Structure*)this;}
inline Factory* toFactory(){return (Factory*)this;}
inline Cruiser* toCruiser(){return (Cruiser*)this;}
inline PointDefense* toPointDefense(){return (PointDefense*)this;}
inline GameObject* toGameObject(){return (GameObject*)this;}
inline int getNumGarrisonSlots(){return garrisonSlots.size();}
inline bool isGarrisonEmpty(){return getNumFreeGarrisonSlots() == getNumGarrisonSlots();}
inline const std::vector<GarrisonSlot>& getGarrisonSlots(){return garrisonSlots;}
inline float getLineOfSight() {return lineOfSight;}
inline UnitType getType() {return type;}
+65 -25
View File
@@ -49,7 +49,11 @@ namespace battleship{
void Vehicle::startCurrentOrder(){
Unit::startCurrentOrder();
if(orders[0].type == Order::TYPE::LAUNCH) return;
switch(orders[0].type){
case Order::TYPE::LAUNCH:
case Order::TYPE::EJECT:
return;
}
removeAllPathpoints();
@@ -234,6 +238,8 @@ namespace battleship{
}
void Vehicle::navigate(float destOffset){
if(pathPoints.empty()) return;
Vector3 hypVec = (pathPoints[0] - pos);
Vector3 baseDir = getVecToPlane(pos, hypVec, upVec);
float angle = baseDir.getAngleBetween(dirVec);
@@ -249,8 +255,7 @@ namespace battleship{
void Vehicle::move(Order order) {
navigate(0.5 * Map::getSingleton()->getCellSize().x);
if(pathPoints.empty())
removeOrder(0);
if(pathPoints.empty()) removeOrder(0);
}
void Vehicle::exitGarrisonable(Vector3 exitPos){
@@ -316,41 +321,55 @@ namespace battleship{
//TODO allow ships to attack land targets and vice versa
//TODO recursively search for vacant dest cell neibourghss
void Vehicle::preparePathpoints(Order &order, Vector3 destPos, bool appendDestPos){
removeAllPathpoints();
bool Vehicle::canReachTarget(Vector3 destPos, int &source, int &dest){
Map *map = Map::getSingleton();
vector<Map::Cell> &cells = map->getCells();
int source = map->getCellId(pos);
source = map->getCellId(pos);
bool ship = (type == UnitType::UNDERWATER || type == UnitType::SEA_LEVEL);
bool waterVehCanMove = (ship && cells[source].type == Map::Cell::WATER);
bool landVehCanMove = (type == UnitType::LAND && cells[source].type == Map::Cell::LAND);
if(type != UnitType::HOVER && !(waterVehCanMove || landVehCanMove)) return;
if(type != UnitType::HOVER && !(waterVehCanMove || landVehCanMove)) return false;
int dest = map->getCellId(destPos);
dest = map->getCellId(destPos);
if(type != UnitType::UNDERWATER && type == UnitType::SEA_LEVEL && fabs(destPos.y - cells[dest].pos.y) > .1) return;
if(type != UnitType::UNDERWATER && type == UnitType::SEA_LEVEL && fabs(destPos.y - cells[dest].pos.y) > .1) return false;
if(cells[dest].blockedBy){
vector<int> surrCellIds = map->getSurroundingCells(cells[dest].pos, 1);
for(int scid : surrCellIds)
if(!cells[scid].blockedBy){
dest = scid;
break;
}
for(int scid : surrCellIds){
if(!cells[scid].blockedBy)
switch(type){
case UnitType::HOVER:
dest = scid;
return true;
case UnitType::LAND:
if(cells[scid].type == Map::Cell::LAND){
dest = scid;
return true;
}
break;
case UnitType::SEA_LEVEL:
case UnitType::UNDERWATER:
if(cells[scid].type == Map::Cell::WATER){
dest = scid;
return true;
}
break;
}
}
return false;
}
else return true;
}
vector<float> heuristics;
for(Map::Cell &cell : cells)
heuristics.push_back(145 * (cells[dest].pos.getDistanceFrom(cell.pos)));
vector<int> path = Pathfinder::getSingleton()->findPath(cells, heuristics, source, dest, this);
path.erase(path.begin());
bool Vehicle::truncatePath(Order &order, vector<int> &path, Vector3 destPos, bool appendDestPos){
bool pathTruncated = false;
bool ship = (type == UnitType::UNDERWATER || type == UnitType::SEA_LEVEL);
vector<Map::Cell> &cells = Map::getSingleton()->getCells();
for(int i = 0; i < path.size(); i++){
if((ship && cells[path[i]].type != Map::Cell::WATER) || (order.type != Order::TYPE::GARRISON && type == UnitType::LAND && cells[path[i]].type != Map::Cell::LAND)){
@@ -361,7 +380,7 @@ namespace battleship{
break;
}
else if(order.type == Order::TYPE::GARRISON && type == UnitType::LAND && cells[path[i]].type != Map::Cell::LAND && path.size() - 1 != i)
return;
return false;
}
for(int p : path) addPathpoint(cells[p].pos);
@@ -410,6 +429,27 @@ namespace battleship{
if(appendDestPos && !pathTruncated)
addPathpoint(destPos);
return true;
}
void Vehicle::preparePathpoints(Order &order, Vector3 destPos, bool appendDestPos){
removeAllPathpoints();
vector<Map::Cell> &cells = Map::getSingleton()->getCells();
int source, dest;
if(!canReachTarget(destPos, source, dest)) return;
vector<float> heurs;
Pathfinder *pf = Pathfinder::getSingleton();
vector<int> path = pf->findPath(cells, heurs, source, dest, this);
if(path.empty()) return;
path.erase(path.begin());
if(!truncatePath(order, path, destPos, appendDestPos)) return;
}
void Vehicle::removePathpoint(int i){
@@ -470,12 +510,12 @@ namespace battleship{
sol::table targTable = generateView()["units"][structure->getId()];
int costRate = (int)targTable["cost"] / 100, buildRate = (int)targTable["buildTime"] / 100;
if(structure->getBuildStatus() < 100 && player->getResource(ResourceType::REFINEDS) >= costRate && getTime() - lastBuildTime > buildRate){
if(!structure->isComplete() && player->getResource(ResourceType::REFINEDS) >= costRate && getTime() - lastBuildTime > buildRate){
structure->incrementBuildStatus();
player->updateResource(ResourceType::REFINEDS, -costRate, true);
lastBuildTime = getTime();
}
else if(structure->getBuildStatus() >= 100){
else if(structure->isComplete()){
removeOrder(0);
player->incStructuresBuilt();
}
+2
View File
@@ -25,6 +25,8 @@ namespace battleship{
vb01::s64 lastBuildTime = 0;
inline int getNextPatrolPointId(int numPoints) {return patrolPointId == numPoints - 1 ? 0 : patrolPointId + 1;}
bool canReachTarget(vb01::Vector3, int&, int&);
bool truncatePath(Order&, std::vector<int>&, vb01::Vector3, bool);
void startCurrentOrder();
bool validateGarrisonOrder(Order);
void enterGarrisonable();