diff --git a/Assets/Scripts/GameObjects/Projectiles/projectileData.lua b/Assets/Scripts/GameObjects/Projectiles/projectileData.lua index b172ef2..3b73cde 100644 --- a/Assets/Scripts/GameObjects/Projectiles/projectileData.lua +++ b/Assets/Scripts/GameObjects/Projectiles/projectileData.lua @@ -7,8 +7,6 @@ projectiles = { }, speed = {.5, .06}, rayLength = {1.25, .75}, - pos = {{x = 0, y = 2.44, z = -3.5}, {x = 0, y = -.27, z = 4.6}}, - rot = {{w = .707, x = -.707, y = 0, z = 0}, {w = 1, x = 0, y = 0, z = 0}}, damage = {450, 300}, name = { "Guided missile", diff --git a/Assets/Scripts/GameObjects/Units/unitData.lua b/Assets/Scripts/GameObjects/Units/unitData.lua index f190968..ebdaa84 100644 --- a/Assets/Scripts/GameObjects/Units/unitData.lua +++ b/Assets/Scripts/GameObjects/Units/unitData.lua @@ -1,4 +1,5 @@ --TYPE = {ATTACK = 0, BUILD = 1, MOVE = 2, GARRISON = 3, EJECT = 4, PATROL = 5, LAUNCH = 6}; +WeaponClass = {HITSCAN = 0, SHELL = 1, TORPEDO = 2, CRUISE_MISSILE = 3} UnitClass = { WAR_MECH = 0, TANK = 1, @@ -24,6 +25,29 @@ vehiclePrefix = modelPrefix .. "Units/Vehicles/" structurePrefix = modelPrefix .. "Units/Structures/" units = { + weapons = { + {{hitscan = true, rateOfFire = 100, fireSfx = PATH .. 'Sounds/Units/WarMechs/fire.ogg', damage = 50, maxRange = 3}}, + {{hitscan = true, rateOfFire = 500, fireSfx = PATH .. 'Sounds/Units/Tanks/attack.ogg', damage = 200, maxRange = 20}}, + {{hitscan = true, rateOfFire = 2000, fireSfx = PATH .. 'Sounds/Units/Tanks/attack.ogg', damage = 5000, maxRange = 45}}, + {}, + {}, + {}, + {{hitscan = true, rateOfFire = 200, fireSfx = PATH .. 'Sounds/Units/Cruisers/fire.ogg', damage = 300, maxRange = 15}}, + {{hitscan = true, rateOfFire = 200, fireSfx = PATH .. 'Sounds/Units/Cruisers/fire.ogg', damage = 300, maxRange = 15}}, + {{hitscan = true, rateOfFire = 200, fireSfx = PATH .. 'Sounds/Units/Cruisers/fire.ogg', damage = 300, maxRange = 15}}, + {{hitscan = true, rateOfFire = 200, fireSfx = PATH .. 'Sounds/Units/Cruisers/fire.ogg', damage = 300, maxRange = 15}}, + {}, + { + {hitscan = false, rateOfFire = 500, fireSfx = PATH .. 'Sounds/Units/Submarines/fire.ogg', damage = 200, maxRange = 20, projectile = {id = 1, pos = {x = 0, y = -.27, z = 4.6}, rot = {w = 1, x = 0, y = 0, z = 0}}}, + {hitscan = false, rateOfFire = 500, fireSfx = PATH .. 'Sounds/Units/Submarines/fire.ogg', minRange = 5, maxRange = 30, projectile = {id = 0, pos = {x = 0, y = 2.44, z = -3.5}, rot = {w = .707, x = -.707, y = 0, z = 0}}} + }, + {{hitscan = false, rateOfFire = 500, fireSfx = PATH .. 'Sounds/Units/Submarines/fire.ogg', damage = 200, maxRange = 20, projectile = {id = 1, pos = {x = 0, y = -.27, z = 4.6}, rot = {w = 1, x = 0, y = 0, z = 0}}}}, + {}, + {}, + {}, + {}, + {{hitscan = true, rateOfFire = 500, fireSfx = PATH .. 'Sounds/Units/WarMechs/fire.ogg', damage = 50, maxRange = 10}}, + }, unitClass = { UnitClass.WAR_MECH, UnitClass.TANK, @@ -93,9 +117,6 @@ units = { health = {500, 500, 600, 200, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500}, cost = {500, 600, 200, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500}, - range = {15, 20, 45, 15, 14, 14, 14, 14, 14, 14, 13, 13, 12, 12, 12, 15, 0, 40}, - damage = {15, 120, 250, 15, 14, 14, 13, 13, 12, 12, 15, 15, 100, 100, 100, 100, 100, 100, 100}, - rateOfFire = {50, 2000, 5000, 100, 100, 100, 100, 100, 100, 100, 1000, 1000, 100, 100, 100, 100, 100, 100}, garrisonCapacity = { {}, {}, @@ -664,26 +685,6 @@ units = { PATH .. 'Sounds/Units/Sample/selection.ogg', PATH .. 'Sounds/Units/Sample/selection.ogg', }, - fireSfx = { - PATH .. 'Sounds/Units/WarMechs/fire.ogg', - PATH .. 'Sounds/Units/Tanks/attack.ogg', - PATH .. 'Sounds/Units/Tanks/attack.ogg', - PATH .. 'Sounds/Units/WarMechs/fire.ogg', - PATH .. 'Sounds/Units/WarMechs/fire.ogg', - PATH .. 'Sounds/Units/WarMechs/fire.ogg', - PATH .. 'Sounds/Units/Cruisers/fire.ogg', - PATH .. 'Sounds/Units/Cruisers/fire.ogg', - PATH .. 'Sounds/Units/Cruisers/fire.ogg', - PATH .. 'Sounds/Units/Cruisers/fire.ogg', - PATH .. 'Sounds/Units/WarMechs/fire.ogg', - PATH .. 'Sounds/Units/Submarines/fire.ogg', - PATH .. 'Sounds/Units/Submarines/fire.ogg', - PATH .. 'Sounds/Units/WarMechs/fire.ogg', - PATH .. 'Sounds/Units/WarMechs/fire.ogg', - PATH .. 'Sounds/Units/WarMechs/fire.ogg', - PATH .. 'Sounds/Units/WarMechs/fire.ogg', - PATH .. 'Sounds/Units/WarMechs/fire.ogg', - }, deathSfx = { PATH .. 'Sounds/SFX/Explosions/explosion01.ogg', PATH .. 'Sounds/SFX/Explosions/explosion01.ogg', diff --git a/engineer.h b/engineer.h index a5a0b8e..edf3bbe 100644 --- a/engineer.h +++ b/engineer.h @@ -14,8 +14,9 @@ namespace battleship{ void build(Order); private: vb01::s64 lastIncrementTime = 0; + int buildRate = 100; - bool canIncrementStructureStatus(){return vb01::getTime() - lastIncrementTime > rateOfFire;} + bool canIncrementStructureStatus(){return vb01::getTime() - lastIncrementTime > buildRate;} }; } diff --git a/gameObject.cpp b/gameObject.cpp index 7fc180b..3a64bc5 100644 --- a/gameObject.cpp +++ b/gameObject.cpp @@ -1,6 +1,8 @@ #include "gameObject.h" #include "gameManager.h" #include "defConfigs.h" +#include "unit.h" +#include "player.h" #include @@ -102,13 +104,11 @@ namespace battleship{ root->getRootNode()->attachChild(model); } + //TODO implement death SFX destruction void GameObject::destroySound(){ } - sf::Sound* GameObject::prepareSfx(sf::SoundBuffer *buffer, string key){ - sol::table SOL_LUA_STATE = generateView()[GameObject::getGameObjTableName()]; - string sfxPath = SOL_LUA_STATE[key][id + 1]; - + sf::Sound* GameObject::prepareSfx(sf::SoundBuffer *buffer, string sfxPath){ sf::Sound *sfx = nullptr; if(buffer->loadFromFile(sfxPath.c_str())){ @@ -121,7 +121,8 @@ namespace battleship{ void GameObject::initSound(){ deathSfxBuffer = new sf::SoundBuffer(); - deathSfx = prepareSfx(deathSfxBuffer, "deathSfx"); + string sfxPath = generateView()[getGameObjTableName()]["deathSfx"][id + 1]; + deathSfx = prepareSfx(deathSfxBuffer, sfxPath); } string GameObject::getGameObjTableName(){ @@ -167,4 +168,19 @@ namespace battleship{ float sizeY = cornersOnScreen[bottomMostPointId].y - cornersOnScreen[topMostPointId].y; return Vector2(sizeX, sizeY); } + + 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 3c2b87b..4839e8b 100644 --- a/gameObject.h +++ b/gameObject.h @@ -12,6 +12,7 @@ namespace sf{ namespace battleship{ class Player; + class Unit; class GameObject{ public: @@ -25,6 +26,8 @@ namespace battleship{ void orientAt(vb01::Quaternion); std::string getGameObjTableName(); vb01::Vector2 calculateSelectionRect(); + void updateGameStats(Unit*); + static sf::Sound* prepareSfx(sf::SoundBuffer*, std::string); inline vb01::Vector2 getScreenPos(){return screenPos;} inline vb01::Vector3 getCorner(int i){return corners[i];} inline bool isSelectable(){return selectable;} @@ -53,7 +56,6 @@ namespace battleship{ virtual void destroyHitbox(); virtual void destroySound(); virtual void initSound(); - sf::Sound* prepareSfx(sf::SoundBuffer*, std::string); Type type; int id; diff --git a/pointDefense.cpp b/pointDefense.cpp index d4950ba..8c05e3d 100644 --- a/pointDefense.cpp +++ b/pointDefense.cpp @@ -11,7 +11,7 @@ namespace battleship{ Unit *targUnit = order.targets[0].unit; Vector3 targDir = (targUnit ? targUnit->getPos() : order.targets[0].pos) - pos; - if(targDir.getLength() > range){ + if(targDir.getLength() > weapons[0]->getMaxRange()){ removeOrder(0); return; } @@ -20,8 +20,8 @@ namespace battleship{ if(angleToTarg > .05) rotateTurret(calculateRotation(targDir.norm(), angleToTarg, .1)); - else if(canFire()) - fire(); + else + weapons[0]->fire(order); Unit::attack(order); } diff --git a/submarine.cpp b/submarine.cpp deleted file mode 100644 index 7eecf90..0000000 --- a/submarine.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include "submarine.h" -#include "player.h" -#include "gameObjectFactory.h" - -#include - -namespace battleship{ - using namespace vb01; - using namespace gameBase; - - Submarine::Submarine(Player *player, int id, Vector3 pos, Quaternion rot) : Vehicle(player, id, pos, rot){} - - void Submarine::fire(){ - int projId = 1; - sol::table SOL_STATE_VIEW = generateView()["projectiles"]; - sol::table posTable = SOL_STATE_VIEW["pos"][projId + 1], rotTable = SOL_STATE_VIEW["rot"][projId + 1]; - Vector3 projPos = Vector3(posTable["x"], posTable["y"], posTable["z"]); - projPos = pos + leftVec * projPos.x + upVec * projPos.y + dirVec * projPos.z; - Quaternion projRot = Quaternion(rotTable["w"], rotTable["x"], rotTable["y"], rotTable["z"]) * rot; - - player->addProjectile(GameObjectFactory::createProjectile(this, projId, projPos, projRot)); - Unit::fire(); - } -} diff --git a/submarine.h b/submarine.h deleted file mode 100644 index f593097..0000000 --- a/submarine.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef SUBMARINE_H -#define SUBMARINE_H - -#include "vehicle.h" - -namespace battleship{ - class Submarine : public Vehicle{ - public: - Submarine(Player*, int, vb01::Vector3, vb01::Quaternion); - private: - void fire(); - }; -} - -#endif diff --git a/unit.cpp b/unit.cpp index 78c3b9d..9f006bf 100755 --- a/unit.cpp +++ b/unit.cpp @@ -14,6 +14,7 @@ #include "util.h" #include "game.h" #include "vehicle.h" +#include "gameObjectFactory.h" #include "activeGameState.h" #include "defConfigs.h" #include "pathfinder.h" @@ -24,6 +25,60 @@ using namespace gameBase; using namespace std; namespace battleship{ + Unit::Weapon::Weapon(Unit *u, sol::table weaponTable) : + unit(u), + hitscan(weaponTable["hitscan"]), + rateOfFire(weaponTable["rateOfFire"]), + damage(weaponTable["damage"].get_or(0)), + minRange(weaponTable["minRange"].get_or(0)) + { + maxRange = weaponTable["maxRange"]; + fireSfxBuffer = new sf::SoundBuffer(); + string sfxPath = weaponTable["fireSfx"]; + fireSfx = GameObject::prepareSfx(fireSfxBuffer, sfxPath); + + string projTable = "projectile"; + sol::optional proj = weaponTable[projTable]; + + if(proj != sol::nullopt){ + projId = weaponTable[projTable]["id"]; + sol::table posTable = weaponTable[projTable]["pos"]; + projPos = Vector3(posTable["x"], posTable["y"], posTable["z"]); + sol::table rotTable = weaponTable[projTable]["rot"]; + projRot = Quaternion(rotTable["w"], rotTable["x"], rotTable["y"], rotTable["z"]); + } + } + + Unit::Weapon::~Weapon(){ + if(fireSfx){ + fireSfx->stop(); + delete fireSfx; + delete fireSfxBuffer; + } + } + + void Unit::Weapon::fire(Order order){ + if(!canFire()) return; + + fireSfx->play(); + Unit *targetUnit = order.targets[0].unit; + + if(targetUnit && hitscan){ + targetUnit->takeDamage(damage); + unit->updateGameStats(targetUnit); + } + else if(!hitscan){ + Vector3 leftVec = unit->getLeftVec(); + Vector3 upVec = unit->getUpVec(); + Vector3 dirVec = unit->getDirVec(); + Vector3 p = unit->getPos() + leftVec * projPos.x + upVec * projPos.y + dirVec * projPos.z; + Quaternion r = projRot * unit->getRot(); + unit->getPlayer()->addProjectile(GameObjectFactory::createProjectile(unit, projId, p, r)); + } + + lastFireTime = getTime(); + } + Unit::Unit(Player *player, int id, Vector3 pos, Quaternion rot) : GameObject(GameObject::Type::UNIT, id, player, pos, rot){ this->id = id; this->player = player; @@ -42,6 +97,7 @@ namespace battleship{ destroySound(); destroyHitbox(); destroyModel(); + destroyWeapons(); } void Unit::init(){ @@ -49,6 +105,7 @@ namespace battleship{ initModel(); initHitbox(); initSound(); + initWeapons(); placeAt(pos); orientAt(rot); } @@ -62,9 +119,6 @@ namespace battleship{ health = SOL_LUA_STATE["health"][id + 1]; maxHealth = health; - rateOfFire = SOL_LUA_STATE["rateOfFire"][id + 1]; - range = SOL_LUA_STATE["range"][id + 1]; - damage = SOL_LUA_STATE["damage"][id + 1]; lineOfSight = SOL_LUA_STATE["lineOfSight"][id + 1]; unitClass = (UnitClass)SOL_LUA_STATE["unitClass"][id + 1]; type = (UnitType)SOL_LUA_STATE["unitType"][id + 1]; @@ -89,27 +143,37 @@ namespace battleship{ armorTypes.push_back(arm); } } + + void Unit::initWeapons(){ + sol::state_view SOL_STATE_VIEW = generateView(); + sol::table unitTable = SOL_STATE_VIEW[GameObject::getGameObjTableName()]; + + string varName = "numWeapons", tblName = "weapons"; + SOL_STATE_VIEW.script(varName + " = #units." + tblName + "[" + to_string(id + 1) + "]"); + int numWeapons = SOL_STATE_VIEW[varName]; + + for(int i = 0; i < numWeapons; i++) + weapons.push_back(new Weapon(this, unitTable[tblName][id + 1][i + 1])); + } + + void Unit::destroyWeapons(){ + for(Weapon *weapon : weapons) + delete weapon; + + weapons.clear(); + } void Unit::destroySound(){ selectionSfx->stop(); delete selectionSfx; delete selectionSfxBuffer; - - if(fireSfx){ - fireSfx->stop(); - delete fireSfx; - delete fireSfxBuffer; - } } void Unit::initSound(){ GameObject::initSound(); - selectionSfxBuffer = new sf::SoundBuffer(); - selectionSfx = GameObject::prepareSfx(selectionSfxBuffer, "selectionSfx"); - - fireSfxBuffer = new sf::SoundBuffer(); - fireSfx = prepareSfx(fireSfxBuffer, "fireSfx"); + string sfxPath = generateView()[getGameObjTableName()]["selectionSfx"][id + 1]; + selectionSfx = GameObject::prepareSfx(selectionSfxBuffer, sfxPath); } void Unit::reinit(){ @@ -163,30 +227,6 @@ namespace battleship{ return rotSpeed; } - void Unit::fire(){ - fireSfx->play(); - - Unit *targetUnit = orders[0].targets[0].unit; - - if(targetUnit){ - targetUnit->takeDamage(damage); - - if(targetUnit->getHealth() <= DEATH_HP){ - Player *targUnitPlayer = targetUnit->getPlayer(); - - if(targetUnit->isVehicle()){ - player->incVehiclesDestroyed(); - targUnitPlayer->incVehiclesLost(); - } - else{ - player->incStructuresDestroyed(); - targUnitPlayer->incStructuresLost(); - } - } - } - - lastFireTime = getTime(); - } void Unit::initUnitStats(){ } diff --git a/unit.h b/unit.h index 6b897cc..95be756 100755 --- a/unit.h +++ b/unit.h @@ -60,6 +60,31 @@ namespace battleship{ class Unit : public GameObject{ public: + class Weapon{ + public: + enum class Type{HITSCAN, SHELL, TORPEDO, CRUISE_MISSILE}; + + Weapon(Unit*, sol::table); + ~Weapon(); + virtual void fire(Order); + inline int getRateOfFire(){return rateOfFire;} + inline int getDamage(){return damage;} + inline int getMinRange(){return minRange;} + inline int getMaxRange(){return maxRange;} + inline Unit* getUnit(){return unit;} + private: + bool hitscan; + int projId = -1, rateOfFire, damage = 0, minRange, maxRange; + vb01::Vector3 projPos; + vb01::Quaternion projRot; + vb01::s64 lastFireTime = 0; + Unit *unit = nullptr; + sf::SoundBuffer *fireSfxBuffer; + sf::Sound *fireSfx = nullptr; + + inline bool canFire(){return vb01::getTime() - lastFireTime > rateOfFire;} + }; + struct GarrisonSlot{ Vehicle *vehicle = nullptr; int category; @@ -90,7 +115,6 @@ namespace battleship{ inline PointDefense* toPointDefense(){return (PointDefense*)this;} inline int getNumGarrisonSlots(){return garrisonSlots.size();} inline const std::vector& getGarrisonSlots(){return garrisonSlots;} - inline vb01::Vector3* getPosPtr() {return &pos;} inline float getLineOfSight() {return lineOfSight;} inline vb01::Model* getNode() {return model;} inline UnitType getType() {return type;} @@ -98,12 +122,15 @@ namespace battleship{ inline void takeDamage(int damage) {health -= damage;} inline int getPlayerId() {return playerId;} inline int getHealth(){return health;} + inline int getDeathHp(){return DEATH_HP;} inline bool isVehicle(){return gameBase::generateView()["units"]["isVehicle"][id + 1];} inline bool isTargetToTheRight(vb01::Vector3 dir, vb01::Vector3 lv){return lv.getAngleBetween(dir) > vb01::PI / 2;} private: void renderOrderLine(bool); void updateScreenCoordinates(); void init(); + void initWeapons(); + void destroyWeapons(); inline bool canDisplayOrderLine(){return vb01::getTime() - orderLineDispTime < orderVecDispLength;} const int orderVecDispLength = 2000, DEATH_HP = 0; @@ -114,13 +141,12 @@ namespace battleship{ UnitClass unitClass; UnitType type; std::vector orders; - sf::SoundBuffer *fireSfxBuffer; - sf::Sound *fireSfx = nullptr; - int health, damage, maxHealth, cost, id, playerId, lenHpBar = 200, rateOfFire; + int health, maxHealth, cost, id, playerId, lenHpBar = 200; s64 orderLineDispTime = 0, lastFireTime = 0; - float lineOfSight, range; + float lineOfSight; std::vector garrisonSlots; std::vector armorTypes; + std::vector weapons; std::vector getSelectingPlayers(); void removeOrder(int); @@ -137,11 +163,9 @@ namespace battleship{ virtual void patrol(Order){} virtual void launch(Order){} float calculateRotation(vb01::Vector3, float, float); - virtual void fire(); 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); - inline bool canFire(){return vb01::getTime() - lastFireTime > rateOfFire;} inline std::vector getArmorTypes(){return armorTypes;} }; } diff --git a/vehicle.cpp b/vehicle.cpp index a44f2ed..be2f73c 100644 --- a/vehicle.cpp +++ b/vehicle.cpp @@ -290,7 +290,8 @@ namespace battleship{ Order::Target target = order.targets[0]; Vector3 targVec = (target.unit ? target.unit->getPos() : target.pos) - pos; float distToTarg = targVec.getLength(); - float minDist = range; + Weapon *weapon = weapons[0]; + float minDist = weapon->getMaxRange(); if(distToTarg > minDist) navigateToTarget(.5 * Map::getSingleton()->getCellSize().x); @@ -299,9 +300,9 @@ namespace battleship{ float angleToTarg = targVec.norm().getAngleBetween(dirVec); - if(distToTarg <= range){ - if(angleToTarg <= anglePrecision && canFire()) - fire(); + if(distToTarg <= weapon->getMaxRange()){ + if(angleToTarg <= anglePrecision) + weapon->fire(order); else if(angleToTarg > anglePrecision) turn(calculateRotation(targVec.norm(), angleToTarg, maxTurnAngle)); }