diff --git a/Assets/Scripts/Core/player.lua b/Assets/Scripts/Core/player.lua index 475c33e..1d4c45b 100644 --- a/Assets/Scripts/Core/player.lua +++ b/Assets/Scripts/Core/player.lua @@ -1,5 +1,6 @@ Player.numStartEngis = 3 -Player.baseDir = nil +Player.baseQuat = nil +Player.baseRadius = 180 Player.numDefWarMechs = 1 Player.behaviour = {} Player.pointDefenseTrans = {} @@ -37,7 +38,7 @@ Player.taskForceData = { Player.taskForces = {} -function Player:initBaseDir() +function Player:initBaseQuat() map = Map.getSingleton() sp = map:getSpawnPoint(self:getSpawnPointId()) minDistId = nil @@ -54,45 +55,109 @@ function Player:initBaseDir() ::continue:: end - self.baseDir = map:getSpawnPoint(minDistId):subtr(sp):norm() + dir = map:getSpawnPoint(minDistId):subtr(sp):norm() + left = (Vector3:new(1, 0, 0):getAngleBetween(dir) < .5 * math.pi) + angle = dir:getAngleBetween(Vector3:new(0, 0, 1)) * (left and 1 or -1) + + self.baseQuat = Quaternion:new(angle, Vector3:new(0, 1, 0)) end function Player:initPdSpots() - numPd = 6 - radius = 100 - map = Map.getSingleton() - mapSize = map:getMapSize() + pdId = self.unitClassMappings[UnitClass.POINT_DEFENSE + 1][self:getFaction() + 1] + pdFrame = GameObjectFrame:new(pdId, 0, self, nil, Vector3:new(0, 0, 0), Quaternion:new(1, 0, 0, 0)) + baseDir = self.baseQuat:multVec(Vector3:new(0, 0, 1)) + frameCtrl = GameObjectFrameController.getSingleton() + + numPd = 12 for i = 1, numPd do angle = (i - 1) * 2 * math.pi / numPd - rotDir = Quaternion:new(angle, Vector3:new(0, 1, 0)):multVec(self.baseDir) - pdPos = map:getSpawnPoint(self:getSpawnPointId()):add(rotDir:norm():mult(radius)) + rotDir = Quaternion:new(angle, Vector3:new(0, 1, 0)):multVec(baseDir) + pdPos = Map.getSingleton():getSpawnPoint(self:getSpawnPointId()):add(rotDir:norm():mult(self.baseRadius)) + pdFrame:placeAt(pdPos) - if math.abs(pdPos.x) < .5 * mapSize.x and math.abs(pdPos.z) < .5 * mapSize.z then + frameCtrl:checkPlacement(pdFrame) + + if pdFrame.status == 0 then self.pointDefenseTrans[#self.pointDefenseTrans + 1] = {pos = pdPos, angle = angle} end end + + pdFrame:destroy() +end + +--TODO replace this method with more robust checks to determine the possibility of building on a given spot +function Player:updatePdSpots() + pdId = self.unitClassMappings[UnitClass.POINT_DEFENSE + 1][self:getFaction() + 1] + pdFrame = GameObjectFrame:new(pdId, 0, self, nil, Vector3:new(0, 0, 0), Quaternion:new(1, 0, 0, 0)) + + gofCtrl = GameObjectFrameController.getSingleton() + delPdTrans = {} + + for i = 1, #self.pointDefenseTrans do + pdFrame:placeAt(self.pointDefenseTrans[i].pos) + gofCtrl:checkPlacement(pdFrame) + + if pdFrame.status == 1 then + table.insert(delPdTrans, i) + end + end + + for i = #delPdTrans, 1, -1 do + table.remove(self.pointDefenseTrans, i) + end + + pdFrame:destroy() end function Player:init() - self:initBaseDir() + self:initBaseQuat() self:initPdSpots() end +function Player:findSuitableSpot(buildingId, startPos) + structFrame = GameObjectFrame:new(buildingId, 0, self, nil, startPos, self.baseQuat) + numYPos = math.floor(2 * self.baseRadius / structFrame:getLength()) + numXPos = math.floor(2 * self.baseRadius / structFrame:getWidth()) + + baseDir = self.baseQuat:multVec(Vector3:new(0, 0, 1)) + baseLeft = self.baseQuat:multVec(Vector3:new(1, 0, 0)) + point = Map.getSingleton():getSpawnPoint(self:getSpawnPointId()):add(baseDir:mult(self.baseRadius)):add(baseLeft:mult(self.baseRadius)) + + frameCtrl = GameObjectFrameController.getSingleton() + frameCtrl:checkPlacement(structFrame) + + if structFrame.status == 1 then + for i = 1, numXPos do + point = point:add(baseLeft:neg():mult(i - 1)) + structFrame:placeAt(point) + frameCtrl:checkPlacement(structFrame) + + if structFrame.status == 0 then + structFrame:destroy() + return point + end + end + else + structFrame:destroy() + return startPos + end + + structFrame:destroy() + return nil +end + function Player:buildStructure(engineer, buildingId, buildPos, buildAngle) if not engineer then return BTNodeResult.FAILURE end + print(buildAngle) self:deselectUnits() self:selectUnits({engineer}) - building = GameObjectFactory.createUnit(self, buildingId, buildPos, Quaternion:new(buildAngle, Vector3:new(0, 1, 0)), 0) + building = GameObjectFactory.createUnit(self, buildingId, buildPos, Quaternion:new(-buildAngle, Vector3:new(0, 1, 0)), 0) self:issueOrder(OrderType.BUILD, Vector3:new(0, 0, 0), {Target:new(building:toGameObject(), Vector3:new(0, 0, 0))}, false) end -function Player:findSuitableSpot() - return Vector3:new(0, 0, 0) -end - function Player:findIdleEngineer() engineers = self:getUnitsByClass(UnitClass.CYBORG_ENGINEER, -1) @@ -115,7 +180,6 @@ function Player:getBuildableUnitSlotId(buildingUnit, buildableUnitId) return nil end ---TODO simplify building construction function Player:buildLandFactory(arguments) factory = self:getUnitsByClass(UnitClass.LAND_FACTORY, 1)[1] @@ -124,10 +188,14 @@ function Player:buildLandFactory(arguments) end factId = self.unitClassMappings[UnitClass.LAND_FACTORY + 1][self:getFaction() + 1] + rd = self.baseQuat:multVec(Vector3:new(0, 0, 1)):mult(self.baseRadius) sp = Map.getSingleton():getSpawnPoint(self:getSpawnPointId()) - self:buildStructure(self:findIdleEngineer(), factId, sp, angle) + pos = self:findSuitableSpot(factId, sp:add(rd)) - return BTNodeResult.RUNNING + if pos then + self:buildStructure(self:findIdleEngineer(), factId, pos, self.baseQuat:getAngle()) + return BTNodeResult.RUNNING + else return BTNodeResult.FAILURE end end function Player:trainEngineers(arguments) @@ -150,16 +218,25 @@ function Player:trainEngineers(arguments) end function Player:buildRefinery(arguments) - refinery = self:getUnitsByClass(UnitClass.REFINERY, 1) - if #refinery > 0 then - return (refinery[1]:toStructure():isComplete() and BTNodeResult.SUCCESS or BTNodeResult.RUNNING) + refinery = self:getUnitsByClass(UnitClass.REFINERY, 1)[1] + if refinery then + return (refinery:toStructure():isComplete() and BTNodeResult.SUCCESS or BTNodeResult.RUNNING) end - buildPos = Map.getSingleton():getSpawnPoint(self:getSpawnPointId()):add(self.baseDir:mult(20)) - factId = self.unitClassMappings[UnitClass.REFINERY + 1][self:getFaction() + 1] - self:buildStructure(self:findIdleEngineer(), factId, buildPos, -.0) + refId = self.unitClassMappings[UnitClass.REFINERY + 1][self:getFaction() + 1] + factId = self.unitClassMappings[UnitClass.LAND_FACTORY + 1][self:getFaction() + 1] - return BTNodeResult.RUNNING + rd = self.baseQuat:multVec(Vector3:new(0, 0, 1)):mult(self.baseRadius - .5 * (units[factId + 1].size.z + units[refId + 1].size.z)) + sp = Map.getSingleton():getSpawnPoint(self:getSpawnPointId()) + buildPos = sp:add(rd) + + pos = self:findSuitableSpot(refId, buildPos) + + if pos then + buildAngle = (self.baseQuat:getAngle() + math.pi) + self:buildStructure(self:findIdleEngineer(), refId, buildPos, buildAngle) + return BTNodeResult.RUNNING + else return BTNodeResult.FAILURE end end -- TODO optimize deposit position check @@ -281,8 +358,10 @@ function Player:buildLandForce(arguments) end function Player:buildPointDefenseRing(arguments) + self:updatePdSpots() pointDefs = self:getUnitsByClass(UnitClass.POINT_DEFENSE, -1) - if #pointDefs == #self.pointDefenseTrans then return BTNodeResult.SUCCESS end + + if #pointDefs >= #self.pointDefenseTrans then return BTNodeResult.SUCCESS end pdId = self.unitClassMappings[UnitClass.POINT_DEFENSE + 1][self:getFaction() + 1] pdTrans = self.pointDefenseTrans[#pointDefs + 1] diff --git a/Assets/Scripts/Core/playerInit.lua b/Assets/Scripts/Core/playerInit.lua index 7ce1f3f..f25b8df 100644 --- a/Assets/Scripts/Core/playerInit.lua +++ b/Assets/Scripts/Core/playerInit.lua @@ -36,6 +36,8 @@ for i = 1, #game.cpuPlayers do type = BTNodeType.PARALLEL, children = game.cpuPlayers[i]:generateTaskForceActions() } + --[[ + ]]-- } } end diff --git a/activeGameState.cpp b/activeGameState.cpp index d58c76d..a8c2fd7 100755 --- a/activeGameState.cpp +++ b/activeGameState.cpp @@ -311,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); diff --git a/buildButton.cpp b/buildButton.cpp index 6146b6f..af69db7 100644 --- a/buildButton.cpp +++ b/buildButton.cpp @@ -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); } diff --git a/gameManager.cpp b/gameManager.cpp index 008de60..7400e65 100755 --- a/gameManager.cpp +++ b/gameManager.cpp @@ -8,6 +8,7 @@ #include #include "gameManager.h" +#include "gameObjectFrameController.h" #include "gameObjectFactory.h" #include "map.h" #include "game.h" @@ -151,6 +152,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;}, @@ -163,6 +165,8 @@ 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;} ); @@ -189,6 +193,24 @@ namespace battleship{ "calcHeuristics", &Pathfinder::calcHeuristics, "findPath", &Pathfinder::findPath ); + + SOL_LUA_STATE.new_usertype( + "GameObjectFrame", sol::constructors(), + "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", + "getSingleton", &GameObjectFrameController::getSingleton, + "checkPlacement", &GameObjectFrameController::checkPlacement + ); } void GameManager::initLua(string gameDir){ diff --git a/gameObject.cpp b/gameObject.cpp index e9bac8f..db193f1 100644 --- a/gameObject.cpp +++ b/gameObject.cpp @@ -153,7 +153,7 @@ namespace battleship{ model->setMaterial(mat); sol::optional colNodeOpt = gameObjTable["colorNodes"]; - if(player && colNodeOpt != sol::nullopt) + if(!(model->isWireframe() || colNodeOpt == sol::nullopt)) useColor(player->getColorMaterial()); root->getRootNode()->attachChild(model); diff --git a/gameObjectFrame.h b/gameObjectFrame.h index 5a249d2..24dfdbd 100644 --- a/gameObjectFrame.h +++ b/gameObjectFrame.h @@ -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(); diff --git a/gameObjectFrameController.cpp b/gameObjectFrameController.cpp index 3bc5060..59905e3 100644 --- a/gameObjectFrameController.cpp +++ b/gameObjectFrameController.cpp @@ -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)); } } @@ -86,7 +86,8 @@ namespace battleship{ sol::table tbl = generateView()["units"][s.getId() + 1]; UnitType ut = (UnitType)tbl["unitType"]; - //vector friendlyUnits = s.getPlayer()->getFriendlyUnits(); + vector friendlyUnits = (s.getPlayer() ? s.getPlayer()->getFriendlyUnits() : vector{}); + 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()); @@ -105,6 +106,18 @@ namespace battleship{ 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(); diff --git a/gameObjectListbox.cpp b/gameObjectListbox.cpp index 2725daa..f82fede 100644 --- a/gameObjectListbox.cpp +++ b/gameObjectListbox.cpp @@ -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); } } diff --git a/player.cpp b/player.cpp index b705407..eb762bc 100755 --- a/player.cpp +++ b/player.cpp @@ -307,13 +307,12 @@ namespace battleship{ return true; Vector3 obsUnitPos = object->getPos(); - obsUnitPos.y = 0; + Vector2 oup2d = Vector2(obsUnitPos.x, obsUnitPos.z); Vector3 compUnitPos = friendlyUnit->getPos(); - compUnitPos.y = 0; - float dist = compUnitPos.getDistanceFrom(obsUnitPos); + Vector2 cup2d = Vector2(compUnitPos.x, compUnitPos.z); - if(dist <= friendlyUnit->getLineOfSight()) + if(cup2d.getDistanceFrom(oup2d) <= friendlyUnit->getLineOfSight()) return true; }