diff --git a/Assets/Scripts/Core/player.lua b/Assets/Scripts/Core/player.lua index 70b9b6c..db2d281 100644 --- a/Assets/Scripts/Core/player.lua +++ b/Assets/Scripts/Core/player.lua @@ -46,7 +46,7 @@ function Player:buildFort(arguments) angle = self.baseDir:getAngleBetween(Vector3:new(0, 0, 1)) * (right and -1 or 1) fort = GameObjectFactory.createUnit(self, UnitId.FORT, sp, Quaternion:new(angle, Vector3:new(0, 1, 0)), 0) self:addUnit(fort) - self:issueOrder(OrderType.BUILD, Vector3:new(0, 0, 0), {Target:new(fort, Vector3:new(0, 0, 0))}, false) + self:issueOrder(OrderType.BUILD, Vector3:new(0, 0, 0), {Target:new(fort:toGameObject(), Vector3:new(0, 0, 0))}, false) return BTNodeResult.RUNNING end @@ -84,7 +84,7 @@ function Player:buildStructure(engineer, buildingId, buildPos, buildAngle) building = GameObjectFactory.createUnit(self, buildingId, buildPos, Quaternion:new(1, 0, 0, 0), 0) self:addUnit(building) - self:issueOrder(OrderType.BUILD, Vector3:new(0, 0, 0), {Target:new(building, Vector3:new(0, 0, 0))}, false) + self:issueOrder(OrderType.BUILD, Vector3:new(0, 0, 0), {Target:new(building:toGameObject(), Vector3:new(0, 0, 0))}, false) end building = self:getUnitsByClass(unitClass, 1)[1] @@ -155,7 +155,7 @@ function Player:startHarvesting() self:deselectUnits() self:selectUnits({harvesters[1]}) - self:issueOrder(OrderType.SUPPLY, Vector3:new(0, 0, 0), {Target:new(extractor, Vector3:new(0, 0, 0))}, false) + self:issueOrder(OrderType.SUPPLY, Vector3:new(0, 0, 0), {Target:new(extractor:toGameObject(), Vector3:new(0, 0, 0))}, false) return BTNodeResult.SUCCESS end @@ -258,7 +258,7 @@ function Player:clearNearEnemies(arguments) if not taskForce.clearing and targUnit then self:deselectUnits() self:selectUnits(taskForce.units) - self:issueOrder(OrderType.MOVE, Vector3:new(0, 0, 0), {Target:new(targUnit, Vector3:new(0, 0, 0))}, false) + self:issueOrder(OrderType.MOVE, Vector3:new(0, 0, 0), {Target:new(targUnit:toGameObject(), Vector3:new(0, 0, 0))}, false) self.taskForces[arguments.tfId].clearing = true elseif taskForce.clearing and not targUnit then diff --git a/Assets/Scripts/GameObjects/Projectiles/projectileData.lua b/Assets/Scripts/GameObjects/Projectiles/projectileData.lua index 05db300..9e0e007 100644 --- a/Assets/Scripts/GameObjects/Projectiles/projectileData.lua +++ b/Assets/Scripts/GameObjects/Projectiles/projectileData.lua @@ -51,6 +51,7 @@ projectiles = { }, { projectileClass = ProjectileClass.CRUISE_MISSILE, + health = 75, size = {x = 6, y = 13.5, z = 2.54}, speed = .5, rotAngle = .1, @@ -64,6 +65,7 @@ projectiles = { }, { projectileClass = ProjectileClass.MISSILE, + health = 25, size = {x = 3, y = 7., z = 1.27}, speed = .5, rotAngle = .1, diff --git a/Assets/Scripts/GameObjects/Units/unitData.lua b/Assets/Scripts/GameObjects/Units/unitData.lua index 73426ff..76e736e 100644 --- a/Assets/Scripts/GameObjects/Units/unitData.lua +++ b/Assets/Scripts/GameObjects/Units/unitData.lua @@ -173,7 +173,8 @@ units = { rateOfFire = 1000, damage = 200, maxRange = 50, - nodes = {{name = 'Turret', rotationSpeed = .05, maxFireAngle = .1}}, + maxFireAngle = .1, + nodes = {{name = 'Turret', rotationSpeed = .05, vertical = false}}, projectile = {id = ProjectileId.HE_SHELL, parent = 'Turret', pos = {x = 0.06, y = 5.82, z = 11.4}, rot = {w = 1, x = 0, y = 0, z = 0}}, fireFx = { { @@ -230,9 +231,10 @@ units = { rateOfFire = 2000, damage = 5000, maxRange = 70, + maxFireAngle = .1, nodes = { - {name = 'turret', rotationSpeed = .05, maxFireAngle = .1}, - {name = 'tubes', rotationSpeed = .05, maxFireAngle = .1} + {name = 'turret', rotationSpeed = .05, vertical = false}, + --{name = 'tubes', rotationSpeed = .05, vertical = true} }, projectile = {id = ProjectileId.MISSILE, parent = 'tubes', pos = {x = 0.95, y = 2.16, z = 4.11}, rot = {w = 1, x = 0, y = 0, z = 0}}, fireFx = { @@ -896,7 +898,8 @@ units = { rateOfFire = 1000, damage = 0, maxRange = 25, - nodes = {{name = 'turret', rotationSpeed = .05, maxFireAngle = .1}}, + maxFireAngle = .1, + nodes = {{name = 'turret', rotationSpeed = .05, vertical = false}}, projectile = {id = ProjectileId.EMP_SHELL, parent = 'turret', pos = {x = 0.06, y = 5.82, z = 11.4}, rot = {w = .998, x = -.066, y = 0, z = 0}}, fireFx = { { @@ -1024,11 +1027,12 @@ units = { { orderType = OrderType.ATTACK, rateOfFire = 100, - damage = 50, - maxRange = 50, + damage = 17, + maxRange = 100, + maxFireAngle = .4, nodes = { - {name = 'TurretBody', rotationSpeed = .05, maxFireAngle = .1}, - {name = 'TurretArms', rotationSpeed = .05, maxFireAngle = .1} + {name = 'TurretBody', rotationSpeed = .1, vertical = false}, + {name = 'TurretArms', rotationSpeed = .1, angleConstraint = 1.1, vertical = true} }, fireFx = { { diff --git a/CMakeLists.txt b/CMakeLists.txt index c89e3e3..b5ee7c7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,18 +24,20 @@ set(TRADING_BUTTONS activeStateBackButton.cpp playerTradeButton.cpp tradingScree set(MENU_BUTTONS mainMenuButton.cpp singlePlayerButton.cpp exitButton.cpp backButton.cpp playButton.cpp) set(MAP_EDITOR_BUTTONS mapEditorButton.cpp newMapButton.cpp loadMapButton.cpp exportButton.cpp) set(BUTTONS statsButton.cpp activeStateButton.cpp minimapButton.cpp ${TRADING_BUTTONS} ${OPTIONS_BUTTONS} ${MENU_BUTTONS} ${MAP_EDITOR_BUTTONS} ${UNIT_BUTTONS}) + set(LISTBOXES skyboxTextureListbox.cpp landTextureListbox.cpp gameObjectListbox.cpp mapListbox.cpp) set(GUI tooltip.cpp concreteGuiManager.cpp ${BUTTONS} ${LISTBOXES}) set(CONTROLLERS gameObjectFrameController.cpp cameraController.cpp) set(CONSOLE console.cpp abstractCommand.cpp addUnitCommand.cpp addResourceCommand.cpp addTechnologyCommand.cpp toggleDebugCommand.cpp) -set(CORE gameManager.cpp game.cpp environment.cpp fxManager.cpp defConfigs.cpp ${CONSOLE} ${CONTROLLERS}) +set(CORE gameManager.cpp game.cpp pathfinder.cpp environment.cpp fxManager.cpp defConfigs.cpp player.cpp trader.cpp ${CONSOLE} ${CONTROLLERS}) set(PROJECTILES projectile.cpp missile.cpp cruiseMissile.cpp shell.cpp) set(VEHICLES vehicle.cpp submarine.cpp engineer.cpp resourceRover.cpp freezer.cpp) set(STRUCTURES structure.cpp factory.cpp pointDefense.cpp extractor.cpp researchStruct.cpp iceSheet.cpp) -set(UNITS gameObjectFactory.cpp unit.cpp weapon.cpp ${STRUCTURES} ${VEHICLES}) -set(CONTENT player.cpp trader.cpp pathfinder.cpp map.cpp gameObject.cpp gameObjectFrame.h resourceDeposit.cpp ${UNITS} ${PROJECTILES}) +set(WEAPONS weapon.cpp cryoGun.cpp) +set(UNITS unit.cpp ${WEAPONS} ${STRUCTURES} ${VEHICLES}) +set(CONTENT map.cpp gameObject.cpp destructable.cpp gameObjectFrame.h gameObjectFactory.cpp resourceDeposit.cpp ${UNITS} ${PROJECTILES}) set(UTIL util.cpp binds.h) diff --git a/cruiseMissile.cpp b/cruiseMissile.cpp index 5034db8..04884ac 100644 --- a/cruiseMissile.cpp +++ b/cruiseMissile.cpp @@ -1,4 +1,5 @@ #include "cruiseMissile.h" +#include "destructable.h" #include "player.h" #include "unit.h" #include "map.h" @@ -12,7 +13,13 @@ namespace battleship{ using namespace std; using namespace vb01; - CruiseMissile::CruiseMissile(Unit *unit, int id, Vector3 tp, Vector3 pos, Quaternion rot) : Projectile(unit, id, pos, rot), targetPoint(tp), flightStage(FlightStage::ASCENT){ + CruiseMissile::CruiseMissile(Unit *unit, int id, Vector3 tp, Vector3 pos, Quaternion rot) : + Projectile(unit, id, pos, rot), + targetPoint(tp), + flightStage(FlightStage::ASCENT) + { + destructable = new Destructable(this); + Vector3 unitDir = unit->getDirVec(); Vector3 leftDir = unit->getLeftVec(); Vector3 targDir = (Vector3(targetPoint.x, pos.y, targetPoint.z) - pos).norm(); @@ -22,20 +29,22 @@ namespace battleship{ orientAt(Quaternion(angle, Vector3::VEC_J) * rot); } + CruiseMissile::~CruiseMissile(){delete destructable;} + void CruiseMissile::pitch(float rotAngle, Vector3 compVec){ float minHeight = 20; - float angleToCompVec = dirVec.getAngleBetween(compVec); + float angleToCompVec = Projectile::dirVec.getAngleBetween(compVec); float angle = (angleToCompVec > rotAngle ? rotAngle : angleToCompVec); - if(flightStage == FlightStage::ASCENT && pos.y - initPos.y > minHeight){ - orientAt(Quaternion(angle, leftVec) * rot); - if(dirVec.y <= .001) flightStage = FlightStage::CRUISE; + if(flightStage == FlightStage::ASCENT && Projectile::pos.y - initPos.y > minHeight){ + Projectile::orientAt(Quaternion(angle, Projectile::leftVec) * Projectile::rot); + if(Projectile::dirVec.y <= .001) flightStage = FlightStage::CRUISE; } else if(flightStage == FlightStage::DESCENT){ Vector3 targDir = (Vector3(targetPoint.x, initPos.y, targetPoint.z) - initPos).norm(); - if(dirVec.getAngleBetween(targDir) < PI / 2) - orientAt(Quaternion(angle, leftVec) * rot); + if(Projectile::dirVec.getAngleBetween(targDir) < PI / 2) + Projectile::orientAt(Quaternion(angle, Projectile::leftVec) * Projectile::rot); } } @@ -43,16 +52,17 @@ namespace battleship{ float minDist = 6; float initDist = Vector3(targetPoint.x, initPos.y, targetPoint.z).getDistanceFrom(initPos); - if(pos.getDistanceFrom(Vector3(targetPoint.x, pos.y, targetPoint.z)) < minDist) + if(Projectile::pos.getDistanceFrom(Vector3(targetPoint.x, Projectile::pos.y, targetPoint.z)) < minDist) flightStage = FlightStage::DESCENT; } void CruiseMissile::update(){ Projectile::update(); + destructable->update(); switch(flightStage){ case FlightStage::ASCENT: - pitch(rotAngle, Vector3(dirVec.x, 0, dirVec.z).norm()); + pitch(rotAngle, Vector3(Projectile::dirVec.x, 0, Projectile::dirVec.z).norm()); break; case FlightStage::DESCENT: pitch(rotAngle, -Vector3::VEC_J); @@ -62,10 +72,6 @@ namespace battleship{ break; } - checkCollision(); - } - - void CruiseMissile::checkCollision(){ if(flightStage == FlightStage::DESCENT) Projectile::checkCollision(); } diff --git a/cruiseMissile.h b/cruiseMissile.h index 19101ab..ff76db4 100644 --- a/cruiseMissile.h +++ b/cruiseMissile.h @@ -7,6 +7,7 @@ namespace battleship{ class CruiseMissile : public Projectile{ public: CruiseMissile(Unit*, int, vb01::Vector3, vb01::Vector3, vb01::Quaternion); + ~CruiseMissile(); void update(); private: enum class FlightStage{ASCENT, CRUISE, DESCENT}; @@ -15,7 +16,6 @@ namespace battleship{ void pitch(float, vb01::Vector3); void cruise(); - void checkCollision(); }; } diff --git a/cryoGun.cpp b/cryoGun.cpp new file mode 100644 index 0000000..d2fd9d7 --- /dev/null +++ b/cryoGun.cpp @@ -0,0 +1,20 @@ +#include "cryoGun.h" +#include "destructable.h" +#include "unit.h" + +namespace battleship{ + using namespace std; + using namespace vb01; + using namespace gameBase; + + CryoGun::CryoGun(Unit *u, sol::table unitTable, int wid) : Weapon(u, unitTable, wid){} + + void CryoGun::updateTarget(GameObject *target){ + if(canFreeze()){ + Destructable *destructTarg = target->getDestructable(); + destructTarg->setFreezeStatus(destructTarg->getFreezeStatus() + 1); + lastFreezeTime = getTime(); + } + } +} + diff --git a/cryoGun.h b/cryoGun.h new file mode 100644 index 0000000..e0fd381 --- /dev/null +++ b/cryoGun.h @@ -0,0 +1,25 @@ +#ifndef CRYOGUN_H +#define CRYOGUN_H + +#include "weapon.h" + +#include + +#include + +namespace battleship{ + class Unit; + + class CryoGun : public Weapon{ + public: + CryoGun(Unit*, sol::table, int); + private: + vb01::s64 lastFreezeTime = 0; + + void updateTarget(GameObject*); + inline bool canFreeze(){return vb01::getTime() - lastFreezeTime > rateOfFire;} + }; +} + +#endif + diff --git a/destructable.cpp b/destructable.cpp new file mode 100644 index 0000000..a127a13 --- /dev/null +++ b/destructable.cpp @@ -0,0 +1,110 @@ +#include "destructable.h" +#include "environment.h" +#include "player.h" +#include "game.h" + +#include +#include +#include +#include + +#include + +#include + +using namespace std; +using namespace vb01; +using namespace gameBase; + +namespace battleship{ + Destructable::Destructable(GameObject *obj) : gameObject(obj){ + initProperties(); + } + + void Destructable::initProperties(){ + //GameObject::initProperties(); + + int id = gameObject->getId(); + sol::state_view SOL_LUA_VIEW = generateView(); + string objType = gameObject->getGameObjTableName(); + sol::table objTable = SOL_LUA_VIEW[objType][gameObject->getId() + 1]; + + vector currTechs = gameObject->getPlayer()->getTechnologies(); + health += Game::getSingleton()->calcAbilFromTech(Ability::Type::HEALTH, currTechs, (int)gameObject->getType(), id); + maxHealth = objTable["health"]; + + if(health == 0) health = maxHealth; + + string tblName = "armor"; + sol::optional at = objTable[tblName]; + + if(at != sol::nullopt){ + string varName = "numArmorTypes"; + SOL_LUA_VIEW.script(varName + " = #" + objType + "[" + to_string(id + 1) + "]." + tblName); + int numArmorTypes = SOL_LUA_VIEW[varName]; + + for(int i = 0; i < numArmorTypes; i++){ + Armor arm = (Armor)objTable[tblName][i + 1]; + armorTypes.push_back(arm); + } + } + } + + //TODO make this class a friend to GameObject + void Destructable::update(){ + if (health <= DEATH_HP){ + gameObject->setRemove(true); + + sol::optional tblOpt = generateView()[gameObject->getGameObjTableName()][gameObject->getId() + 1]["deathFx"]; + + if(tblOpt == sol::nullopt) return; + + Vector3 pos = gameObject->getPos(); + sol::table tbl = generateView()[gameObject->getGameObjTableName()][gameObject->getId() + 1]["deathFx"]; + FxManager::Fx *fx = FxManager::getSingleton()->initFx(tbl, gameObject->getModel(), false, pos); + Environment::explode(fx, Environment::Detonation::EXPLOSION, pos); + } + } + + Node* Destructable::createBar(Vector2 pos, Vector2 size, Vector4 color){ + Root *root = Root::getSingleton(); + Material *mat = new Material(root->getLibPath() + "gui"); + mat->addBoolUniform("texturingEnabled", false); + mat->addVec4Uniform("diffuseColor", color); + + Quad *quad = new Quad(Vector3(size.x, size.y, 0), false); + quad->setMaterial(mat); + + Node *node = new Node(Vector3(pos.x, pos.y, 0)); + node->attachMesh(quad); + node->setVisible(false); + root->getGuiNode()->attachChild(node); + + return node; + } + + void Destructable::displayStats(Node *foreground, Node *background, int currVal, int maxVal, bool render, Vector2 offset) { + foreground->setVisible(render); + background->setVisible(render); + + if(render){ + Vector3 offset3d = Vector3(offset.x, offset.y, 0); + Vector2 screenPos = gameObject->getScreenPos(); + + Quad *bgQuad = (Quad*)background->getMesh(0); + Vector3 size = bgQuad->getSize(); + float shiftedX = screenPos.x - 0.5 * size.x; + background->setPosition(Vector3(shiftedX, screenPos.y, 0) + offset3d); + + Quad *fgQuad = (Quad*)foreground->getMesh(0); + fgQuad->setSize(Vector3((float)currVal / maxVal * size.x, size.y, 0)); + fgQuad->updateVerts(fgQuad->getMeshBase()); + foreground->setPosition(Vector3(shiftedX, screenPos.y, .01) + offset3d); + } + } + + void Destructable::removeBar(Node *node){ + Root::getSingleton()->getGuiNode()->dettachChild(node); + delete node; + } +} diff --git a/destructable.h b/destructable.h new file mode 100644 index 0000000..083b56e --- /dev/null +++ b/destructable.h @@ -0,0 +1,43 @@ +#ifndef DESTRUCTABLE_H +#define DESTRUCTABLE_H + +#include + +#include +#include + +namespace vb01{ + class Node; +} + +namespace battleship{ + enum class Armor {CAST, COMBINED, MECHANIC, SHELL, STEEL}; + + class GameObject; + + class Destructable{ + public: + Destructable(GameObject*); + void update(); + void removeBar(vb01::Node*); + vb01::Node* createBar(vb01::Vector2, vb01::Vector2, vb01::Vector4); + void displayStats(vb01::Node*, vb01::Node*, int, int, bool, vb01::Vector2 offset = vb01::Vector2::VEC_ZERO); + inline int getHealth(){return health;} + inline int getMaxHealth(){return maxHealth;} + inline int getDeathHp(){return DEATH_HP;} + inline void takeDamage(int damage) {health -= damage * (1 + (freezeDmgFactor - 1) * freezeStatus * .01f);} + inline GameObject* getGameObject(){return gameObject;} + inline std::vector getArmorTypes(){return armorTypes;} + inline void setFreezeStatus(int fs){this->freezeStatus = std::clamp(fs, 0, 100);} + inline int getFreezeStatus(){return freezeStatus;} + private: + std::vector armorTypes; + const int DEATH_HP = 0; + int health = 0, maxHealth, freezeStatus = 0, freezeDmgFactor = 10; + GameObject *gameObject = nullptr; + + void initProperties(); + }; +} + +#endif diff --git a/engineer.cpp b/engineer.cpp index 937cbcb..e8755e9 100644 --- a/engineer.cpp +++ b/engineer.cpp @@ -1,5 +1,6 @@ #include "engineer.h" #include "activeGameState.h" +#include "destructable.h" #include "structure.h" #include "player.h" #include "game.h" @@ -21,13 +22,13 @@ namespace battleship{ hackRange = generateView()["units"][id + 1]["hackRange"]; hackRange += game->calcAbilFromTech(Ability::Type::HACK_RANGE, currTechs, (int)GameObject::type, id); Vector2 size = Vector2(lenHpBar, 10); - hackStatusBackground = Unit::createBar(Vector2::VEC_ZERO, size, Vector4(0, 0, 0, 1)); - hackStatusForeground = Unit::createBar(Vector2::VEC_ZERO, size, Vector4(1, 0, 1, 1)); + hackStatusBackground = destructable->createBar(Vector2::VEC_ZERO, size, Vector4(0, 0, 0, 1)); + hackStatusForeground = destructable->createBar(Vector2::VEC_ZERO, size, Vector4(1, 0, 1, 1)); } Engineer::~Engineer(){ - removeBar(hackStatusBackground); - removeBar(hackStatusForeground); + destructable->removeBar(hackStatusBackground); + destructable->removeBar(hackStatusForeground); } void Engineer::update(){ @@ -40,7 +41,7 @@ namespace battleship{ bool mainPlayerSelecting = (activeState && find(selectingPlayers.begin(), selectingPlayers.end(), mainPlayer) != selectingPlayers.end()); if(hackStatus < 100) - Unit::displayUnitStats(hackStatusForeground, hackStatusBackground, hackStatus, 100, mainPlayer == player && mainPlayerSelecting, Vector2(0, -10)); + destructable->displayStats(hackStatusForeground, hackStatusBackground, hackStatus, 100, mainPlayer == player && mainPlayerSelecting, Vector2(0, -10)); else{ hackStatusBackground->setVisible(false); hackStatusForeground->setVisible(false); @@ -52,7 +53,7 @@ namespace battleship{ //TODO change unit colors after faction change void Engineer::hack(Order order){ - Unit *targUnit = order.targets[0].unit; + Unit *targUnit = (Unit*)order.targets[0].unit; bool withinRange = (targUnit->getPos().getDistanceFrom(pos) < hackRange); int hackRate = int(generateView()["units"][id + 1]["hackTime"]) / 100; bool canHack = (getTime() - lastHackTime > hackRate); diff --git a/environment.cpp b/environment.cpp index 57971f2..28480cb 100644 --- a/environment.cpp +++ b/environment.cpp @@ -3,6 +3,7 @@ #include "player.h" #include "unit.h" #include "game.h" +#include "destructable.h" #include #include @@ -36,7 +37,7 @@ namespace battleship{ if(distance < radius){ switch(det){ case Detonation::EXPLOSION: - un->takeDamage(int(damage * (1.f - distance / radius))); + un->getDestructable()->takeDamage(int(damage * (1.f - distance / radius))); break; case Detonation::EMP: un->setCondition(Unit::Condition::EM_JAMMED); diff --git a/extractor.cpp b/extractor.cpp index 2e5d0cc..e88de35 100644 --- a/extractor.cpp +++ b/extractor.cpp @@ -1,6 +1,7 @@ #include "extractor.h" #include "player.h" #include "game.h" +#include "destructable.h" #include "activeGameState.h" #include "resourceDeposit.h" @@ -12,25 +13,25 @@ namespace battleship{ using namespace gameBase; Extractor::Extractor(Player *player, int id, Vector3 pos, Quaternion rot, int buildStatus, ResourceDeposit *rd, Unit::State state) : Structure(player, id, pos, rot, buildStatus, state){ - if(!rd) - for(ResourceDeposit *dep : Game::getSingleton()->getCivilianPlayer()->getResourceDeposits()) - if(dep->getPos().getDistanceFrom(pos) < .001){ - deposit = dep; - deposit->setExtractor(this); - break; - } - Vector2 size = Vector2(lenHpBar, 10); - ammountBackground = Unit::createBar(Vector2::VEC_ZERO, size, Vector4(0, 0, 0, 1)); - ammountForeground = Unit::createBar(Vector2::VEC_ZERO, size, Vector4(0, 0, 1, 1)); + ammountBackground = destructable->createBar(Vector2::VEC_ZERO, size, Vector4(0, 0, 0, 1)); + ammountForeground = destructable->createBar(Vector2::VEC_ZERO, size, Vector4(0, 0, 1, 1)); + + if(rd) return; + + for(ResourceDeposit *dep : Game::getSingleton()->getCivilianPlayer()->getResourceDeposits()) + if(dep->getPos().getDistanceFrom(pos) < .001){ + deposit = dep; + deposit->setExtractor(this); + break; + } } Extractor::~Extractor(){ - if(deposit) - deposit->setExtractor(nullptr); + if(deposit) deposit->setExtractor(nullptr); - removeBar(ammountForeground); - removeBar(ammountBackground); + destructable->removeBar(ammountForeground); + destructable->removeBar(ammountBackground); } void Extractor::initProperties(){ @@ -58,7 +59,7 @@ namespace battleship{ initAmmount = deposit->getInitAmmount(); } - Unit::displayUnitStats(ammountForeground, ammountBackground, ammount, initAmmount, mainPlayer == player && mainPlayerSelecting, Vector2(0, -10)); + destructable->displayStats(ammountForeground, ammountBackground, ammount, initAmmount, mainPlayer == player && mainPlayerSelecting, Vector2(0, -10)); } void Extractor::draw(){ diff --git a/factory.cpp b/factory.cpp index 6008c6e..aacf115 100644 --- a/factory.cpp +++ b/factory.cpp @@ -1,6 +1,7 @@ #include "factory.h" #include "player.h" #include "game.h" +#include "destructable.h" #include "gameObjectFactory.h" #include "activeGameState.h" @@ -21,16 +22,12 @@ namespace battleship{ if(!isComplete()) return; - if(!unitQueue.empty()) - train(); + if(!unitQueue.empty()) train(); } //TODO replace repetetive string literals void Factory::initProperties(){ Structure::initProperties(); - Game *game = Game::getSingleton(); - vector currTechs = player->getTechnologies(); - } int Factory::getNumQueueUnitsById(int unitId){ @@ -60,7 +57,7 @@ namespace battleship{ vector selectingPlayers = getSelectingPlayers(); bool mainPlayerSelecting = (activeState && find(selectingPlayers.begin(), selectingPlayers.end(), mainPlayer) != selectingPlayers.end()); - Unit::displayUnitStats(buildStatusForeground, buildStatusBackground, trainingStatus, 100, mainPlayer == player && mainPlayerSelecting, Vector2(0, -10)); + destructable->displayStats(buildStatusForeground, buildStatusBackground, trainingStatus, 100, mainPlayer == player && mainPlayerSelecting, Vector2(0, -10)); sol::table targTable = generateView()["units"][unitQueue[0] + 1]; int costRate = (int)targTable["cost"] / 100, trainRate = (int)targTable["buildTime"] / 100; diff --git a/freezer.cpp b/freezer.cpp index f0f81d0..d3df3ab 100644 --- a/freezer.cpp +++ b/freezer.cpp @@ -1,4 +1,5 @@ #include "freezer.h" +#include "destructable.h" namespace battleship{ using namespace vb01; @@ -9,7 +10,7 @@ namespace battleship{ void Freezer::attack(Order order){ Vehicle::attack(order); - Unit *target = order.targets[0].unit; + Destructable *target = order.targets[0].unit->getDestructable(); if(target && target->getFreezeStatus() == 100) removeOrder(0); diff --git a/gameManager.cpp b/gameManager.cpp index 5d9cc8b..73d031a 100755 --- a/gameManager.cpp +++ b/gameManager.cpp @@ -16,6 +16,7 @@ #include "player.h" #include "factory.h" #include "engineer.h" +#include "destructable.h" #include "pointDefense.h" #include "resourceDeposit.h" @@ -44,7 +45,7 @@ namespace battleship{ ); SOL_LUA_STATE.new_usertype( - "Target", sol::constructors(), + "Target", sol::constructors(), "unit", &Order::Target::unit, "pos", &Order::Target::pos ); @@ -58,6 +59,7 @@ namespace battleship{ SOL_LUA_STATE.new_usertype( "Unit", sol::constructors(), "setState", &Unit::setState, + "getDestructable", &Unit::getDestructable, "getOrder", &Unit::getOrder, "getNumOrders", &Unit::getNumOrders, "getPos", &GameObject::getPos, @@ -66,7 +68,8 @@ namespace battleship{ "toEngineer", &Unit::toEngineer, "toPointDefense", &Unit::toPointDefense, "toStructure", &Unit::toStructure, - "toFactory", &Unit::toFactory + "toFactory", &Unit::toFactory, + "toGameObject", &Unit::toGameObject ); SOL_LUA_STATE.new_usertype( diff --git a/gameObject.cpp b/gameObject.cpp index 5904786..e9bac8f 100644 --- a/gameObject.cpp +++ b/gameObject.cpp @@ -1,5 +1,6 @@ #include "gameObject.h" #include "gameManager.h" +#include "destructable.h" #include "defConfigs.h" #include "player.h" #include "game.h" @@ -222,19 +223,4 @@ namespace battleship{ return "resources"; } } - - void GameObject::updateGameStats(Unit *targetUnit){ - if(targetUnit->getHealth() <= targetUnit->getDeathHp()){ - Player *targUnitPlayer = targetUnit->getPlayer(); - - if(targetUnit->isVehicle()){ - player->incVehiclesDestroyed(); - targUnitPlayer->incVehiclesLost(); - } - else{ - player->incStructuresDestroyed(); - targUnitPlayer->incStructuresLost(); - } - } - } } diff --git a/gameObject.h b/gameObject.h index aeb501c..e095f7d 100644 --- a/gameObject.h +++ b/gameObject.h @@ -13,6 +13,7 @@ namespace sf{ namespace battleship{ class Player; class Unit; + class Destructable; class GameObject{ public: @@ -26,7 +27,6 @@ namespace battleship{ virtual void placeAt(vb01::Vector3); void orientAt(vb01::Quaternion); std::string getGameObjTableName(); - void updateGameStats(Unit*); static sf::Sound* prepareSfx(sf::SoundBuffer*, std::string); bool pointWithinObj(vb01::Vector3, float = 0, float = 0, bool = false, float = 0); void changePlayer(Player *newPlayer); @@ -50,7 +50,9 @@ namespace battleship{ inline int getId() {return id;} inline Type getType(){return type;} inline vb01::Node* getHitbox(){return hitbox;} + inline void setRemove(bool rm){this->remove = rm;} inline bool isRemove(){return remove;} + inline Destructable* getDestructable(){return destructable;} protected: virtual void useColor(vb01::Material*); virtual void initProperties(); @@ -64,6 +66,7 @@ namespace battleship{ Type type; int id; Player *player; + Destructable *destructable = nullptr; vb01::Model *model = nullptr; vb01::Node *hitbox = nullptr; vb01::Vector3 pos = vb01::Vector3(0, 0, 0), upVec = vb01::Vector3(0, 1, 0), dirVec = vb01::Vector3(0, 0, 1), leftVec = vb01::Vector3(1, 0, 0), corners[8]; diff --git a/missile.cpp b/missile.cpp index 64754b5..434ec14 100644 --- a/missile.cpp +++ b/missile.cpp @@ -1,19 +1,27 @@ #include "missile.h" +#include "unit.h" +#include "destructable.h" namespace battleship{ using namespace vb01; Missile::Missile(Unit *un, int id, Vector3 tp, Vector3 pos, Quaternion rot) : Projectile(un, id, pos, rot), - targetPos(tp){} + targetPos(tp) + { + destructable = new Destructable(this); + } + + Missile::~Missile(){delete destructable;} void Missile::update(){ - Vector3 targDir = (targetPos - pos).norm(); - float angle = targDir.getAngleBetween(dirVec); + Vector3 targDir = (targetPos - Projectile::pos).norm(); + float angle = targDir.getAngleBetween(Projectile::dirVec); float ra = (rotAngle < angle ? rotAngle : angle); - orientAt(Quaternion(ra, dirVec.cross(targDir)) * rot); + orientAt(Quaternion(ra, Projectile::dirVec.cross(targDir)) * Projectile::rot); Projectile::update(); + destructable->update(); checkCollision(); } } diff --git a/missile.h b/missile.h index 44024f9..1ef06de 100644 --- a/missile.h +++ b/missile.h @@ -7,7 +7,7 @@ namespace battleship{ class Missile : public Projectile{ public: Missile(Unit*, int, vb01::Vector3, vb01::Vector3, vb01::Quaternion); - ~Missile(){} + ~Missile(); void update(); private: vb01::Vector3 targetPos; diff --git a/player.cpp b/player.cpp index 8cbfbbd..18cfd97 100755 --- a/player.cpp +++ b/player.cpp @@ -6,6 +6,7 @@ #include "structure.h" #include "projectile.h" #include "tradeOffer.h" +#include "destructable.h" #include "activeGameState.h" #include "resourceDeposit.h" @@ -255,4 +256,34 @@ namespace battleship{ break; } } + + vector Player::getDestructables(){ + vector destructables; + + for(Projectile *p : projectiles) + if(p->getDestructable()) + destructables.push_back(p); + + for(Unit *unit : units) + destructables.push_back((GameObject*)unit); + + return destructables; + } + + void Player::updateGameStats(Unit *targetUnit){ + Destructable *destructTarg = targetUnit->getDestructable(); + + if(destructTarg->getHealth() <= destructTarg->getDeathHp()){ + Player *targUnitPlayer = targetUnit->getPlayer(); + + if(targetUnit->isVehicle()){ + incVehiclesDestroyed(); + targUnitPlayer->incVehiclesLost(); + } + else{ + incStructuresDestroyed(); + targUnitPlayer->incStructuresLost(); + } + } + } } diff --git a/player.h b/player.h index 8733ccf..d2f68b8 100755 --- a/player.h +++ b/player.h @@ -37,6 +37,8 @@ namespace battleship{ void addTradeOffer(Player*, TradeOffer*); std::vector getTradeOffers(Player*); void deselectUnit(Unit*); + std::vector getDestructables(); + void updateGameStats(Unit*); 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;} diff --git a/projectile.cpp b/projectile.cpp index 03873a3..8835615 100755 --- a/projectile.cpp +++ b/projectile.cpp @@ -13,6 +13,7 @@ #include "environment.h" #include "projectile.h" #include "defConfigs.h" +#include "destructable.h" #include "resourceDeposit.h" #include "inGameAppState.h" @@ -54,6 +55,8 @@ namespace battleship{ vector currTechs = player->getTechnologies(); sol::table projTable = generateView()[GameObject::getGameObjTableName()][id + 1]; + projClass = (ProjectileClass)projTable["projectileClass"]; + rayLength = projTable["rayLength"]; directHitDamage = projTable["directHitDamage"]; directHitDamage += game->calcAbilFromTech(Ability::Type::DIRECT_HIT_DAMAGE, currTechs, (int)GameObject::type, id); @@ -70,7 +73,7 @@ namespace battleship{ } void Projectile::detonate(Unit *target){ - if(target) target->takeDamage(directHitDamage); + if(target) target->getDestructable()->takeDamage(directHitDamage); sol::table tbl = generateView()[getGameObjTableName()][id + 1]["explosion"]; FxManager::Fx *fx = FxManager::getSingleton()->initFx(tbl["fx"], model, false, pos); diff --git a/projectile.h b/projectile.h index 24329d9..2d24cb2 100755 --- a/projectile.h +++ b/projectile.h @@ -21,6 +21,7 @@ namespace battleship { virtual ~Projectile(); virtual void update(); virtual void debug(); + inline ProjectileClass getProjectileClass(){return projClass;} private: void initProperties(); void detonate(Unit *u = nullptr); @@ -31,6 +32,7 @@ namespace battleship { void checkCollision(); vb01::Vector3 initPos; + ProjectileClass projClass; Unit *unit = nullptr; FxManager::Fx *explosionFx = nullptr; float speed, rayLength, explosionRadius, rotAngle; diff --git a/researchStruct.cpp b/researchStruct.cpp index b31c89f..398b307 100644 --- a/researchStruct.cpp +++ b/researchStruct.cpp @@ -1,5 +1,6 @@ #include "researchStruct.h" #include "activeGameState.h" +#include "destructable.h" #include "player.h" #include "game.h" @@ -17,13 +18,13 @@ namespace battleship{ researchCost = unitTable["researchCost"]; Vector2 size = Vector2(lenHpBar, 10); - researchStatusBackground = Unit::createBar(Vector2::VEC_ZERO, size, Vector4(0, 0, 0, 1)); - researchStatusForeground = Unit::createBar(Vector2::VEC_ZERO, size, Vector4(1, 0, 1, 1)); + researchStatusBackground = destructable->createBar(Vector2::VEC_ZERO, size, Vector4(0, 0, 0, 1)); + researchStatusForeground = destructable->createBar(Vector2::VEC_ZERO, size, Vector4(1, 0, 1, 1)); } ResearchStruct::~ResearchStruct(){ - removeBar(researchStatusBackground); - removeBar(researchStatusForeground); + destructable->removeBar(researchStatusBackground); + destructable->removeBar(researchStatusForeground); } void ResearchStruct::update(){ @@ -38,7 +39,7 @@ namespace battleship{ bool mainPlayerSelecting = (activeState && find(selectingPlayers.begin(), selectingPlayers.end(), mainPlayer) != selectingPlayers.end()); if(researchQueue.empty()){ - if(health > .3 * maxHealth && player->getResource(ResourceType::REFINEDS) >= researchCost && canUpdateResearch()){ + if(destructable->getHealth() > .3 * destructable->getMaxHealth() && player->getResource(ResourceType::REFINEDS) >= researchCost && canUpdateResearch()){ player->updateResource(ResourceType::RESEARCH, generationSpeed, true); player->updateResource(ResourceType::REFINEDS, -researchCost, true); lastUpdateTime = getTime(); @@ -48,7 +49,7 @@ namespace battleship{ researchStatusForeground->setVisible(false); } else if(!researchQueue.empty()){ - Unit::displayUnitStats(researchStatusForeground, researchStatusBackground, researchStatus, 100, mainPlayer == player && mainPlayerSelecting, Vector2(0, -10)); + destructable->displayStats(researchStatusForeground, researchStatusBackground, researchStatus, 100, mainPlayer == player && mainPlayerSelecting, Vector2(0, -10)); int techCost = Game::getSingleton()->getTechnology(researchQueue[0]).cost; int playerResearch = player->getResource(ResourceType::RESEARCH); diff --git a/resourceRover.cpp b/resourceRover.cpp index 4cbafc5..fe68a65 100644 --- a/resourceRover.cpp +++ b/resourceRover.cpp @@ -1,5 +1,6 @@ #include "resourceRover.h" #include "resourceDeposit.h" +#include "destructable.h" #include "map.h" #include "game.h" #include "player.h" @@ -16,15 +17,15 @@ namespace battleship{ ResourceRover::ResourceRover(Player *player, int id, Vector3 pos, Quaternion rot, Unit::State state) : Vehicle(player, id, pos, rot, state) { Vector2 size = Vector2(lenHpBar, 10); - loadBackground = Unit::createBar(Vector2::VEC_ZERO, size, Vector4(0, 0, 0, 1)); - loadForeground = Unit::createBar(Vector2::VEC_ZERO, size, Vector4(1, 1, 0, 1)); + loadBackground = destructable->createBar(Vector2::VEC_ZERO, size, Vector4(0, 0, 0, 1)); + loadForeground = destructable->createBar(Vector2::VEC_ZERO, size, Vector4(1, 1, 0, 1)); initProperties(); } ResourceRover::~ResourceRover(){ - removeBar(loadForeground); - removeBar(loadBackground); + destructable->removeBar(loadForeground); + destructable->removeBar(loadBackground); } void ResourceRover::initProperties(){ @@ -166,7 +167,7 @@ namespace battleship{ vector selectingPlayers = getSelectingPlayers(); bool mainPlayerSelecting = (activeState && find(selectingPlayers.begin(), selectingPlayers.end(), mainPlayer) != selectingPlayers.end()); - Unit::displayUnitStats(loadForeground, loadBackground, calcTotalLoad(), capacity, mainPlayer == player && mainPlayerSelecting, Vector2(0, -10)); + destructable->displayStats(loadForeground, loadBackground, calcTotalLoad(), capacity, mainPlayer == player && mainPlayerSelecting, Vector2(0, -10)); } Unit* ResourceRover::getClosestUnit(vector structs){ diff --git a/structure.cpp b/structure.cpp index 52b5cd2..3926dae 100644 --- a/structure.cpp +++ b/structure.cpp @@ -1,5 +1,6 @@ #include "structure.h" #include "activeGameState.h" +#include "destructable.h" #include @@ -12,13 +13,13 @@ using namespace std; namespace battleship{ Structure::Structure(Player *player, int id, Vector3 pos, Quaternion rot, int bldSt, Unit::State state) : Unit(player, id, pos, rot, state), buildStatus(bldSt){ Vector2 size = Vector2(lenHpBar, 10); - buildStatusBackground = Unit::createBar(Vector2::VEC_ZERO, size, Vector4(0, 0, 0, 1)); - buildStatusForeground = Unit::createBar(Vector2::VEC_ZERO, size, Vector4(0, 0, 1, 1)); + buildStatusBackground = destructable->createBar(Vector2::VEC_ZERO, size, Vector4(0, 0, 0, 1)); + buildStatusForeground = destructable->createBar(Vector2::VEC_ZERO, size, Vector4(0, 0, 1, 1)); } Structure::~Structure(){ - removeBar(buildStatusForeground); - removeBar(buildStatusBackground); + destructable->removeBar(buildStatusForeground); + destructable->removeBar(buildStatusBackground); } void Structure::update(){ @@ -31,7 +32,7 @@ namespace battleship{ bool mainPlayerSelecting = (activeState && find(selectingPlayers.begin(), selectingPlayers.end(), mainPlayer) != selectingPlayers.end()); if(buildStatus < 100) - Unit::displayUnitStats(buildStatusForeground, buildStatusBackground, buildStatus, 100, mainPlayer == player && mainPlayerSelecting, Vector2(0, -10)); + destructable->displayStats(buildStatusForeground, buildStatusBackground, buildStatus, 100, mainPlayer == player && mainPlayerSelecting, Vector2(0, -10)); else{ buildStatusBackground->setVisible(false); buildStatusForeground->setVisible(false); diff --git a/unit.cpp b/unit.cpp index 7f4d295..0fb6b40 100755 --- a/unit.cpp +++ b/unit.cpp @@ -13,12 +13,13 @@ #include #include "unit.h" +#include "cryoGun.h" #include "weapon.h" #include "util.h" #include "game.h" #include "map.h" #include "vehicle.h" -#include "environment.h" +#include "destructable.h" #include "gameObjectFactory.h" #include "activeGameState.h" #include "gameManager.h" @@ -33,9 +34,15 @@ using namespace gameBase; using namespace std; namespace battleship{ - Unit::Unit(Player *player, int id, Vector3 pos, Quaternion rot, State st) : GameObject(GameObject::Type::UNIT, id, player, pos, rot), state(st){ + //TODO move restartTime to unitData.lua + Unit::Unit(Player *player, int id, Vector3 pos, Quaternion rot, State st) : + GameObject(GameObject::Type::UNIT, id, player, pos, rot), + state(st), + restartTime(2000) + { selectable = true; - restartTime = 2000; + + destructable = new Destructable(this); Unit::initProperties(); initModel(); @@ -46,14 +53,14 @@ namespace battleship{ orientAt(rot); Vector2 size = Vector2(lenHpBar, 10); - hpBackgroundNode = createBar(Vector2::VEC_ZERO, size, Vector4(0, 0, 0, 1)); - hpForegroundNode = createBar(Vector2::VEC_ZERO, size, Vector4(0, 1, 0, 1)); + hpBackgroundNode = destructable->createBar(Vector2::VEC_ZERO, size, Vector4(0, 0, 0, 1)); + hpForegroundNode = destructable->createBar(Vector2::VEC_ZERO, size, Vector4(0, 1, 0, 1)); } Unit::~Unit() { Map::getSingleton()->unblockCells(this); - removeBar(hpBackgroundNode); - removeBar(hpForegroundNode); + destructable->removeBar(hpBackgroundNode); + destructable->removeBar(hpForegroundNode); destroyWeapons(); destroySound(); destroyHitbox(); @@ -73,10 +80,6 @@ namespace battleship{ string name = unitTable["name"]; alignToSurface = unitTable["alignToSurface"].get_or(false); vehicle = unitTable["isVehicle"]; - health += game->calcAbilFromTech(Ability::Type::HEALTH, currTechs, (int)GameObject::type, id); - maxHealth = unitTable["health"]; - - if(health == 0) health = maxHealth; lineOfSight = unitTable["lineOfSight"]; lineOfSight += game->calcAbilFromTech(Ability::Type::LINE_OF_SIGHT, currTechs, (int)GameObject::type, id); unitClass = (UnitClass)unitTable["unitClass"]; @@ -99,27 +102,13 @@ namespace battleship{ for(int i = 0; i < numGarrisonSlots; i++){ Vector2 size = 10 * Vector2::VEC_IJ; Vector2 pos = Vector2(1.5 * size.x * i, 20); - Node *bg = createBar(pos, size, Vector4(0, 0, 0, 1)); - Node *fg = createBar(pos, size, Vector4(0, 1, 0, 1)); + Node *bg = destructable->createBar(pos, size, Vector4(0, 0, 0, 1)); + Node *fg = destructable->createBar(pos, size, Vector4(0, 1, 0, 1)); int category = unitTable[tblName][i + 1]; garrisonSlots.push_back(GarrisonSlot(bg, fg, pos, category)); } } - tblName = "armor"; - sol::optional at = unitTable[tblName]; - - if(at != sol::nullopt){ - string varName = "numArmorTypes"; - SOL_LUA_VIEW.script(varName + " = #" + objType + "[" + to_string(id + 1) + "]." + tblName); - int numArmorTypes = SOL_LUA_VIEW[varName]; - - for(int i = 0; i < numArmorTypes; i++){ - Armor arm = (Armor)unitTable[tblName][i + 1]; - armorTypes.push_back(arm); - } - } - tblName = "buildableUnits"; sol::optional bu = unitTable[tblName]; @@ -153,8 +142,14 @@ namespace battleship{ if(wtOpt != sol::nullopt) wt = unitTable[tblName][i + 1]["type"]; - Weapon *weapon = ((Weapon::Type)wt == Weapon::Type::FREEZER ? new CryoGun(this, unitTable, i) : new Weapon(this, unitTable, i)); - weapons.push_back(weapon); + switch((Weapon::Type)wt){ + case Weapon::Type::FREEZER: + weapons.push_back(new CryoGun(this, unitTable, i)); + break; + default: + weapons.push_back(new Weapon(this, unitTable, i)); + break; + } } } } @@ -226,28 +221,6 @@ namespace battleship{ return false; } - Node* Unit::createBar(Vector2 pos, Vector2 size, Vector4 color){ - Root *root = Root::getSingleton(); - Material *mat = new Material(root->getLibPath() + "gui"); - mat->addBoolUniform("texturingEnabled", false); - mat->addVec4Uniform("diffuseColor", color); - - Quad *quad = new Quad(Vector3(size.x, size.y, 0), false); - quad->setMaterial(mat); - - Node *node = new Node(Vector3(pos.x, pos.y, 0)); - node->attachMesh(quad); - node->setVisible(false); - root->getGuiNode()->attachChild(node); - - return node; - } - - void Unit::removeBar(Node *node){ - Root::getSingleton()->getGuiNode()->dettachChild(node); - delete node; - } - void Unit::launch(Order order){ getWeaponsByOrder(Order::TYPE::LAUNCH)[0]->fire(order); removeOrder(0); @@ -262,10 +235,6 @@ namespace battleship{ return rotSpeed; } - - void Unit::initUnitStats(){ - } - void Unit::renderOrderLine(bool mainPlayerSelecting){ if (!orders.empty() && orders[0].lineId != -1 && mainPlayerSelecting){ bool display = canDisplayOrderLine(); @@ -280,81 +249,56 @@ namespace battleship{ } } - void Unit::targetUnitsAutomatically(){ + //TODO clean up method code + void Unit::autoAttackTargets(){ + if(!orders.empty()) return; + vector players = Game::getSingleton()->getPlayers(); - vector units; + vector targets; for(Player *pl : players) if(!(pl == player || pl->getTeam() == player->getTeam())){ - vector un = pl->getUnits(); - units.insert(units.end(), un.begin(), un.end()); + vector targs = pl->getDestructables(); + targets.insert(targets.end(), targs.begin(), targs.end()); } - if(orders.empty()) - for(Unit *unit : units) - if(unit->getPos().getDistanceFrom(pos) < lineOfSight){ - receiveOrder(Order(Order::TYPE::ATTACK, vector{Order::Target(unit)}, Vector3::VEC_ZERO, -1, false), false); - break; - } + for(GameObject *targ : targets) + if(targ->getPos().getDistanceFrom(pos) < lineOfSight){ + receiveOrder(Order(Order::TYPE::ATTACK, vector{Order::Target(targ)}, Vector3::VEC_ZERO, -1, false), false); + break; + } } void Unit::update() { GameObject::update(); + destructable->update(); if(condition == Condition::EM_JAMMED && getTime() - lastJamTime > restartTime) condition = Condition::ABLE; - if(freezeStatus >= 100) condition = Condition::FROZEN; + if(destructable->getFreezeStatus() >= 100) condition = Condition::FROZEN; + + if(state != State::HOLD_FIRE) + autoAttackTargets(); ActiveGameState *activeState = (ActiveGameState*)GameManager::getSingleton()->getStateManager()->getAppStateByType(AppStateType::ACTIVE_STATE); Player *mainPlayer = (activeState ? activeState->getPlayer() : nullptr); - - if(state != State::HOLD_FIRE) - targetUnitsAutomatically(); - vector selectingPlayers = getSelectingPlayers(); bool mainPlayerSelecting = (find(selectingPlayers.begin(), selectingPlayers.end(), mainPlayer) != selectingPlayers.end()); bool mainPlayerOwner = (player == mainPlayer); bool renderSelectables = (mainPlayerSelecting && mainPlayerOwner); - renderOrderLine(renderSelectables); - executeOrders(); - displayUnitStats(hpForegroundNode, hpBackgroundNode, health, maxHealth, mainPlayerSelecting); + executeOrders(); + destructable->displayStats(hpForegroundNode, hpBackgroundNode, destructable->getHealth(), destructable->getMaxHealth(), mainPlayerSelecting); for(GarrisonSlot &slot : garrisonSlots) - displayUnitStats(slot.foreground, slot.background, (int)((bool)slot.vehicle), (int)true, renderSelectables, slot.offset); - - if (health <= DEATH_HP){ - sol::table tbl = generateView()[getGameObjTableName()][id + 1]["deathFx"]; - FxManager::Fx *fx = FxManager::getSingleton()->initFx(tbl, model, false, pos); - Environment::explode(fx, Environment::Detonation::EXPLOSION, pos); - remove = true; - } + destructable->displayStats(slot.foreground, slot.background, (int)((bool)slot.vehicle), (int)true, renderSelectables, slot.offset); for(Weapon *weapon : weapons) weapon->update(); } - void Unit::displayUnitStats(Node *foreground, Node *background, int currVal, int maxVal, bool render, Vector2 offset) { - foreground->setVisible(render); - background->setVisible(render); - - if(render){ - Vector3 offset3d = Vector3(offset.x, offset.y, 0); - - Quad *bgQuad = (Quad*)background->getMesh(0); - Vector3 size = bgQuad->getSize(); - float shiftedX = screenPos.x - 0.5 * size.x; - background->setPosition(Vector3(shiftedX, screenPos.y, 0) + offset3d); - - Quad *fgQuad = (Quad*)foreground->getMesh(0); - fgQuad->setSize(Vector3((float)currVal / maxVal * size.x, size.y, 0)); - fgQuad->updateVerts(fgQuad->getMeshBase()); - foreground->setPosition(Vector3(shiftedX, screenPos.y, .01) + offset3d); - } - } - //TODO remove order argument from action methods void Unit::executeOrders() { if(orders.empty() || condition != Condition::ABLE) return; @@ -423,16 +367,16 @@ namespace battleship{ } void Unit::attack(Order order){ - vector units; + vector targets; for(Player *pl : Game::getSingleton()->getPlayers()){ - vector un = pl->getUnits(); - units.insert(units.end(), un.begin(), un.end()); + vector targs = pl->getDestructables(); + targets.insert(targets.end(), targs.begin(), targs.end()); } for(Order::Target &target : orders[0].targets) if(target.unit){ - if(find(units.begin(), units.end(), target.unit) != units.end()) + if(find(targets.begin(), targets.end(), target.unit) != targets.end()) break; removeOrder(0); @@ -447,8 +391,11 @@ namespace battleship{ bool Unit::validateOrder(Order order){ switch (order.type) { - case Order::TYPE::ATTACK: - return !getWeaponsByOrder(Order::TYPE::ATTACK).empty(); + case Order::TYPE::ATTACK:{ + GameObject *target = order.targets[0].unit; + bool destructTarg = (!target || (target && target->getDestructable())); + return destructTarg && !getWeaponsByOrder(Order::TYPE::ATTACK).empty(); + } case Order::TYPE::BUILD: return (unitClass == UnitClass::ENGINEER || unitClass == UnitClass::FREEZER); case Order::TYPE::PATROL: diff --git a/unit.h b/unit.h index d9dca9f..29df120 100755 --- a/unit.h +++ b/unit.h @@ -36,15 +36,16 @@ namespace battleship{ class Engineer; class PointDefense; class Projectile; + class GameObject; struct Order { enum class TYPE {ATTACK, BUILD, MOVE, GARRISON, EJECT, PATROL, LAUNCH, SUPPLY, LOAD, UNLOAD, HACK}; struct Target{ - Unit *unit = nullptr; + GameObject *unit = nullptr; vb01::Vector3 pos; Target(){} - Target(Unit *u, vb01::Vector3 p = vb01::Vector3::VEC_ZERO) : unit(u), pos(p){} + Target(GameObject *u, vb01::Vector3 p = vb01::Vector3::VEC_ZERO) : unit(u), pos(p){} }; TYPE type; @@ -100,7 +101,6 @@ namespace battleship{ GarrisonSlot(vb01::Node *bg, vb01::Node *fg, vb01::Vector2 off, int cat, Vehicle *v = nullptr) : background(bg), foreground(fg), offset(off), category(cat), vehicle(v){} }; - enum class Armor {CAST, COMBINED, MECHANIC, SHELL, STEEL}; enum class State {CHASE, STAND_GROUND, HOLD_FIRE}; enum class Condition{ABLE, FROZEN, EM_JAMMED}; @@ -123,15 +123,13 @@ namespace battleship{ 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 const std::vector& getGarrisonSlots(){return garrisonSlots;} inline float getLineOfSight() {return lineOfSight;} inline UnitType getType() {return type;} inline UnitClass getUnitClass() {return unitClass;} - inline void takeDamage(int damage) {health -= damage * (1 + (freezeDmgFactor - 1) * freezeStatus * .01f);} inline int getPlayerId() {return playerId;} - inline int getHealth(){return health;} - inline int getDeathHp(){return DEATH_HP;} inline bool isVehicle(){return vehicle;} inline bool isTargetToTheRight(vb01::Vector3 dir, vb01::Vector3 lv){return lv.getAngleBetween(dir) > vb01::PI / 2;} inline Order getOrder(int i){return orders[i];} @@ -139,8 +137,6 @@ namespace battleship{ inline std::string getGuiScreen(){return guiScreen;} inline BuildableUnit getBuildableUnit(int i){return buildableUnits[i];} inline vb01::Node* getLosLightNode(){return losLightNode;} - inline void setFreezeStatus(int fs){this->freezeStatus = std::clamp(fs, 0, 100);} - inline int getFreezeStatus(){return freezeStatus;} inline Condition getCondition(){return condition;} inline void setCondition(Condition cond){ this->condition = cond; @@ -149,31 +145,30 @@ namespace battleship{ } private: void renderOrderLine(bool); - void updateScreenCoordinates(); void initWeapons(); void destroyWeapons(); bool validateOrder(Order); inline bool canDisplayOrderLine(){return vb01::getTime() - orderLineDispTime < orderVecDispLength;} - const int orderVecDispLength = 2000, DEATH_HP = 0; + const int orderVecDispLength = 2000; sf::SoundBuffer *selectionSfxBuffer; sf::Sound *selectionSfx = nullptr; - vb01::Node *hpBackgroundNode = nullptr, *hpForegroundNode = nullptr, *losLightNode = nullptr; + vb01::Node *losLightNode = nullptr; bool vehicle, currOrderStarted = false, alignToSurface = false; Condition condition = Condition::ABLE; protected: - UnitClass unitClass; UnitType type; + UnitClass unitClass; std::vector orders; std::string guiScreen = ""; - int health = 0, maxHealth, playerId, lenHpBar = 200, freezeStatus = 0, freezeDmgFactor = 10, restartTime; + int playerId, restartTime, lenHpBar = 200; vb01::s64 orderLineDispTime = 0, lastFireTime = 0, lastJamTime = 0; float lineOfSight; - std::vector armorTypes; std::vector weapons; std::vector garrisonSlots; std::vector buildableUnits; State state = State::STAND_GROUND; + vb01::Node *hpBackgroundNode = nullptr, *hpForegroundNode = nullptr; void placeAt(vb01::Vector3); std::vector getSelectingPlayers(); @@ -181,12 +176,11 @@ namespace battleship{ virtual void startCurrentOrder(){currOrderStarted = true;} virtual bool validateLaunchOrder(){return !getWeaponsByOrder(Order::TYPE::LAUNCH).empty();} virtual bool validateGarrisonOrder(Order){return false;} - virtual void targetUnitsAutomatically(); + virtual void autoAttackTargets(); virtual void reinit(); virtual void initProperties(); virtual void destroySound(); virtual void initSound(); - virtual void initUnitStats(); virtual void executeOrders(); virtual void eject(Order); virtual void attack(Order); @@ -199,11 +193,7 @@ namespace battleship{ virtual void hack(Order){} virtual void freeze(Order){} float calculateRotation(vb01::Vector3, float, float); - void removeBar(vb01::Node*); - vb01::Node* createBar(vb01::Vector2, vb01::Vector2, vb01::Vector4); - void displayUnitStats(vb01::Node*, vb01::Node*, int, int, bool, vb01::Vector2 offset = vb01::Vector2::VEC_ZERO); std::vector getWeaponsByOrder(Order::TYPE); - inline std::vector getArmorTypes(){return armorTypes;} }; } diff --git a/vehicle.cpp b/vehicle.cpp index 3226ecd..7b88bd0 100644 --- a/vehicle.cpp +++ b/vehicle.cpp @@ -10,6 +10,7 @@ #include #include "pathfinder.h" +#include "destructable.h" #include "defConfigs.h" #include "structure.h" #include "vehicle.h" @@ -57,7 +58,7 @@ namespace battleship{ } bool Vehicle::validateGarrisonOrder(Order order){ - Unit *targUnit = order.targets[0].unit; + Unit *targUnit = (Unit*)order.targets[0].unit; for(GarrisonSlot slot : targUnit->getGarrisonSlots()) if(!slot.vehicle && slot.category >= garrisonCategory) @@ -259,7 +260,7 @@ namespace battleship{ } void Vehicle::enterGarrisonable(){ - Unit *targUnit = orders[0].targets[0].unit; + Unit *targUnit = (Unit*)orders[0].targets[0].unit; targUnit->updateGarrison(this, true); removeAllPathpoints(); @@ -282,7 +283,7 @@ namespace battleship{ } void Vehicle::garrison(Order order){ - Unit *targUnit = order.targets[0].unit; + Unit *targUnit = (Unit*)order.targets[0].unit; float distToGarrisonable = pos.getDistanceFrom(targUnit->getPos()), garrisonDist = Map::getSingleton()->getCellSize().x; if(distToGarrisonable > garrisonDist) @@ -425,22 +426,18 @@ namespace battleship{ void Vehicle::build(Order order){ if(pathPoints.empty()){ - if(!order.targets[0].unit) - player->addUnit(order.targets[0].unit); - else { - Structure *structure = (Structure*)order.targets[0].unit; - sol::table targTable = generateView()["units"][structure->getId()]; - int costRate = (int)targTable["cost"] / 100, buildRate = (int)targTable["buildTime"] / 100; + Structure *structure = (Structure*)order.targets[0].unit; + 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){ - structure->incrementBuildStatus(); - player->updateResource(ResourceType::REFINEDS, -costRate, true); - lastBuildTime = getTime(); - } - else if(structure->getBuildStatus() >= 100){ - removeOrder(0); - player->incStructuresBuilt(); - } + if(structure->getBuildStatus() < 100 && player->getResource(ResourceType::REFINEDS) >= costRate && getTime() - lastBuildTime > buildRate){ + structure->incrementBuildStatus(); + player->updateResource(ResourceType::REFINEDS, -costRate, true); + lastBuildTime = getTime(); + } + else if(structure->getBuildStatus() >= 100){ + removeOrder(0); + player->incStructuresBuilt(); } } else navigate(0.5 * Map::getSingleton()->getCellSize().x); diff --git a/weapon.cpp b/weapon.cpp index ccaa9d7..3cb84ee 100644 --- a/weapon.cpp +++ b/weapon.cpp @@ -3,10 +3,12 @@ #include #include "map.h" +#include "unit.h" #include "util.h" #include "weapon.h" #include "player.h" #include "fxManager.h" +#include "destructable.h" #include "gameObjectFactory.h" #include "projectile.h" @@ -23,6 +25,7 @@ namespace battleship{ { sol::table weaponTable = unitTable["weapons"][wid + 1]; maxRange = weaponTable["maxRange"]; + maxFireAngle = weaponTable["maxFireAngle"].get_or(.1); orderType = (Order::TYPE)weaponTable["orderType"]; initProjectileData(weaponTable); @@ -48,11 +51,20 @@ namespace battleship{ for(int i = 0; i < numNodes; i++){ sol::table nodeTbl = weaponTable["nodes"][i + 1]; - maxFireAngle = nodeTbl["maxFireAngle"]; - rotSpeed = nodeTbl["rotationSpeed"]; + float rotSpeed = nodeTbl["rotationSpeed"]; + bool vertical = nodeTbl["vertical"]; + + sol::optional angleConstrOpt = nodeTbl["angleConstraint"]; + float angleConstr; + + if(angleConstrOpt != sol::nullopt) + angleConstr = nodeTbl["angleConstraint"]; + else angleConstr = (vertical ? PI / 2 : 0); string name = nodeTbl["name"]; - nodes.push_back(unit->getModel()->findDescendant(name, true)); + Node *node = unit->getModel()->findDescendant(name, true); + + components.push_back(Component(node, rotSpeed, angleConstr, vertical)); } } @@ -106,19 +118,15 @@ namespace battleship{ int numOrders = unit->getNumOrders(); int ordTp = (numOrders > 0 ? (int)unit->getOrder(0).type : -1); - Unit *targUnit = (ordTp != -1 ? unit->getOrder(0).targets[0].unit : nullptr); + GameObject *targDestruct = (ordTp != -1 ? unit->getOrder(0).targets[0].unit : nullptr); if(ordTp == (int)orderType){ - Vector3 targPos = (targUnit ? targUnit->getPos() : unit->getOrder(0).targets[0].pos); + Vector3 targPos = (targDestruct ? targDestruct->getPos() : unit->getOrder(0).targets[0].pos); float targDist = unit->getPos().getDistanceFrom(targPos); - bool withinRange = (minRange <= targDist && targDist <= maxRange); - bool withinAngle = true; - if(!nodes.empty()){ - Vector3 dirVec = nodes[0]->getGlobalAxis(2); - withinAngle = Vector3(dirVec.x, 0, dirVec.z).norm().getAngleBetween((targPos - unit->getPos()).norm()) <= maxFireAngle; - } + Vector3 dirVec = (components.empty() ? unit->getDirVec() : components[components.size() - 1].node->getGlobalAxis(2)); + bool withinAngle = (dirVec.getAngleBetween((targPos - unit->getPos()).norm()) <= maxFireAngle); if((Order::TYPE)ordTp == Order::TYPE::ATTACK && withinRange && withinAngle) fire(unit->getOrder(0)); @@ -128,10 +136,8 @@ namespace battleship{ } void Weapon::useFx(FxManager::Fx *fx, Vector3 targPos, bool fire){ - if(fx && !fire) - FxManager::getSingleton()->addFx(fx); - else if(!fx) - return; + if(fx && !fire) FxManager::getSingleton()->addFx(fx); + else if(!fx) return; fx->toggleComponents(true); @@ -164,17 +170,19 @@ namespace battleship{ } } - void Weapon::updateTargetUnit(Unit *targetUnit){ - targetUnit->takeDamage(damage); - unit->updateGameStats(targetUnit); + void Weapon::updateTarget(GameObject *target){ + target->getDestructable()->takeDamage(damage); + + if(target->getType() == GameObject::Type::UNIT) + unit->getPlayer()->updateGameStats((Unit*)target); } //TODO replace the 'laser' flag literal void Weapon::fire(Order order){ if(!canFire()) return; - Unit *targetUnit = order.targets[0].unit; - Vector3 targPos = (targetUnit ? targetUnit->getPos() : order.targets[0].pos); + GameObject *target = order.targets[0].unit; + Vector3 targPos = (target ? target->getPos() : order.targets[0].pos); if(fireFx) useFx(fireFx, targPos, true); @@ -183,8 +191,7 @@ namespace battleship{ FxManager *fxManager = FxManager::getSingleton(); string fxKey = "unitHitFx"; - if(targetUnit) - updateTargetUnit(targetUnit); + if(target) updateTarget(target); else{ Map *map = Map::getSingleton(); Map::Cell::Type cellType = map->getCells()[map->getCellId(targPos)].type; @@ -211,29 +218,37 @@ namespace battleship{ //TODO improve to allow for vertical alignment void Weapon::trackTarget(Vector3 targPos){ - if(nodes.empty()) return; + for(Component &component : components){ + Vector3 unitPos = unit->getPos(); + Vector3 unitUp = unit->getUpVec(); + Vector3 targDir = (targPos - unitPos).norm(); + Vector3 targDirProj = getVecToPlane(unitPos, targDir, unitUp); - Vector3 unitPos = unit->getPos(); - Vector3 targDir = (targPos - unitPos).norm(); - targDir = getVecToPlane(unitPos, targDir, unit->getUpVec()); + Vector3 nodeDir = component.node->getGlobalAxis(2); - Vector3 dirVec = getVecToPlane(unitPos, nodes[0]->getGlobalAxis(2), unit->getUpVec()); - Vector3 leftVec = nodes[0]->getGlobalAxis(0); - bool negate = (leftVec.getAngleBetween(targDir) < PI / 2); + Vector3 rotAxis; + float rotAngle; - float angle = dirVec.getAngleBetween(targDir); - float rotAngle = (rotSpeed < angle ? rotSpeed : angle); + if(component.vertical){ + float angle1 = targDir.getAngleBetween(targDirProj); + float angle2 = nodeDir.getAngleBetween(getVecToPlane(unitPos, nodeDir, unitUp)); + float angleDiff = angle1 - angle2; + rotAngle = (component.rotSpeed < fabs(angleDiff) ? component.rotSpeed : fabs(angleDiff)) * (angleDiff > 0 ? -1 : 1); - Quaternion rot = Quaternion((negate ? 1 : -1) * rotAngle, Vector3::VEC_J) * nodes[0]->getOrientation(); - nodes[0]->setOrientation(rot); - } + if(angle2 - rotAngle > component.angleConstr) + rotAngle = -(fabs(rotAngle) - (angle2 + fabs(rotAngle) - component.angleConstr)); - CryoGun::CryoGun(Unit *u, sol::table unitTable, int wid) : Weapon(u, unitTable, wid){} + rotAxis = Vector3::VEC_I; + } + else{ + bool negate = (component.node->getGlobalAxis(0).getAngleBetween(targDirProj) < PI / 2); + float angle = nodeDir.getAngleBetween(targDirProj); + rotAngle = (negate ? 1 : -1) * (component.rotSpeed < angle ? component.rotSpeed : angle); + rotAxis = Vector3::VEC_J; + } - void CryoGun::updateTargetUnit(Unit *targetUnit){ - if(canFreeze()){ - targetUnit->setFreezeStatus(targetUnit->getFreezeStatus() + 1); - lastFreezeTime = getTime(); + Quaternion rot = Quaternion(rotAngle, rotAxis) * component.node->getOrientation(); + component.node->setOrientation(rot); } } } diff --git a/weapon.h b/weapon.h index ba4c712..787e22d 100644 --- a/weapon.h +++ b/weapon.h @@ -1,25 +1,38 @@ #ifndef WEAPON_H #define WEAPON_H +#include "unit.h" + #include #include #include #include -#include "unit.h" - namespace vb01{ class Node; } namespace battleship{ class FxManager; + class GameObject; class Weapon{ public: enum class Type{FREEZER = 1}; + struct Component{ + vb01::Node *node = nullptr; + float rotSpeed, angleConstr; + bool vertical; + + Component(vb01::Node *n, float rs, float ac, bool v) : + node(n), + rotSpeed(rs), + angleConstr(ac), + vertical(v) {} + }; + Weapon(Unit*, sol::table, int); ~Weapon(); virtual void update(); @@ -36,13 +49,11 @@ namespace battleship{ Unit *unit = nullptr; Order::TYPE orderType; int id, projId = -1, damage = 0; - float minRange = 0, maxRange, rotSpeed, maxFireAngle; + float minRange = 0, maxRange, maxFireAngle; vb01::s64 lastFireTime = 0; FxManager::Fx *fireFx = nullptr; vb01::Quaternion projRot; vb01::Vector3 projPos; - float horConstraint = 1.57, vertConstraint = 1.57; - std::vector nodes; vb01::Node *projPar = nullptr; static std::string LASER_FLAG; @@ -52,18 +63,9 @@ namespace battleship{ inline bool canFire(){return vb01::getTime() - lastFireTime > rateOfFire;} protected: int rateOfFire; + std::vector components; - virtual void updateTargetUnit(Unit*); - }; - - class CryoGun : public Weapon{ - public: - CryoGun(Unit*, sol::table, int); - private: - vb01::s64 lastFreezeTime = 0; - - void updateTargetUnit(Unit*); - inline bool canFreeze(){return vb01::getTime() - lastFreezeTime > rateOfFire;} + virtual void updateTarget(GameObject*); }; }