Merge branch 'aa-point-defense' into imp-207-shoot-down-missiles

This commit is contained in:
devZoGok
2025-12-06 16:22:26 +02:00
32 changed files with 502 additions and 297 deletions
+4 -4
View File
@@ -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
@@ -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,
+12 -8
View File
@@ -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 = {
{
+5 -3
View File
@@ -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)
+19 -13
View File
@@ -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();
}
+1 -1
View File
@@ -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();
};
}
+20
View File
@@ -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();
}
}
}
+25
View File
@@ -0,0 +1,25 @@
#ifndef CRYOGUN_H
#define CRYOGUN_H
#include "weapon.h"
#include <util.h>
#include <solUtil.h>
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
+110
View File
@@ -0,0 +1,110 @@
#include "destructable.h"
#include "environment.h"
#include "player.h"
#include "game.h"
#include <root.h>
#include <node.h>
#include <quad.h>
#include <material.h>
#include <solUtil.h>
#include <vector>
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<int> 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<sol::table> 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<sol::table> 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;
}
}
+43
View File
@@ -0,0 +1,43 @@
#ifndef DESTRUCTABLE_H
#define DESTRUCTABLE_H
#include <vector.h>
#include <vector>
#include <algorithm>
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<Armor> getArmorTypes(){return armorTypes;}
inline void setFreezeStatus(int fs){this->freezeStatus = std::clamp(fs, 0, 100);}
inline int getFreezeStatus(){return freezeStatus;}
private:
std::vector<Armor> armorTypes;
const int DEATH_HP = 0;
int health = 0, maxHealth, freezeStatus = 0, freezeDmgFactor = 10;
GameObject *gameObject = nullptr;
void initProperties();
};
}
#endif
+7 -6
View File
@@ -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);
+2 -1
View File
@@ -3,6 +3,7 @@
#include "player.h"
#include "unit.h"
#include "game.h"
#include "destructable.h"
#include <root.h>
#include <node.h>
@@ -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);
+16 -15
View File
@@ -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(){
+3 -6
View File
@@ -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<int> currTechs = player->getTechnologies();
}
int Factory::getNumQueueUnitsById(int unitId){
@@ -60,7 +57,7 @@ namespace battleship{
vector<Player*> 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;
+2 -1
View File
@@ -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);
+5 -2
View File
@@ -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<Order::Target>(
"Target", sol::constructors<Order::Target(), Order::Target(Unit*, Vector3)>(),
"Target", sol::constructors<Order::Target(), Order::Target(GameObject*, Vector3)>(),
"unit", &Order::Target::unit,
"pos", &Order::Target::pos
);
@@ -58,6 +59,7 @@ namespace battleship{
SOL_LUA_STATE.new_usertype<Unit>(
"Unit", sol::constructors<Unit(Player*, int, Vector3, Quaternion)>(),
"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<Structure>(
+1 -15
View File
@@ -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();
}
}
}
}
+4 -1
View File
@@ -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];
+12 -4
View File
@@ -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();
}
}
+1 -1
View File
@@ -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;
+31
View File
@@ -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<GameObject*> Player::getDestructables(){
vector<GameObject*> 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();
}
}
}
}
+2
View File
@@ -37,6 +37,8 @@ namespace battleship{
void addTradeOffer(Player*, TradeOffer*);
std::vector<TradeOffer*> getTradeOffers(Player*);
void deselectUnit(Unit*);
std::vector<GameObject*> 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;}
+4 -1
View File
@@ -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<int> 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);
+2
View File
@@ -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;
+7 -6
View File
@@ -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);
+6 -5
View File
@@ -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<Player*> 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<Structure*> structs){
+6 -5
View File
@@ -1,5 +1,6 @@
#include "structure.h"
#include "activeGameState.h"
#include "destructable.h"
#include <stateManager.h>
@@ -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);
+53 -106
View File
@@ -13,12 +13,13 @@
#include <ext.hpp>
#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<sol::table> 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<sol::table> 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<Player*> players = Game::getSingleton()->getPlayers();
vector<Unit*> units;
vector<GameObject*> targets;
for(Player *pl : players)
if(!(pl == player || pl->getTeam() == player->getTeam())){
vector<Unit*> un = pl->getUnits();
units.insert(units.end(), un.begin(), un.end());
vector<GameObject*> 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>{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>{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<Player*> 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<Unit*> units;
vector<GameObject*> targets;
for(Player *pl : Game::getSingleton()->getPlayers()){
vector<Unit*> un = pl->getUnits();
units.insert(units.end(), un.begin(), un.end());
vector<GameObject*> 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:
+10 -20
View File
@@ -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<GarrisonSlot>& 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<Order> 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<Armor> armorTypes;
std::vector<Weapon*> weapons;
std::vector<GarrisonSlot> garrisonSlots;
std::vector<BuildableUnit> buildableUnits;
State state = State::STAND_GROUND;
vb01::Node *hpBackgroundNode = nullptr, *hpForegroundNode = nullptr;
void placeAt(vb01::Vector3);
std::vector<Player*> 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<Weapon*> getWeaponsByOrder(Order::TYPE);
inline std::vector<Armor> getArmorTypes(){return armorTypes;}
};
}
+15 -18
View File
@@ -10,6 +10,7 @@
#include <quaternion.h>
#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);
+54 -39
View File
@@ -3,10 +3,12 @@
#include <particleEmitter.h>
#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<float> 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);
}
}
}
+18 -16
View File
@@ -1,25 +1,38 @@
#ifndef WEAPON_H
#define WEAPON_H
#include "unit.h"
#include <vector>
#include <util.h>
#include <quaternion.h>
#include <solUtil.h>
#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<vb01::Node*> 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<Component> 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*);
};
}