mirror of
https://github.com/devZoGok/PlanetFleet.git
synced 2026-08-26 19:43:29 +00:00
reordered source files
This commit is contained in:
+180
@@ -0,0 +1,180 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
set(GAME_NAME planetFleet)
|
||||
project(${GAME_NAME})
|
||||
|
||||
option(BUILD_GAME_TESTS "Build game unit tests" OFF)
|
||||
|
||||
set(STATES
|
||||
source/core/appStates/activeGameState.cpp
|
||||
source/core/appStates/inGameAppState.cpp
|
||||
source/core/appStates/guiAppState.cpp
|
||||
source/core/appStates/mapEditorAppState.cpp
|
||||
source/core/appStates/loadingAppState.cpp)
|
||||
|
||||
set(CONSOLE
|
||||
source/core/console/console.cpp
|
||||
source/core/console/abstractCommand.cpp
|
||||
source/core/console/addUnitCommand.cpp
|
||||
source/core/console/addResourceCommand.cpp
|
||||
source/core/console/addTechnologyCommand.cpp
|
||||
source/core/console/toggleDebugCommand.cpp)
|
||||
|
||||
set(GAME_SRC
|
||||
source/core/game/game.cpp
|
||||
source/core/game/gameManager.cpp)
|
||||
|
||||
set(
|
||||
CORE_SRC
|
||||
source/core/pathfinding/pathfinder.cpp
|
||||
source/utils/util.cpp
|
||||
source/Core/defConfigs.cpp
|
||||
source/core/controllers/cameraController.cpp
|
||||
source/core/controllers/gameObjectFrameController.cpp)
|
||||
${STATES} ${CONSOLE} ${PATHFINDING_SRC} ${UTILS_SRC} ${GAME}
|
||||
|
||||
set(UNIT_BUTTONS
|
||||
source/ui/buttons/unitButton.cpp
|
||||
source/ui/buttons/tradeButton.cpp
|
||||
source/ui/buttons/buildButton.cpp
|
||||
source/ui/buttons/trainButton.cpp
|
||||
source/ui/buttons/researchButton.cpp
|
||||
source/ui/buttons/orderButton.cpp
|
||||
source/ui/buttons/stateToggleButton.cpp)
|
||||
|
||||
set(OPTIONS_BUTTONS
|
||||
source/ui/buttons/optionsButton.cpp
|
||||
source/ui/buttons/tabButton.cpp
|
||||
source/ui/buttons/okButton.cpp
|
||||
source/ui/buttons/defaultsButton.cpp)
|
||||
|
||||
set(TRADING_BUTTONS
|
||||
source/ui/buttons/activeStateBackButton.cpp
|
||||
source/ui/buttons/playerTradeButton.cpp
|
||||
source/ui/buttons/tradingScreenButton.cpp
|
||||
source/ui/buttons/offerButton.cpp
|
||||
source/ui/buttons/resourceAmmountButton.cpp)
|
||||
|
||||
set(MENU_BUTTONS
|
||||
source/ui/buttons/mainMenuButton.cpp
|
||||
source/ui/buttons/singlePlayerButton.cpp
|
||||
source/ui/buttons/exitButton.cpp
|
||||
source/ui/buttons/backButton.cpp
|
||||
source/ui/buttons/playButton.cpp)
|
||||
|
||||
set(MAP_EDITOR_BUTTONS
|
||||
source/ui/buttons/mapEditorButton.cpp
|
||||
source/ui/buttons/newMapButton.cpp
|
||||
source/ui/buttons/loadMapButton.cpp
|
||||
source/ui/buttons/exportButton.cpp)
|
||||
|
||||
set(BUTTONS
|
||||
source/ui/buttons/statsButton.cpp
|
||||
source/ui/buttons/activeStateButton.cpp
|
||||
source/ui/buttons/minimapButton.cpp
|
||||
${TRADING_BUTTONS} ${OPTIONS_BUTTONS} ${MENU_BUTTONS}
|
||||
${MAP_EDITOR_BUTTONS} ${UNIT_BUTTONS})
|
||||
|
||||
set(LISTBOXES
|
||||
source/ui/listboxes/skyboxTextureListbox.cpp
|
||||
source/ui/listboxes/landTextureListbox.cpp
|
||||
source/ui/listboxes/gameObjectListbox.cpp
|
||||
source/ui/listboxes/mapListbox.cpp)
|
||||
|
||||
set(GUI_SRC
|
||||
source/gui/tooltip.cpp
|
||||
source/gui/concreteGuiManager.cpp
|
||||
source/gui/gameObjectFrame.cpp
|
||||
${BUTTONS} ${LISTBOXES})
|
||||
|
||||
set(ENVIRONMENT_SRC
|
||||
source/gameplay/Private/environment.cpp
|
||||
source/gameplay/Private/fxManager.cpp
|
||||
source/gameplay/Private/explosion.cpp
|
||||
source/gameplay/Private/map.cpp
|
||||
)
|
||||
|
||||
set(PLAYER_SRC
|
||||
source/gameplay/Private/player.cpp
|
||||
source/gameplay/Private/trader.cpp
|
||||
)
|
||||
|
||||
set(PROJECTILES
|
||||
source/gameplay/projectile.cpp
|
||||
source/gameplay/missile.cpp
|
||||
source/gameplay/cruiseMissile.cpp
|
||||
source/gameplay/shell.cpp
|
||||
source/gameplay/depthCharge.cpp
|
||||
source/gameplay/torpedo.cpp)
|
||||
|
||||
set(VEHICLES
|
||||
source/gameplay/vehicle.cpp
|
||||
source/gameplay/submarine.cpp
|
||||
source/gameplay/engineer.cpp
|
||||
source/gameplay/resourceRover.cpp
|
||||
source/gameplay/freezer.cpp
|
||||
source/gameplay/vessel.cpp)
|
||||
|
||||
set(STRUCTURES
|
||||
source/gameplay/structure.cpp
|
||||
source/gameplay/factory.cpp
|
||||
source/gameplay/pointDefense.cpp
|
||||
source/gameplay/extractor.cpp
|
||||
source/gameplay/researchStruct.cpp
|
||||
source/gameplay/iceSheet.cpp)
|
||||
|
||||
set(UNITS_SRC
|
||||
source/gameplay/unit.cpp
|
||||
source/gameplay/garrisonable.cpp
|
||||
${VEHICLES} ${STRUCTURES}
|
||||
)
|
||||
|
||||
set(GAME_OBJECT_SRC
|
||||
source/gameplay/Private/resourceDeposit.cpp
|
||||
${UNITS} ${PROJECTILES}
|
||||
)
|
||||
|
||||
set(GAMEPLAY_SRC
|
||||
source/gameplay/Private/gameObject.cpp
|
||||
source/gameplay/Private/gameObjectFactory.cpp
|
||||
source/gameplay/Private/tradeCenter.cpp
|
||||
source/gameplay/Private/destructable.cpp
|
||||
source/gameplay/Private/weapon.cpp
|
||||
${ENVIRONMENT_SRC} ${PLAYER_SRC} ${GAME_OBJECT_SRC})
|
||||
|
||||
|
||||
set(GAME_SRC ${CORE_SRC} ${GUI_SRC} ${GAMEPLAY_SRC})
|
||||
|
||||
add_executable(${GAME_NAME} source/core/main.cpp ${GAME_SRC})
|
||||
|
||||
target_include_directories(${GAME_NAME} PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/source/core
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/source/gameplay
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/source/gui
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/source/utils)
|
||||
|
||||
target_link_libraries(${GAME_NAME} PRIVATE vb01 gameBase)
|
||||
|
||||
if(BUILD_GAME_TESTS)
|
||||
if(UNIX)
|
||||
include_directories(/usr/include/cppunit)
|
||||
link_directories(/usr/lib)
|
||||
elseif(WIN32)
|
||||
include_directories("C:/Program Files (x86)/cppunit/include")
|
||||
link_directories("C:/Program Files (x86)/cppunit/lib")
|
||||
endif()
|
||||
|
||||
set(TEST_SRC
|
||||
tests/testMain.cpp
|
||||
tests/pathfinderTest.cpp
|
||||
${GAME_SRC})
|
||||
|
||||
add_executable(battleshipTests ${TEST_SRC})
|
||||
target_include_directories(planetFleetTests PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/source/core
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/source/gameplay
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/source/gui
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/source/utils)
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/source/tests)
|
||||
target_link_libraries(planetFleetTests PRIVATE vb01 gameBase cppunit)
|
||||
endif()
|
||||
@@ -0,0 +1,857 @@
|
||||
#include <root.h>
|
||||
#include <quaternion.h>
|
||||
#include <model.h>
|
||||
#include <material.h>
|
||||
#include <texture.h>
|
||||
#include <quad.h>
|
||||
#include <box.h>
|
||||
#include <text.h>
|
||||
#include <assetManager.h>
|
||||
#include <imageAsset.h>
|
||||
|
||||
#include <stateManager.h>
|
||||
#include <solUtil.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <map>
|
||||
|
||||
#include "activeGameState.h"
|
||||
#include "inGameAppState.h"
|
||||
#include "defConfigs.h"
|
||||
#include "structure.h"
|
||||
#include "game.h"
|
||||
#include "util.h"
|
||||
#include "tooltip.h"
|
||||
#include "gameObjectFrameController.h"
|
||||
#include "gameObjectFactory.h"
|
||||
#include "cameraController.h"
|
||||
#include "unitButton.h"
|
||||
#include "extractor.h"
|
||||
#include "resourceDeposit.h"
|
||||
#include "resourceRover.h"
|
||||
#include "concreteGuiManager.h"
|
||||
|
||||
using namespace vb01;
|
||||
using namespace vb01Gui;
|
||||
using namespace std;
|
||||
|
||||
namespace battleship{
|
||||
using namespace configData;
|
||||
using namespace gameBase;
|
||||
|
||||
ActiveGameState::ActiveGameState(GuiAppState *gs, int plId) : AbstractAppState(
|
||||
AppStateType::ACTIVE_STATE,
|
||||
configData::calcSumBinds(AppStateType::ACTIVE_STATE, true),
|
||||
configData::calcSumBinds(AppStateType::ACTIVE_STATE, false),
|
||||
GameManager::getSingleton()->getPath() + scripts[(int)ScriptFiles::OPTIONS]), guiState(gs), playerId(plId), depth(1){
|
||||
initDragbox();
|
||||
|
||||
mainPlayer = Game::getSingleton()->getPlayer(playerId);
|
||||
}
|
||||
|
||||
ActiveGameState::~ActiveGameState() {
|
||||
removeDragbox();
|
||||
}
|
||||
|
||||
void ActiveGameState::initDragbox(){
|
||||
Root *root = Root::getSingleton();
|
||||
|
||||
Material *mat = new Material(root->getLibPath() + "gui");
|
||||
mat->addBoolUniform("texturingEnabled", false);
|
||||
mat->addBoolUniform("diffuseColorEnabled", false);
|
||||
mat->addVec4Uniform("diffuseColor", Vector4(.5, .5, .5, .5));
|
||||
|
||||
Quad *dragbox = new Quad(Vector3::VEC_ZERO, false);
|
||||
dragbox->setMaterial(mat);
|
||||
dragboxNode = new Node();
|
||||
dragboxNode->attachMesh(dragbox);
|
||||
|
||||
root->getGuiNode()->attachChild(dragboxNode);
|
||||
}
|
||||
|
||||
void ActiveGameState::initCursor(){
|
||||
string basePath = GameManager::getSingleton()->getPath() + "Textures/Icons/Cursors/";
|
||||
sol::state_view SOL_LUA_VIEW = generateView();
|
||||
|
||||
string pt = SOL_LUA_VIEW["pointerTex"],
|
||||
at = SOL_LUA_VIEW["attackTex"],
|
||||
gt = SOL_LUA_VIEW["garrisonTex"],
|
||||
st = SOL_LUA_VIEW["supplyTex"],
|
||||
ht = SOL_LUA_VIEW["hackTex"],
|
||||
ngt = SOL_LUA_VIEW["noGarrisonTex"],
|
||||
nst = SOL_LUA_VIEW["noSupplyTex"],
|
||||
nht = SOL_LUA_VIEW["noHackTex"],
|
||||
p1[]{basePath + pt},
|
||||
p2[]{basePath + at},
|
||||
p3[]{basePath + gt},
|
||||
p4[]{basePath + st},
|
||||
p5[]{basePath + ht},
|
||||
p6[]{basePath + ngt},
|
||||
p7[]{basePath + nst},
|
||||
p8[]{basePath + nht};
|
||||
pointerTex = new Texture(p1, 1, false);
|
||||
attackTex = new Texture(p2, 1, false);
|
||||
garrisonTex = new Texture(p3, 1, false);
|
||||
supplyTex = new Texture(p4, 1, false);
|
||||
hackTex = new Texture(p5, 1, false);
|
||||
noGarrisonTex = new Texture(p6, 1, false);
|
||||
noSupplyTex = new Texture(p7, 1, false);
|
||||
noHackTex = new Texture(p8, 1, false);
|
||||
|
||||
Root *root = Root::getSingleton();
|
||||
Material *mat = new Material(root->getLibPath() + "gui");
|
||||
mat->addBoolUniform("texturingEnabled", true);
|
||||
mat->addTexUniform("diffuseMap", pointerTex, false);
|
||||
|
||||
Quad *quad = new Quad(Vector3(20, 20, 0), false);
|
||||
quad->setMaterial(mat);
|
||||
|
||||
cursorNode = new Node();
|
||||
cursorNode->attachMesh(quad);
|
||||
root->getGuiNode()->attachChild(cursorNode);
|
||||
}
|
||||
|
||||
void ActiveGameState::removeDragbox(){
|
||||
Root::getSingleton()->getRootNode()->dettachChild(dragboxNode);
|
||||
delete dragboxNode;
|
||||
}
|
||||
|
||||
void ActiveGameState::onAttached() {
|
||||
AbstractAppState::onAttached();
|
||||
vector<Button*> buttons = guiButtons;
|
||||
buttons.insert(buttons.end(), unitButtons.begin(), unitButtons.end());
|
||||
|
||||
ConcreteGuiManager::getSingleton()->readLuaScreenScript(
|
||||
"activeGameState.lua",
|
||||
buttons,
|
||||
vector<Listbox*>{},
|
||||
vector<Checkbox*>{},
|
||||
vector<Slider*>{},
|
||||
vector<Textbox*>{},
|
||||
guiRects,
|
||||
guiTexts,
|
||||
"music = generateFactionMusic(" + to_string(mainPlayer->getFaction()) + ")"
|
||||
);
|
||||
|
||||
if(!cursorNode) initCursor();
|
||||
}
|
||||
|
||||
void ActiveGameState::onDettached() {
|
||||
AbstractAppState::onDettached();
|
||||
}
|
||||
|
||||
void ActiveGameState::updateCursor(){
|
||||
Vector2 cursorPos = getCursorPos();
|
||||
cursorNode->setPosition(Vector3(cursorPos.x, cursorPos.y, .8));
|
||||
|
||||
if(mainPlayer->getNumSelectedUnits() > 0){
|
||||
bool ownGameObj = (gameObjHoveredOn && gameObjHoveredOn->getPlayer() == mainPlayer);
|
||||
bool alliedGameObj = (gameObjHoveredOn && !ownGameObj && gameObjHoveredOn->getPlayer()->getTeam() == mainPlayer->getTeam());
|
||||
bool gameObjUnit = (gameObjHoveredOn && gameObjHoveredOn->getType() == GameObject::Type::UNIT);
|
||||
bool gameObjTransport = (gameObjUnit && ((Unit*)gameObjHoveredOn)->getNumGarrisonSlots() > 0);
|
||||
bool canGarrison = true;
|
||||
|
||||
if(gameObjUnit && gameObjTransport)
|
||||
for(int i = 0; i < mainPlayer->getNumSelectedUnits(); i++)
|
||||
if(!((Unit*)gameObjHoveredOn)->canGarrison((Vehicle*)mainPlayer->getSelectedUnit(i))){
|
||||
canGarrison = false;
|
||||
break;
|
||||
}
|
||||
|
||||
vector<TradeOffer*> offers = (gameObjHoveredOn && alliedGameObj ? mainPlayer->getTradeOffers(gameObjHoveredOn->getPlayer()) : vector<TradeOffer*>{});
|
||||
bool tradeResource[NUM_RESOURCES][2], trade = false;
|
||||
|
||||
for(int i = 0; i < NUM_RESOURCES; i++)
|
||||
for(int j = 0; j < 2; j++){
|
||||
if(!offers.empty() && offers[0]->tradeResources[i][j] > 0){
|
||||
tradeResource[i][j] = true;
|
||||
trade = true;
|
||||
}
|
||||
else tradeResource[i][j] = false;
|
||||
}
|
||||
|
||||
int objClass = (gameObjUnit ? int(((Unit*)gameObjHoveredOn)->getUnitClass()) : -1);
|
||||
bool tradeCenter = ((UnitClass)objClass == UnitClass::TRADE_CENTER);
|
||||
bool refinery = ((UnitClass)objClass == UnitClass::REFINERY);
|
||||
bool lab = ((UnitClass)objClass == UnitClass::LAB);
|
||||
bool ownExtractor = (ownGameObj && (UnitClass)objClass == UnitClass::EXTRACTOR);
|
||||
|
||||
bool roverSelected = (mainPlayer->getSelectedUnit(0)->getUnitClass() == UnitClass::RESOURCE_ROVER);
|
||||
ResourceRover *rover = (roverSelected ? (ResourceRover*)mainPlayer->getSelectedUnit(0) : nullptr);
|
||||
int unloadFlag = (int)shiftPressed;
|
||||
|
||||
if(!forceCursorState){
|
||||
if(gameObjUnit && gameObjTransport){
|
||||
orderPossible = (ownGameObj && canGarrison);
|
||||
cursorState = CursorState::GARRISON;
|
||||
}
|
||||
else if(roverSelected && ownExtractor){
|
||||
orderPossible = (((Extractor*)gameObjHoveredOn)->getDeposit()->getAmmount() > 0);
|
||||
cursorState = CursorState::SUPPLY;
|
||||
}
|
||||
else if(roverSelected && (tradeCenter || refinery || lab) && (ownGameObj || (alliedGameObj && trade))){
|
||||
bool tradeRes = false;
|
||||
int resId;
|
||||
|
||||
switch((UnitClass)objClass){
|
||||
case UnitClass::TRADE_CENTER:
|
||||
tradeRes = tradeResource[(int)ResourceType::WEALTH][unloadFlag];
|
||||
resId = (int)ResourceType::WEALTH;
|
||||
break;
|
||||
case UnitClass::REFINERY:
|
||||
tradeRes = tradeResource[(int)ResourceType::REFINEDS][unloadFlag];
|
||||
resId = (int)ResourceType::REFINEDS;
|
||||
break;
|
||||
case UnitClass::LAB:
|
||||
tradeRes = tradeResource[(int)ResourceType::RESEARCH][unloadFlag];
|
||||
resId = (int)ResourceType::RESEARCH;
|
||||
break;
|
||||
}
|
||||
|
||||
bool canLoad = (rover && rover->calcTotalLoad() < rover->getCapacity());
|
||||
orderPossible = (unloadFlag ? rover->getLoad(resId) > 0 : canLoad);
|
||||
|
||||
if(alliedGameObj) orderPossible = tradeRes && orderPossible;
|
||||
|
||||
cursorState = (unloadFlag ? CursorState::UNLOAD : CursorState::LOAD);
|
||||
}
|
||||
else if(gameObjUnit && !(ownGameObj || alliedGameObj)){
|
||||
orderPossible = true;
|
||||
cursorState = CursorState::ATTACK;
|
||||
}
|
||||
else
|
||||
cursorState = CursorState::NORMAL;
|
||||
}
|
||||
else{
|
||||
if(cursorState == CursorState::GARRISON)
|
||||
orderPossible = (ownGameObj && gameObjTransport && canGarrison);
|
||||
else if(cursorState == CursorState::SUPPLY)
|
||||
orderPossible = (roverSelected && ownExtractor);
|
||||
else if(cursorState == CursorState::LOAD || cursorState == CursorState::UNLOAD){
|
||||
int ulf = int(cursorState == CursorState::UNLOAD);
|
||||
bool tradeRefs = tradeResource[(int)ResourceType::REFINEDS][ulf];
|
||||
bool tradeWealth = tradeResource[(int)ResourceType::WEALTH][ulf];
|
||||
bool tradeTech = tradeResource[(int)ResourceType::RESEARCH][ulf];
|
||||
|
||||
bool canLoad = (rover->calcTotalLoad() < rover->getCapacity());
|
||||
bool loadResource = (
|
||||
cursorState == CursorState::LOAD ? canLoad : (
|
||||
rover->getLoad((int)ResourceType::REFINEDS) > 0 ||
|
||||
rover->getLoad((int)ResourceType::WEALTH) > 0 ||
|
||||
rover->getLoad((int)ResourceType::RESEARCH) > 0
|
||||
)
|
||||
);
|
||||
|
||||
bool transferResource = (
|
||||
(refinery && loadResource && (ownGameObj || (alliedGameObj && tradeRefs))) ||
|
||||
(tradeCenter && loadResource && (ownGameObj || (alliedGameObj && tradeWealth))) ||
|
||||
(lab && loadResource && (ownGameObj || (alliedGameObj && tradeTech)))
|
||||
);
|
||||
orderPossible = (roverSelected && transferResource);
|
||||
}
|
||||
else if(cursorState == CursorState::HACK)
|
||||
orderPossible = (!ownGameObj && gameObjUnit && mainPlayer->getSelectedUnit(0)->getUnitClass() == UnitClass::CYBORG_ENGINEER);
|
||||
else if(controlPressed)
|
||||
cursorState = CursorState::ATTACK;
|
||||
else
|
||||
cursorState = CursorState::NORMAL;
|
||||
}
|
||||
}
|
||||
|
||||
cursorNode->setVisible(cursorState != CursorState::NORMAL);
|
||||
Texture *tex = nullptr;
|
||||
|
||||
switch(cursorState){
|
||||
case CursorState::ATTACK:
|
||||
tex = attackTex;
|
||||
break;
|
||||
case CursorState::GARRISON:
|
||||
tex = (orderPossible ? garrisonTex : noGarrisonTex);
|
||||
break;
|
||||
case CursorState::SUPPLY:
|
||||
case CursorState::LOAD:
|
||||
case CursorState::UNLOAD:
|
||||
tex = (orderPossible ? supplyTex : noSupplyTex);
|
||||
break;
|
||||
case CursorState::HACK:
|
||||
tex = (orderPossible ? hackTex : noHackTex);
|
||||
break;
|
||||
}
|
||||
|
||||
cursorNode->getMesh(0)->getMaterial()->setTexUniform("diffuseMap", tex, false);
|
||||
}
|
||||
|
||||
void ActiveGameState::update() {
|
||||
ConcreteGuiManager *guiManager = ConcreteGuiManager::getSingleton();
|
||||
guiManager->getText("refineds")->setText(to_wstring(mainPlayer->getResource(ResourceType::REFINEDS)));
|
||||
guiManager->getText("wealth")->setText(to_wstring(mainPlayer->getResource(ResourceType::WEALTH)));
|
||||
guiManager->getText("research")->setText(to_wstring(mainPlayer->getResource(ResourceType::RESEARCH)));
|
||||
|
||||
updateCursor();
|
||||
Vector2 cursorPos = getCursorPos();
|
||||
|
||||
float eps = .01;
|
||||
|
||||
if(!isSelectionBox && selectMouseClicked && (fabs(clickPoint.x - cursorPos.x) > eps || fabs(clickPoint.y - cursorPos.y) > eps) && getTime() - lastSelectMouseClicked > 10)
|
||||
isSelectionBox = true;
|
||||
else if (isSelectionBox)
|
||||
updateDragBox();
|
||||
|
||||
dragboxNode->setVisible(isSelectionBox);
|
||||
|
||||
updateGameObjHoveredOn();
|
||||
|
||||
vector<Unit*> selectedUnits = mainPlayer->getSelectedUnits();
|
||||
GameObjectFrameController *fc = GameObjectFrameController::getSingleton();
|
||||
|
||||
if(!selectingDestOrient && orderMouseClicked && !selectedUnits.empty() && getTime() - lastOrderMouseClicked > 100){
|
||||
if(targets.empty()) castRayToTerrain();
|
||||
|
||||
if(!buildableStructSelected)
|
||||
for(int i = 0; i < selectedUnits.size(); i++)
|
||||
fc->addGameObjectFrame(GameObjectFrame(selectedUnits[i]->getId(), GameObject::Type::UNIT, mainPlayer, selectedUnits[i], targets[0].pos));
|
||||
|
||||
selectingDestOrient = true;
|
||||
fc->setRotating(true);
|
||||
}
|
||||
else if(selectingDestOrient && !orderMouseClicked){
|
||||
selectingDestOrient = false;
|
||||
|
||||
fc->toggleFrameTransformations(false, false, false);
|
||||
fc->removeGameObjectFrames();
|
||||
}
|
||||
|
||||
if(!tradingScreen){
|
||||
guiTexts = guiManager->getTexts();
|
||||
guiRects = guiManager->getGuiRectangles();
|
||||
guiButtons = guiManager->getButtons();
|
||||
}
|
||||
|
||||
renderUnits();
|
||||
|
||||
vector<Unit*> currSelectedUnits = mainPlayer->getSelectedUnits();
|
||||
|
||||
if(prevSelectedUnits != currSelectedUnits){
|
||||
addUnitGui();
|
||||
prevSelectedUnits = currSelectedUnits;
|
||||
}
|
||||
|
||||
if(fc->isRotating() || fc->isPlacingOnSurface() || fc->isPlacingVertically())
|
||||
fc->update();
|
||||
|
||||
CameraController *camCtr = CameraController::getSingleton();
|
||||
|
||||
if(!camCtr->isLookingAround())
|
||||
camCtr->updateCameraPosition();
|
||||
}
|
||||
|
||||
void ActiveGameState::updateGameObjHoveredOn(){
|
||||
vector<GameObject*> gameObjs;
|
||||
vector<Player*> players = Game::getSingleton()->getPlayers(true);
|
||||
|
||||
for(Player *pl : players){
|
||||
vector<ResourceDeposit*> resDeps = pl->getResourceDeposits();
|
||||
vector<Unit*> units = pl->getUnits();
|
||||
|
||||
for(ResourceDeposit *rd : resDeps)
|
||||
gameObjs.push_back((GameObject*)rd);
|
||||
|
||||
for(Unit *u : units)
|
||||
gameObjs.push_back((GameObject*)u);
|
||||
}
|
||||
|
||||
for(GameObject *gameObj : gameObjs)
|
||||
if(isGameObjSelectable(gameObj, false)){
|
||||
gameObjHoveredOn = gameObj;
|
||||
return;
|
||||
}
|
||||
|
||||
gameObjHoveredOn = nullptr;
|
||||
}
|
||||
|
||||
void ActiveGameState::deselectUnits(){
|
||||
mainPlayer->deselectUnits();
|
||||
GameObjectFrameController *ufCtr = GameObjectFrameController::getSingleton();
|
||||
ufCtr->removeGameObjectFrames();
|
||||
ufCtr->toggleFrameTransformations(false, false, false);
|
||||
|
||||
ConcreteGuiManager::getSingleton()->readLuaScreenScript("activeGameState.lua");
|
||||
}
|
||||
|
||||
bool ActiveGameState::selectedUnitsAmongst(vector<Unit*> units){
|
||||
vector<Unit*> selUnits = mainPlayer->getSelectedUnits();
|
||||
|
||||
for(Unit *unit : units)
|
||||
if(find(selUnits.begin(), selUnits.end(), unit) != selUnits.end())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ActiveGameState::isGameObjSelectable(GameObject *obj, bool useDragBox){
|
||||
if(!obj->getModel()->isVisible()) return false;
|
||||
|
||||
Node *hitboxNode = obj->getHitbox();
|
||||
Box *hitbox = (Box*)hitboxNode->getMesh(0);
|
||||
|
||||
Vector3 hitboxSize = hitbox->getSize();
|
||||
float width = hitboxSize.x, height = hitboxSize.y, length = hitboxSize.z;
|
||||
const int NUM_CORNERS = 8;
|
||||
|
||||
Vector3 corners[NUM_CORNERS]{
|
||||
Vector3(-.5 * width, -.5 * height, -.5 * length),
|
||||
Vector3(-.5 * width, -.5 * height, .5 * length),
|
||||
Vector3(.5 * width, -.5 * height, .5 * length),
|
||||
Vector3(.5 * width, -.5 * height, -.5 * length),
|
||||
Vector3(-.5 * width, .5 * height, -.5 * length),
|
||||
Vector3(-.5 * width, .5 * height, .5 * length),
|
||||
Vector3(.5 * width, .5 * height, .5 * length),
|
||||
Vector3(.5 * width, .5 * height, -.5 * length),
|
||||
};
|
||||
|
||||
Vector2 cornersOnScreen[NUM_CORNERS];
|
||||
Vector3 hitboxOffset = hitboxNode->getPosition();
|
||||
|
||||
for(int i = 0; i < NUM_CORNERS; i++){
|
||||
Vector3 cornerInWorld =
|
||||
obj->getPos() +
|
||||
obj->getLeftVec() * (corners[i].x + hitboxOffset.x) +
|
||||
obj->getUpVec() * (corners[i].y + hitboxOffset.y) +
|
||||
obj->getDirVec() * (corners[i].z + hitboxOffset.z);
|
||||
|
||||
Vector3 screenSpace3d = spaceToScreen3d(cornerInWorld);
|
||||
|
||||
if(fabs(screenSpace3d.z) > 1) return false;
|
||||
|
||||
cornersOnScreen[i] = Vector2(screenSpace3d.x, screenSpace3d.y);
|
||||
}
|
||||
|
||||
vector<Vector2> selectionPoints;
|
||||
Vector3 dragboxOrigin = Vector3::VEC_ZERO, dragboxSize = Vector3::VEC_ZERO;
|
||||
|
||||
if(useDragBox){
|
||||
dragboxOrigin = dragboxNode->getPosition();
|
||||
dragboxSize = ((Quad*)dragboxNode->getMesh(0))->getSize();
|
||||
Vector2 objScreenPos = spaceToScreen(obj->getPos());
|
||||
|
||||
if(
|
||||
(dragboxOrigin.x < objScreenPos.x && objScreenPos.x < dragboxOrigin.x + dragboxSize.x) &&
|
||||
(dragboxOrigin.y < objScreenPos.y && objScreenPos.y < dragboxOrigin.y + dragboxSize.y)
|
||||
)
|
||||
return true;
|
||||
|
||||
selectionPoints = vector<Vector2>{
|
||||
Vector2(dragboxOrigin.x, dragboxOrigin.y),
|
||||
Vector2(dragboxOrigin.x + dragboxSize.x, dragboxOrigin.y),
|
||||
Vector2(dragboxOrigin.x + dragboxSize.x, dragboxOrigin.y + dragboxSize.y),
|
||||
Vector2(dragboxOrigin.x, dragboxOrigin.y + dragboxSize.y)
|
||||
};
|
||||
}
|
||||
else
|
||||
selectionPoints = vector<Vector2>{getCursorPos()};
|
||||
|
||||
int numAboveEdges = 0, numBelowEdges = 0;
|
||||
|
||||
for(int i = 0; i < selectionPoints.size(); i++){
|
||||
const int NUM_EDGES = 12;
|
||||
int edges[NUM_EDGES][2]{{0, 1}, {1, 2}, {2, 3}, {3, 0}, {4, 5}, {5, 6}, {6, 7}, {7, 4}, {0, 4}, {1, 5}, {2, 6}, {3, 7}};
|
||||
|
||||
for(int j = 0; j < NUM_EDGES && (numAboveEdges == 0 || numBelowEdges == 0); j++){
|
||||
Vector2 vertA = cornersOnScreen[edges[j][0]], vertB = cornersOnScreen[edges[j][1]];
|
||||
float edgeHorLen = fabs(vertA.x - vertB.x), edgeVertLen = fabs(vertA.y - vertB.y);
|
||||
|
||||
if(fabs(selectionPoints[i].x - vertA.x) < edgeHorLen && fabs(selectionPoints[i].x - vertB.x) < edgeHorLen){
|
||||
if(vertA.x > selectionPoints[i].x) swap(vertA, vertB);
|
||||
|
||||
float horOffset = (selectionPoints[i].x - vertA.x) / edgeHorLen;
|
||||
float height = vertA.y + (vertA.y < vertB.y ? 1 : -1) * horOffset * edgeVertLen;
|
||||
|
||||
(selectionPoints[i].y > height ? numAboveEdges : numBelowEdges)++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (numAboveEdges > 0 && numBelowEdges > 0);
|
||||
}
|
||||
|
||||
void ActiveGameState::renderUnits() {
|
||||
vector<Unit*> friendlyUnits = mainPlayer->getFriendlyUnits();
|
||||
Game *game = Game::getSingleton();
|
||||
|
||||
for (Player *p : game->getPlayers(true)){
|
||||
vector<Unit*> units = p->getUnits();
|
||||
|
||||
for (Unit *u : units) {
|
||||
if(u->isVehicle() && ((Vehicle*)u)->getGarrisonable()) continue;
|
||||
|
||||
bool unitVisible = (game->isDebug() || mainPlayer->isObjectVisible((GameObject*)u, friendlyUnits));
|
||||
u->getModel()->setVisible(unitVisible);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ActiveGameState::updateDragBox() {
|
||||
Vector2 mousePos = getCursorPos(), dragBoxOrigin, dragBoxEnd;
|
||||
|
||||
if (mousePos.x >= clickPoint.x && mousePos.y >= clickPoint.y) {
|
||||
dragBoxOrigin = Vector2(clickPoint.x, clickPoint.y);
|
||||
dragBoxEnd = Vector2(mousePos.x, mousePos.y);
|
||||
}
|
||||
else if (mousePos.x < clickPoint.x && mousePos.y > clickPoint.y) {
|
||||
dragBoxOrigin = Vector2(mousePos.x, clickPoint.y);
|
||||
dragBoxEnd = Vector2(clickPoint.x, mousePos.y);
|
||||
}
|
||||
else if (mousePos.x >= clickPoint.x && mousePos.y < clickPoint.y) {
|
||||
dragBoxOrigin = Vector2(clickPoint.x, mousePos.y);
|
||||
dragBoxEnd = Vector2(mousePos.x, clickPoint.y);
|
||||
}
|
||||
else {
|
||||
dragBoxOrigin = Vector2(mousePos.x, mousePos.y);
|
||||
dragBoxEnd = Vector2(clickPoint.x, clickPoint.y);
|
||||
}
|
||||
|
||||
Vector3 size = Vector3(dragBoxEnd.x - dragBoxOrigin.x, dragBoxEnd.y - dragBoxOrigin.y, 0);
|
||||
Quad *dragbox = (Quad*)dragboxNode->getMesh(0);
|
||||
dragbox->setSize(size);
|
||||
dragbox->updateVerts(dragbox->getMeshBase());
|
||||
dragboxNode->setPosition(Vector3(dragBoxOrigin.x, dragBoxOrigin.y, 0));
|
||||
}
|
||||
|
||||
//TODO fix ejectable unit selection with multiple transports selected
|
||||
//TODO replace shiftPressed with a dedicated buy flag
|
||||
void ActiveGameState::issueOrder(Order::TYPE type, vector<Order::Target> targets, bool addOrder) {
|
||||
depth = 1;
|
||||
Vector3 destDir = Vector3::VEC_ZERO;
|
||||
|
||||
if(selectingDestOrient){
|
||||
GameObjectFrame &objFrame = GameObjectFrameController::getSingleton()->getGameObjectFrame(0);
|
||||
destDir = objFrame.getDirVec();
|
||||
targets[0].pos = objFrame.getPos();
|
||||
}
|
||||
|
||||
mainPlayer->issueOrder(type, destDir, targets, addOrder);
|
||||
this->targets.clear();
|
||||
|
||||
if(cursorState != CursorState::ATTACK)
|
||||
forceCursorState = false;
|
||||
}
|
||||
|
||||
void ActiveGameState::castRayToTerrain() {
|
||||
Camera *cam = Root::getSingleton()->getCamera();
|
||||
Vector3 camPos = cam->getPosition();
|
||||
Vector3 endPos = screenToSpace(getCursorPos());
|
||||
|
||||
Vector3 rayDir = (endPos - camPos).norm();
|
||||
Map *map = Map::getSingleton();
|
||||
vector<RayCaster::CollisionResult> results = map->raycastTerrain(camPos, rayDir, true);
|
||||
|
||||
if(!results.empty())
|
||||
targets.push_back(Order::Target(nullptr, results[0].pos));
|
||||
}
|
||||
|
||||
void ActiveGameState::enableUnitState(Unit::State state){
|
||||
vector<Unit*> selectedUnits = mainPlayer->getSelectedUnits();
|
||||
|
||||
for(Unit *unit : selectedUnits)
|
||||
unit->setState(state);
|
||||
}
|
||||
|
||||
void ActiveGameState::addUnitGui(){
|
||||
vector<Unit*> currSelectedUnits = mainPlayer->getSelectedUnits();
|
||||
|
||||
if(currSelectedUnits.empty()) return;
|
||||
|
||||
ConcreteGuiManager *guiManager = ConcreteGuiManager::getSingleton();
|
||||
|
||||
sol::state_view SOL_LUA_VIEW = generateView();
|
||||
SOL_LUA_VIEW.script("_mainUnitId = " + to_string(currSelectedUnits[0]->getId()));
|
||||
guiManager->readLuaScreenScriptDel("unitGui.lua", unitButtons);
|
||||
|
||||
SOL_LUA_VIEW.script("numGui = #gui");
|
||||
int numButtons = SOL_LUA_VIEW["numGui"];
|
||||
|
||||
for(int i = 0; i < numButtons; i++)
|
||||
unitButtons.push_back(guiManager->getButtons()[guiManager->getButtons().size() - (i + 1)]);
|
||||
}
|
||||
|
||||
void ActiveGameState::onAction(int bind, bool isPressed) {
|
||||
if(tradingScreen || !ConcreteGuiManager::getSingleton()->findClickedButtons().empty()) return;
|
||||
|
||||
GameObjectFrameController *ufCtr = GameObjectFrameController::getSingleton();
|
||||
vector<Unit*> selectedUnits = mainPlayer->getSelectedUnits();
|
||||
|
||||
switch((Bind)bind){
|
||||
case Bind::DRAG_BOX:
|
||||
selectMouseClicked = isPressed;
|
||||
|
||||
if(isPressed){
|
||||
clickPoint = getCursorPos();
|
||||
lastSelectMouseClicked = getTime();
|
||||
}
|
||||
else{
|
||||
if(!shiftPressed) deselectUnits();
|
||||
|
||||
if(canSelectHoveredOnGameObj())
|
||||
mainPlayer->selectUnit((Unit*)gameObjHoveredOn);
|
||||
|
||||
selectingDestOrient = false;
|
||||
|
||||
if(isSelectionBox){
|
||||
if(!shiftPressed) deselectUnits();
|
||||
|
||||
vector<Unit*> units = mainPlayer->getUnits();
|
||||
|
||||
for(Unit *un : units)
|
||||
if(isGameObjSelectable(un, true))
|
||||
mainPlayer->selectUnit(un);
|
||||
}
|
||||
|
||||
isSelectionBox = false;
|
||||
Quad *quad = (Quad*)dragboxNode->getMesh(0);
|
||||
quad->setSize(Vector3::VEC_ZERO);
|
||||
quad->updateVerts(quad->getMeshBase());
|
||||
|
||||
ufCtr->toggleFrameTransformations(false, false, false);
|
||||
ufCtr->removeGameObjectFrames();
|
||||
}
|
||||
|
||||
break;
|
||||
case Bind::ROTATE_OBJ_FRAME:
|
||||
orderMouseClicked = isPressed;
|
||||
|
||||
if(isPressed)
|
||||
lastOrderMouseClicked = getTime();
|
||||
else if(!(isPressed || selectedUnits.empty())){
|
||||
if(selectingPatrolPoints){
|
||||
castRayToTerrain();
|
||||
|
||||
if(!(targets.empty() || selectingPatrolPoints)){
|
||||
Order::TYPE type = Order::TYPE::MOVE;
|
||||
|
||||
if(controlPressed || (targets[0].unit && targets[0].unit->getPlayer()->getTeam() != mainPlayer->getTeam()))
|
||||
type = Order::TYPE::ATTACK;
|
||||
else if(ufCtr->isPlacingOnSurface() && !selectingDestOrient)
|
||||
type = Order::TYPE::BUILD;
|
||||
|
||||
issueOrder(type, targets, shiftPressed);
|
||||
}
|
||||
}
|
||||
else if(!isSelectionBox){
|
||||
bool ownGameObj = (gameObjHoveredOn && gameObjHoveredOn->getPlayer()->getTeam() == mainPlayer->getTeam());
|
||||
|
||||
if(cursorState == CursorState::GARRISON){
|
||||
if(orderPossible) issueOrder(Order::TYPE::GARRISON, vector<Order::Target>{Order::Target((Unit*)gameObjHoveredOn, gameObjHoveredOn->getPos())}, shiftPressed);
|
||||
}
|
||||
else if(cursorState == CursorState::SUPPLY){
|
||||
if(orderPossible) issueOrder(Order::TYPE::SUPPLY, vector<Order::Target>{Order::Target((Unit*)gameObjHoveredOn)}, shiftPressed);
|
||||
}
|
||||
else if(cursorState == CursorState::LOAD){
|
||||
if(orderPossible) issueOrder(Order::TYPE::LOAD, vector<Order::Target>{Order::Target((Unit*)gameObjHoveredOn)}, shiftPressed);
|
||||
}
|
||||
else if(cursorState == CursorState::UNLOAD){
|
||||
if(orderPossible) issueOrder(Order::TYPE::UNLOAD, vector<Order::Target>{Order::Target((Unit*)gameObjHoveredOn)}, shiftPressed);
|
||||
}
|
||||
else if(cursorState == CursorState::ATTACK){
|
||||
if(controlPressed && !gameObjHoveredOn){
|
||||
castRayToTerrain();
|
||||
issueOrder(Order::TYPE::ATTACK, targets, shiftPressed);
|
||||
}
|
||||
else{
|
||||
if(orderPossible) issueOrder(Order::TYPE::ATTACK, vector<Order::Target>{Order::Target((Unit*)gameObjHoveredOn, gameObjHoveredOn->getPos())}, shiftPressed);
|
||||
}
|
||||
}
|
||||
else if(cursorState == CursorState::HACK){
|
||||
if(orderPossible) issueOrder(Order::TYPE::HACK, vector<Order::Target>{Order::Target((Unit*)gameObjHoveredOn)}, shiftPressed);
|
||||
}
|
||||
else if(ufCtr->isPlacingOnSurface()){
|
||||
Order::TYPE type;
|
||||
|
||||
switch(selectedUnits[0]->getUnitClass()){
|
||||
case UnitClass::ROBO_ENGINEER:
|
||||
case UnitClass::CYBORG_ENGINEER:
|
||||
case UnitClass::FREEZER:
|
||||
type = Order::TYPE::BUILD;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
targets.clear();
|
||||
|
||||
for(int i = 0; i < ufCtr->getNumGameObjectFrames(); i++){
|
||||
GameObjectFrame gmObjFr = ufCtr->getGameObjectFrame(i);
|
||||
|
||||
if(gmObjFr.status == GameObjectFrame::BLOCKED_BY_DIFF_TERR) continue;
|
||||
|
||||
Unit *buildStruct = GameObjectFactory::createUnit(mainPlayer, gmObjFr.getId(), gmObjFr.getPos(), gmObjFr.getRot());
|
||||
issueOrder(type, vector<Order::Target>{Order::Target(buildStruct, gmObjFr.getPos())}, shiftPressed);
|
||||
}
|
||||
|
||||
buildableStructSelected = false;
|
||||
}
|
||||
else{
|
||||
if(targets.empty()) castRayToTerrain();
|
||||
|
||||
issueOrder(Order::TYPE::MOVE, targets, shiftPressed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case Bind::MOVE_CAMERA:
|
||||
break;
|
||||
case Bind::ENABLE_CHASE_STATE:
|
||||
if(isPressed) enableUnitState(Unit::State::CHASE);
|
||||
break;
|
||||
case Bind::ENABLE_STAND_GROUND_STATE:
|
||||
if(isPressed) enableUnitState(Unit::State::STAND_GROUND);
|
||||
break;
|
||||
case Bind::ENABLE_HOLD_FIRE_STATE:
|
||||
if(isPressed) enableUnitState(Unit::State::HOLD_FIRE);
|
||||
break;
|
||||
case Bind::EJECT_GARRISON:
|
||||
if(isPressed) issueOrder(Order::TYPE::EJECT, vector<Order::Target>{}, shiftPressed);
|
||||
break;
|
||||
case Bind::LAUNCH:
|
||||
if(isPressed){
|
||||
castRayToTerrain();
|
||||
issueOrder(Order::TYPE::LAUNCH, targets, shiftPressed);
|
||||
}
|
||||
|
||||
break;
|
||||
/*
|
||||
case Bind::HACK:
|
||||
if(isPressed){
|
||||
if(gameObjHoveredOn && gameObjHoveredOn->getType() == GameObject::Type::UNIT && gameObjHoveredOn->getPlayer()->getTeam() != mainPlayer->getTeam())
|
||||
issueOrder(Order::TYPE::HACK, vector<Order::Target>{Order::Target((Unit*)gameObjHoveredOn)}, shiftPressed);
|
||||
|
||||
break;
|
||||
}
|
||||
*/
|
||||
case Bind::SHIFT_SUB_DEPTH:
|
||||
ufCtr->toggleFrameTransformations(false, false, isPressed);
|
||||
break;
|
||||
case Bind::ZOOM_IN:
|
||||
if (zooms > -NUM_MAX_ZOOMS) {
|
||||
Camera *cam = Root::getSingleton()->getCamera();
|
||||
cam->setPosition(cam->getPosition() + cam->getDirection().norm() * .5f);
|
||||
zooms--;
|
||||
}
|
||||
break;
|
||||
case Bind::ZOOM_OUT:
|
||||
if (zooms < NUM_MAX_ZOOMS) {
|
||||
Camera *cam = Root::getSingleton()->getCamera();
|
||||
cam->setPosition(cam->getPosition() - (cam->getDirection().norm() * .5f));
|
||||
zooms++;
|
||||
}
|
||||
break;
|
||||
case Bind::LOOK_AROUND:
|
||||
if(!ufCtr->isPlacingOnSurface())
|
||||
CameraController::getSingleton()->setLookingAround(isPressed);
|
||||
break;
|
||||
case Bind::HALT:
|
||||
if(isPressed) mainPlayer->haltUnits();
|
||||
break;
|
||||
//TODO reimplement submarine diving mechanic
|
||||
case Bind::LEFT_CONTROL:
|
||||
if(isPressed) cursorState = CursorState::ATTACK;
|
||||
|
||||
forceCursorState = isPressed;
|
||||
controlPressed = isPressed;
|
||||
orderPossible = isPressed;
|
||||
break;
|
||||
case Bind::LEFT_SHIFT:
|
||||
{
|
||||
shiftPressed = isPressed;
|
||||
|
||||
ufCtr->setPaintSelecting(shiftPressed);
|
||||
|
||||
if(isPressed){
|
||||
Vector3 startPos = Root::getSingleton()->getCamera()->getPosition();
|
||||
vector<RayCaster::CollisionResult> results = Map::getSingleton()->raycastTerrain(startPos, (screenToSpace(getCursorPos()) - startPos).norm(), true);
|
||||
|
||||
if(!results.empty())
|
||||
ufCtr->setPaintSelectRowStart(results[0].pos);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Bind::SELECT_PATROL_POINTS:
|
||||
/*
|
||||
if(isPressed && mainPlayer->getNumSelectedUnits() > 0){
|
||||
targets.push_back(Order::Target(nullptr, mainPlayer->getSelectedUnit(0)->getPos()));
|
||||
selectingPatrolPoints = isPressed;
|
||||
}
|
||||
*/
|
||||
|
||||
break;
|
||||
case Bind::GROUP_0:
|
||||
case Bind::GROUP_1:
|
||||
case Bind::GROUP_2:
|
||||
case Bind::GROUP_3:
|
||||
case Bind::GROUP_4:
|
||||
case Bind::GROUP_5:
|
||||
case Bind::GROUP_6:
|
||||
case Bind::GROUP_7:
|
||||
case Bind::GROUP_8:
|
||||
case Bind::GROUP_9:
|
||||
if(isPressed){
|
||||
int group = bind - Bind::GROUP_0;
|
||||
|
||||
if(controlPressed)
|
||||
unitGroups[group] = mainPlayer->getSelectedUnits();
|
||||
else{
|
||||
if(!shiftPressed)
|
||||
mainPlayer->selectUnits(unitGroups[group]);
|
||||
else
|
||||
for(Unit *u : unitGroups[group])
|
||||
mainPlayer->selectUnit(u);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case Bind::DESELECT_STRUCTURE:
|
||||
forceCursorState = false;
|
||||
buildableStructSelected = false;
|
||||
ufCtr->toggleFrameTransformations(false, false, false);
|
||||
ufCtr->removeGameObjectFrames();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ActiveGameState::onAnalog(int bind, float strength) {
|
||||
CameraController *camCtr = CameraController::getSingleton();
|
||||
GameObjectFrameController *ufCtr = GameObjectFrameController::getSingleton();
|
||||
|
||||
switch((Bind)bind){
|
||||
case Bind::LOOK_UP:
|
||||
case Bind::LOOK_DOWN:
|
||||
if(camCtr->isLookingAround()) {
|
||||
Vector3 dirProj = Root::getSingleton()->getCamera()->getDirection();
|
||||
dirProj = Vector3(dirProj.x, 0, dirProj.z).norm();
|
||||
CameraController::getSingleton()->orientCamera(Vector3(0, 1, 0).cross(dirProj), strength);
|
||||
}
|
||||
else if(ufCtr->isPlacingVertically()){
|
||||
depth -= .2 * strength;
|
||||
|
||||
if(depth < 0) depth = 0;
|
||||
else if(depth > 1) depth = 1;
|
||||
}
|
||||
|
||||
break;
|
||||
case Bind::LOOK_LEFT:
|
||||
case Bind::LOOK_RIGHT:
|
||||
if(camCtr->isLookingAround())
|
||||
CameraController::getSingleton()->orientCamera(Vector3(0, 1, 0), strength);
|
||||
else if(ufCtr->isRotating())
|
||||
ufCtr->rotateGameObjectFrames(100 * strength);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ActiveGameState::onRawMouseWheelScroll(bool up){
|
||||
CameraController::getSingleton()->zoomCamera(up);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
#ifndef ACTIVE_GAME_STATE_H
|
||||
#define ACTIVE_GAME_STATE_H
|
||||
|
||||
#include "guiAppState.h"
|
||||
#include "player.h"
|
||||
#include "map.h"
|
||||
#include "unit.h"
|
||||
|
||||
#include <util.h>
|
||||
|
||||
namespace vb01{
|
||||
class Node;
|
||||
class Texture;
|
||||
}
|
||||
|
||||
namespace vb01Gui{
|
||||
class Button;
|
||||
}
|
||||
|
||||
namespace battleship{
|
||||
class GameObject;
|
||||
class Unit;
|
||||
class UnitButton;
|
||||
|
||||
class ActiveGameState : public gameBase::AbstractAppState {
|
||||
public:
|
||||
enum CursorState{
|
||||
NORMAL,
|
||||
ATTACK,
|
||||
GARRISON,
|
||||
SUPPLY,
|
||||
LOAD,
|
||||
UNLOAD,
|
||||
HACK
|
||||
};
|
||||
|
||||
ActiveGameState(GuiAppState*, int);
|
||||
~ActiveGameState();
|
||||
void onAttached();
|
||||
void onDettached();
|
||||
void update();
|
||||
void onAction(int, bool);
|
||||
void onAnalog(int, float);
|
||||
void onRawMouseWheelScroll(bool);
|
||||
inline CursorState getCursorState(){return cursorState;}
|
||||
inline void setCursorState(CursorState cs){this->cursorState = cs;}
|
||||
inline void addButton(vb01Gui::Button *b){guiButtons.push_back(b);}
|
||||
inline std::vector<vb01Gui::Button*> getGuiButtons(){return guiButtons;}
|
||||
inline std::vector<vb01::Node*> getGuiRects(){return guiRects;}
|
||||
inline std::vector<vb01::Text*> getGuiTexts(){return guiTexts;}
|
||||
inline Player* getPlayer(){return mainPlayer;}
|
||||
inline std::vector<Unit*>& getUnitGroup(int i){return unitGroups[i];}
|
||||
inline void setBuildableStructSelected(bool bss){this->buildableStructSelected = bss;}
|
||||
inline bool isBuildableStructSelected(){return buildableStructSelected;}
|
||||
inline float getDepth(){return depth;}
|
||||
inline void setForceCursorState(bool force){this->forceCursorState = force;}
|
||||
inline bool isForceCursorState(){return forceCursorState;}
|
||||
inline void setTradingScreen(bool ts){this->tradingScreen = ts;}
|
||||
inline bool isTradingScreen(){return tradingScreen;}
|
||||
inline void setOfferScreen(bool os){this->offerScreen = os;}
|
||||
inline bool isOfferScreen(){return offerScreen;}
|
||||
private:
|
||||
bool selectedUnitsAmongst(std::vector<Unit*>);
|
||||
void updateGameObjHoveredOn();
|
||||
void initCursor();
|
||||
void updateCursor();
|
||||
void initDragbox();
|
||||
void removeDragbox();
|
||||
bool isGameObjSelectable(GameObject*, bool);
|
||||
void deselectUnits();
|
||||
void renderUnits();
|
||||
void updateDragBox();
|
||||
void updateStructureFrames();
|
||||
void castRayToTerrain();
|
||||
void issueOrder(Order::TYPE, std::vector<Order::Target>, bool);
|
||||
void enableUnitState(Unit::State);
|
||||
void addUnitGui();
|
||||
inline bool canSelectHoveredOnGameObj(){return gameObjHoveredOn && gameObjHoveredOn->isSelectable() && gameObjHoveredOn->getPlayer() == mainPlayer;}
|
||||
|
||||
CursorState cursorState = CursorState::NORMAL;
|
||||
Player *mainPlayer;
|
||||
GuiAppState *guiState;
|
||||
GameObject *gameObjHoveredOn = nullptr;
|
||||
vb01::Vector2 clickPoint;
|
||||
std::vector<Unit*> unitGroups[9], prevSelectedUnits;
|
||||
std::vector<Order::Target> targets;
|
||||
vb01::Node *dragboxNode = nullptr;
|
||||
std::vector<vb01::Node*> guiRects;
|
||||
std::vector<vb01::Text*> guiTexts;
|
||||
std::vector<vb01Gui::Button*> guiButtons, unitButtons;
|
||||
bool isSelectionBox = false;
|
||||
bool shiftPressed = false;
|
||||
bool controlPressed = false;
|
||||
bool selectMouseClicked = false;
|
||||
bool orderMouseClicked = false;
|
||||
bool buildableStructSelected = false;
|
||||
bool selectingPatrolPoints = false;
|
||||
bool selectingDestOrient = false;
|
||||
bool forceCursorState = false;
|
||||
bool orderPossible = false;
|
||||
bool tradingScreen = false;
|
||||
bool offerScreen = false;
|
||||
int playerId, zooms = 0;
|
||||
const int NUM_MAX_ZOOMS = 10;
|
||||
float depth = 1;
|
||||
vb01::s64 lastSelectMouseClicked = 0, lastOrderMouseClicked = 0;
|
||||
vb01::Node *cursorNode = nullptr;
|
||||
vb01::Texture *pointerTex = nullptr, *attackTex = nullptr, *garrisonTex = nullptr, *noGarrisonTex = nullptr, *supplyTex = nullptr, *noSupplyTex = nullptr, *hackTex = nullptr, *noHackTex = nullptr;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,119 @@
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
|
||||
#include <vector.h>
|
||||
#include <util.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "defConfigs.h"
|
||||
#include "gameManager.h"
|
||||
#include "concreteGuiManager.h"
|
||||
#include "guiAppState.h"
|
||||
|
||||
using namespace gameBase;
|
||||
using namespace vb01;
|
||||
using namespace vb01Gui;
|
||||
using namespace std;
|
||||
|
||||
namespace battleship{
|
||||
using namespace configData;
|
||||
|
||||
GuiAppState::GuiAppState() : AbstractAppState(
|
||||
AppStateType::GUI_STATE,
|
||||
configData::calcSumBinds(AppStateType::GUI_STATE, true),
|
||||
configData::calcSumBinds(AppStateType::GUI_STATE, false),
|
||||
GameManager::getSingleton()->getPath() + scripts[(int)ScriptFiles::OPTIONS]){
|
||||
}
|
||||
|
||||
GuiAppState::~GuiAppState() {}
|
||||
|
||||
void GuiAppState::update() {
|
||||
ConcreteGuiManager::getSingleton()->update();
|
||||
}
|
||||
|
||||
void GuiAppState::onAttached() {
|
||||
AbstractAppState::onAttached();
|
||||
}
|
||||
|
||||
void GuiAppState::onDettached() {
|
||||
AbstractAppState::onDettached();
|
||||
}
|
||||
|
||||
void GuiAppState::onAction(int bind, bool isPressed) {
|
||||
ConcreteGuiManager *guiManager = ConcreteGuiManager::getSingleton();
|
||||
|
||||
switch((Bind)bind){
|
||||
case Bind::LEFT_CLICK:
|
||||
leftMousePressed = isPressed;
|
||||
|
||||
if(isPressed)
|
||||
guiManager->updateGui();
|
||||
|
||||
break;
|
||||
case Bind::SCROLLING_UP:{
|
||||
Listbox *l = getOpenListbox();
|
||||
if(l) l->scrollUp();
|
||||
break;
|
||||
}
|
||||
case Bind::SCROLLING_DOWN:{
|
||||
Listbox *l = getOpenListbox();
|
||||
if(l) l->scrollDown();
|
||||
break;
|
||||
}
|
||||
case Bind::DELETE_CHAR:{
|
||||
Textbox *t = getOpenTextbox();
|
||||
if(t)t->setDeleteCharacters(isPressed);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GuiAppState::onRawKeyPress(int ch){
|
||||
for(Button *b : ConcreteGuiManager::getSingleton()->getButtons())
|
||||
if(b->getTrigger() == ch){
|
||||
b->onClick();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GuiAppState::onRawCharPress(u32 codepoint){
|
||||
Textbox *currentTextbox = getOpenTextbox();
|
||||
|
||||
if(currentTextbox)
|
||||
currentTextbox->type(codepoint);
|
||||
}
|
||||
|
||||
void GuiAppState::onRawMousePress(int trigger){
|
||||
}
|
||||
|
||||
Textbox* GuiAppState::getOpenTextbox() {
|
||||
vector<Textbox*> textboxes = ConcreteGuiManager::getSingleton()->getTextboxes();
|
||||
|
||||
for (int i = 0; i < textboxes.size(); i++)
|
||||
if (textboxes[i]->isEnabled())
|
||||
return textboxes[i];
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Listbox* GuiAppState::getOpenListbox() {
|
||||
vector<Listbox*> listboxes = ConcreteGuiManager::getSingleton()->getListboxes();
|
||||
|
||||
for (int i = 0; i < listboxes.size(); i++)
|
||||
if (listboxes[i]->isOpen())
|
||||
return listboxes[i];
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void GuiAppState::onAnalog(int bind, float strength) {}
|
||||
|
||||
void GuiAppState::onRawMouseWheelScroll(bool up){
|
||||
Listbox *openListbox = getOpenListbox();
|
||||
|
||||
if(!openListbox) return;
|
||||
|
||||
if(up) openListbox->scrollUp();
|
||||
else openListbox->scrollDown();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
#ifndef GUI_APP_STATE_H
|
||||
#define GUI_APP_STATE_H
|
||||
|
||||
#include <button.h>
|
||||
#include <listbox.h>
|
||||
#include <checkbox.h>
|
||||
#include <textbox.h>
|
||||
#include <slider.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <abstractAppState.h>
|
||||
|
||||
#include "binds.h"
|
||||
#include "tooltip.h"
|
||||
|
||||
namespace battleship{
|
||||
class GuiAppState : public gameBase::AbstractAppState {
|
||||
public:
|
||||
GuiAppState();
|
||||
~GuiAppState();
|
||||
void onAttached();
|
||||
void onDettached();
|
||||
void update();
|
||||
inline bool isLeftMousePressed(){return leftMousePressed;}
|
||||
private:
|
||||
virtual void onAction(int, bool);
|
||||
virtual void onAnalog(int, float);
|
||||
virtual void onRawKeyPress(int);
|
||||
virtual void onRawCharPress(vb01::u32);
|
||||
virtual void onRawMousePress(int);
|
||||
virtual void onRawMouseWheelScroll(bool);
|
||||
vb01Gui::Textbox* getOpenTextbox();
|
||||
vb01Gui::Listbox* getOpenListbox();
|
||||
|
||||
bool leftMousePressed = false, backspacePressed = false;
|
||||
protected:
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,103 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include <button.h>
|
||||
|
||||
#include <util.h>
|
||||
#include <root.h>
|
||||
#include <camera.h>
|
||||
#include <assetManager.h>
|
||||
|
||||
#include <stateManager.h>
|
||||
|
||||
#include "defConfigs.h"
|
||||
#include "inGameAppState.h"
|
||||
#include "game.h"
|
||||
#include "console.h"
|
||||
#include "gameObjectFrameController.h"
|
||||
#include "concreteGuiManager.h"
|
||||
#include "vessel.h"
|
||||
|
||||
#include <solUtil.h>
|
||||
|
||||
using namespace vb01;
|
||||
using namespace vb01Gui;
|
||||
using namespace std;
|
||||
|
||||
namespace battleship{
|
||||
using namespace configData;
|
||||
using namespace gameBase;
|
||||
|
||||
InGameAppState::ResumeButton::ResumeButton(Vector3 pos, Vector2 size) : Button(pos, size, "Resume", GameManager::getSingleton()->getPath() + "Fonts/batang.ttf", -1, true) {}
|
||||
|
||||
void InGameAppState::ResumeButton::onClick() {
|
||||
Game::getSingleton()->togglePause();
|
||||
}
|
||||
|
||||
InGameAppState::ConsoleButton::ConsoleButton(Vector3 pos, Vector2 size) : Button(pos, size, "Console", GameManager::getSingleton()->getPath() + "Fonts/batang.ttf", -1, true) { }
|
||||
|
||||
void InGameAppState::ConsoleButton::onClick() {
|
||||
ConcreteGuiManager::getSingleton()->readLuaScreenScript("console.lua");
|
||||
}
|
||||
|
||||
InGameAppState::ConsoleButton::ConsoleButton::ConsoleCommandEntryButton::ConsoleCommandEntryButton(Textbox *t, Listbox *l, Vector3 pos, Vector2 size, string name) : Button(pos, size, name, GameManager::getSingleton()->getPath() + "Fonts/batang.ttf", 257, true) {
|
||||
textbox = t;
|
||||
listbox = l;
|
||||
}
|
||||
|
||||
void InGameAppState::ConsoleButton::ConsoleButton::ConsoleCommandEntryButton::onClick() {
|
||||
Console::execute(wstringToString(textbox->getText()));
|
||||
}
|
||||
|
||||
InGameAppState::InGameAppState(std::string mn) : AbstractAppState(
|
||||
AppStateType::IN_GAME_STATE,
|
||||
configData::calcSumBinds(AppStateType::IN_GAME_STATE, true),
|
||||
configData::calcSumBinds(AppStateType::IN_GAME_STATE, false),
|
||||
GameManager::getSingleton()->getPath() + scripts[(int)ScriptFiles::OPTIONS]
|
||||
),
|
||||
mapName(mn),
|
||||
playerId(0){}
|
||||
|
||||
void InGameAppState::onAttached() {
|
||||
AbstractAppState::onAttached();
|
||||
|
||||
Map *map = Map::getSingleton();
|
||||
map->load(mapName);
|
||||
map->loadPlayersGameObjects();
|
||||
|
||||
Camera *cam = Root::getSingleton()->getCamera();
|
||||
cam->setPosition(Map::getSingleton()->getSpawnPoint(playerId) + Vector3(1, 1, 1) * configData::CAMERA_DISTANCE);
|
||||
cam->lookAt(Vector3(0, -1, -1).norm(), Vector3(0, 1, -1).norm());
|
||||
|
||||
GameManager *gm = GameManager::getSingleton();
|
||||
StateManager *stateManager = gm->getStateManager();
|
||||
GuiAppState *guiState = ((GuiAppState*)stateManager->getAppStateByType((int)AppStateType::GUI_STATE));
|
||||
activeState = new ActiveGameState(guiState, playerId);
|
||||
stateManager->attachAppState(activeState);
|
||||
|
||||
Game::getSingleton()->initLuaPlayers();
|
||||
//Map::Minimap::getSingleton()->updateImage();
|
||||
}
|
||||
|
||||
void InGameAppState::onDettached() {
|
||||
StateManager *sm = GameManager::getSingleton()->getStateManager();
|
||||
ActiveGameState *activeState = (ActiveGameState*)sm->getAppStateByType(int(AppStateType::ACTIVE_STATE));
|
||||
sm->dettachAppState(activeState);
|
||||
delete activeState;
|
||||
}
|
||||
|
||||
void InGameAppState::update() {
|
||||
Game::getSingleton()->update();
|
||||
Map::getSingleton()->update();
|
||||
}
|
||||
|
||||
void InGameAppState::onAction(int bind, bool isPressed) {
|
||||
switch((Bind)bind){
|
||||
case Bind::TOGGLE_MAIN_MENU:
|
||||
if(isPressed && !(GameObjectFrameController::getSingleton()->isPlacingOnSurface() || activeState->isForceCursorState()))
|
||||
Game::getSingleton()->togglePause();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void InGameAppState::onAnalog(int bind, float str) {}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
#pragma once
|
||||
#ifndef IN_GAME_APP_STATE_H
|
||||
#define IN_GAME_APP_STATE_H
|
||||
|
||||
#include "gameManager.h"
|
||||
#include "player.h"
|
||||
#include "map.h"
|
||||
#include "activeGameState.h"
|
||||
#include "guiAppState.h"
|
||||
#include "exitButton.h"
|
||||
#include "optionsButton.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
//TODO refactor dependence on ActiveGameState
|
||||
namespace battleship{
|
||||
class InGameAppState : public gameBase::AbstractAppState {
|
||||
public:
|
||||
class ResumeButton : public vb01Gui::Button {
|
||||
public:
|
||||
ResumeButton(vb01::Vector3, vb01::Vector2);
|
||||
void onClick();
|
||||
private:
|
||||
};
|
||||
|
||||
class ConsoleButton : public vb01Gui::Button {
|
||||
public:
|
||||
class ConsoleCommandEntryButton : public Button {
|
||||
public:
|
||||
ConsoleCommandEntryButton(vb01Gui::Textbox*, vb01Gui::Listbox*, vb01::Vector3, vb01::Vector2, std::string);
|
||||
void onClick();
|
||||
private:
|
||||
vb01Gui::Textbox *textbox;
|
||||
vb01Gui::Listbox *listbox;
|
||||
};
|
||||
|
||||
ConsoleButton(vb01::Vector3, vb01::Vector2);
|
||||
void onClick();
|
||||
private:
|
||||
};
|
||||
|
||||
InGameAppState(std::string);
|
||||
~InGameAppState(){}
|
||||
void onAttached();
|
||||
void onDettached();
|
||||
void update();
|
||||
void onAction(int, bool);
|
||||
void onAnalog(int, float);
|
||||
std::vector<Unit*> getSelectedUnits(Player*);
|
||||
inline ActiveGameState* getActiveState(){return activeState;}
|
||||
private:
|
||||
bool isMainMenuActive = false;
|
||||
std::vector<std::string> modelPaths;
|
||||
int playerId;
|
||||
std::string mapName = "";
|
||||
ActiveGameState* activeState;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,51 @@
|
||||
#include "loadingAppState.h"
|
||||
#include "concreteGuiManager.h"
|
||||
#include "gameManager.h"
|
||||
#include "defConfigs.h"
|
||||
|
||||
#include <quad.h>
|
||||
#include <node.h>
|
||||
#include <vector.h>
|
||||
#include <assetManager.h>
|
||||
|
||||
#include <stateManager.h>
|
||||
|
||||
namespace battleship{
|
||||
using namespace configData;
|
||||
using namespace gameBase;
|
||||
using namespace vb01;
|
||||
using namespace std;
|
||||
|
||||
LoadingAppState::LoadingAppState(AbstractAppState *newSt, string newScr) : AbstractAppState(
|
||||
AppStateType::LOADING_STATE,
|
||||
configData::calcSumBinds(AppStateType::LOADING_STATE, true),
|
||||
configData::calcSumBinds(AppStateType::LOADING_STATE, false),
|
||||
GameManager::getSingleton()->getPath() + scripts[(int)ScriptFiles::OPTIONS]
|
||||
),
|
||||
newState(newSt),
|
||||
newScreen(newScr)
|
||||
{}
|
||||
|
||||
void LoadingAppState::onDettached(){
|
||||
ConcreteGuiManager::getSingleton()->readLuaScreenScript(newScreen);
|
||||
GameManager::getSingleton()->getStateManager()->attachAppState(newState);
|
||||
|
||||
AbstractAppState::onDettached();
|
||||
}
|
||||
|
||||
void LoadingAppState::update(){
|
||||
Node *loadingBar = ConcreteGuiManager::getSingleton()->getGuiRectangle("_loadingBar");
|
||||
Quad *quad = (Quad*)loadingBar->getMesh(0);
|
||||
quad->setSize(Vector3((1 - (float)loadableAssets.size() / initNumAssets) * 200.f, 20, 0));
|
||||
quad->updateVerts(quad->getMeshBase());
|
||||
|
||||
if(getTime() - lastUpdateTime > 5){
|
||||
AssetManager::getSingleton()->load(loadableAssets[0]);
|
||||
loadableAssets.erase(loadableAssets.begin());
|
||||
|
||||
if(loadableAssets.empty()) GameManager::getSingleton()->getStateManager()->dettachAppState(this);
|
||||
|
||||
lastUpdateTime = getTime();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
#ifndef LOADING_APP_STATE_H
|
||||
#define LOADING_APP_STATE_H
|
||||
|
||||
#include <abstractAppState.h>
|
||||
#include <util.h>
|
||||
|
||||
namespace battleship{
|
||||
class LoadingAppState : public gameBase::AbstractAppState{
|
||||
public:
|
||||
LoadingAppState(gameBase::AbstractAppState*, std::string);
|
||||
~LoadingAppState(){}
|
||||
void onAttached(){}
|
||||
void onDettached();
|
||||
void update();
|
||||
inline void setLoadableAssets(std::vector<std::string> ls){
|
||||
this->loadableAssets = ls;
|
||||
initNumAssets = ls.size();
|
||||
}
|
||||
private:
|
||||
int initNumAssets;
|
||||
std::vector<std::string> loadableAssets;
|
||||
gameBase::AbstractAppState *newState = nullptr;
|
||||
std::string newScreen = "";
|
||||
vb01::s64 lastUpdateTime = 0;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,800 @@
|
||||
#include "mapEditorAppState.h"
|
||||
#include "gameManager.h"
|
||||
#include "defConfigs.h"
|
||||
#include "cameraController.h"
|
||||
#include "resourceDeposit.h"
|
||||
#include "gameObjectFactory.h"
|
||||
#include "gameObjectFrameController.h"
|
||||
#include "player.h"
|
||||
#include "game.h"
|
||||
#include "map.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <box.h>
|
||||
#include <text.h>
|
||||
#include <node.h>
|
||||
#include <quad.h>
|
||||
#include <light.h>
|
||||
#include <model.h>
|
||||
#include <texture.h>
|
||||
#include <assetManager.h>
|
||||
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#include <stb_image_write.h>
|
||||
|
||||
#include <util.h>
|
||||
|
||||
#include <listbox.h>
|
||||
|
||||
#include <map>
|
||||
#include <filesystem>
|
||||
#include <filesystem>
|
||||
|
||||
#include <tinyxml2.h>
|
||||
|
||||
namespace battleship{
|
||||
using namespace tinyxml2;
|
||||
using namespace configData;
|
||||
using namespace gameBase;
|
||||
using namespace vb01;
|
||||
using namespace vb01Gui;
|
||||
using namespace std;
|
||||
using namespace std::filesystem;
|
||||
|
||||
MapEditorAppState::MapEditor::MapEditor(string name, Vector2 size, bool newMap){
|
||||
this->newMap = newMap;
|
||||
|
||||
string basePath = GameManager::getSingleton()->getPath();
|
||||
prepareTextures(basePath + "Textures/Skyboxes/", true, skyTextures);
|
||||
prepareTextures(basePath + "Textures/Landmass/", false, landmassTextures);
|
||||
prepareTextures(basePath + "Textures/Water/", false, waterTextures);
|
||||
|
||||
AssetManager *assetManager = AssetManager::getSingleton();
|
||||
assetManager->load(basePath + "Models/Units/", true);
|
||||
assetManager->load(basePath + "Models/Resources/", true);
|
||||
assetManager->load(basePath + DEFAULT_TEXTURE);
|
||||
|
||||
map = Map::getSingleton();
|
||||
Game *game = Game::getSingleton();
|
||||
|
||||
if(newMap){
|
||||
game->addPlayer(new Player(0, 0, 0, Vector3(1, 1, 1)));
|
||||
map->create(name, Vector3(size.x, 0, size.y));
|
||||
generatePlane(size);
|
||||
}
|
||||
else{
|
||||
map->load(name);
|
||||
|
||||
int numPlayers = map->getNumSpawnPoints();
|
||||
int numVerts = 3 * map->getNodeParent()->getChild(0)->getMesh(0)->getMeshBase().numTris;
|
||||
oldLandmassVertHeights = new float[numVerts];
|
||||
|
||||
for(int i = 0; i < numPlayers; i++)
|
||||
game->addPlayer(new Player(0, 0, 0, Vector3(1, 1, 1)));
|
||||
|
||||
map->loadPlayersGameObjects();
|
||||
}
|
||||
}
|
||||
|
||||
void MapEditorAppState::MapEditor::updateCircleRadius(bool increase){
|
||||
circleRadius += (increase ? INCREASE_RATE : -INCREASE_RATE);
|
||||
|
||||
if(circleRadius > MAX_RADIUS)
|
||||
circleRadius = MAX_RADIUS;
|
||||
else if(circleRadius < MIN_RADIUS)
|
||||
circleRadius = MIN_RADIUS;
|
||||
}
|
||||
|
||||
void MapEditorAppState::MapEditor::toggleSelection(Node *terrNode, bool select){
|
||||
terrNode->getMesh(0)->setWireframe(select);
|
||||
selectedTerrainNode = (select ? terrNode : nullptr);
|
||||
}
|
||||
|
||||
void MapEditorAppState::MapEditor::castSelectionRay(){
|
||||
/*
|
||||
Camera *cam = Root::getSingleton()->getCamera();
|
||||
Vector3 startPos = cam->getPosition();
|
||||
Vector3 endPos = screenToSpace(getCursorPos());
|
||||
|
||||
Map *map = Map::getSingleton();
|
||||
vector<RayCaster::CollisionResult> results = RayCaster::cast(startPos, (endPos - startPos).norm(), map->getNodeParent());
|
||||
|
||||
if(selectedTerrainNode)
|
||||
toggleSelection(selectedTerrainNode, false);
|
||||
|
||||
if(!results.empty()){
|
||||
for(int i = 0; i < map->getNodeParent()->getNumChildren(); i++)
|
||||
if(map->getNodeParent()->getChild(i) == results[i].mesh->getNode()){
|
||||
toggleSelection(map->getNodeParent()->getChild(i), true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void MapEditorAppState::MapEditor::createWaterbody(){
|
||||
Material *mat = new Material(Root::getSingleton()->getLibPath() + "texture");
|
||||
mat->addBoolUniform("lightingEnabled", false);
|
||||
mat->addBoolUniform("texturingEnabled", true);
|
||||
mat->addTexUniform("textures[0]", waterTextures[0], false);
|
||||
|
||||
Vector3 size = Vector3(30, 30, 1);
|
||||
Quad *quad = new Quad(size, true);
|
||||
quad->setMaterial(mat);
|
||||
|
||||
Vector3 pos = 12 * Vector3::VEC_J;
|
||||
Node *node = new Node(pos);
|
||||
node->attachMesh(quad);
|
||||
|
||||
Map *map = Map::getSingleton();
|
||||
Node *terrNodeParent = map->getNodeParent();
|
||||
terrNodeParent->attachChild(node);
|
||||
toggleSelection(node, true);
|
||||
}
|
||||
|
||||
void MapEditorAppState::MapEditor::moveTerrainObject(float strength){
|
||||
if(fabs(strength) < .00001) return;
|
||||
|
||||
Vector3 axis;
|
||||
|
||||
switch(transformAxis){
|
||||
case TransformAxis::X_AXIS:
|
||||
axis = Vector3::VEC_I;
|
||||
break;
|
||||
case TransformAxis::Y_AXIS:
|
||||
axis = -Vector3::VEC_J;
|
||||
break;
|
||||
case TransformAxis::Z_AXIS:
|
||||
axis = Vector3::VEC_K;
|
||||
break;
|
||||
}
|
||||
|
||||
Vector3 pos = selectedTerrainNode->getPosition() + 10 * strength * axis;
|
||||
selectedTerrainNode->setPosition(pos);
|
||||
}
|
||||
|
||||
void MapEditorAppState::MapEditor::scaleTerrainObject(float strength){
|
||||
if(fabs(strength) < .00001) return;
|
||||
|
||||
Vector2 axis;
|
||||
|
||||
switch(transformAxis){
|
||||
case TransformAxis::X_AXIS:
|
||||
axis = Vector2::VEC_I;
|
||||
break;
|
||||
case TransformAxis::Z_AXIS:
|
||||
axis = Vector2::VEC_J;
|
||||
break;
|
||||
}
|
||||
|
||||
Quad *quad = (Quad*)selectedTerrainNode->getMesh(0);
|
||||
Vector3 size = quad->getSize() + 10 * strength * Vector3(axis.x, axis.y, 0);
|
||||
quad->setSize(Vector3(size.x, size.y, 1));
|
||||
quad->updateVerts(quad->getMeshBase());
|
||||
}
|
||||
|
||||
void MapEditorAppState::MapEditor::pushLandmassVerts(float strength){
|
||||
Mesh *mesh = map->getNodeParent()->getChild(0)->getMesh(0);
|
||||
MeshData meshData = mesh->getMeshBase();
|
||||
MeshData::Vertex *verts = meshData.vertices;
|
||||
int numVerts = meshData.numTris * 3;
|
||||
pushPos.y += 10 * strength;
|
||||
|
||||
for(int i = 0; i < numVerts; i++){
|
||||
Vector3 distVec = *verts[i].pos - pushPos;
|
||||
distVec.y = 0;
|
||||
float dist = distVec.getLength();
|
||||
|
||||
if(dist < circleRadius)
|
||||
verts[i].pos->y = oldLandmassVertHeights[i] + pushPos.y - (pushPos.y / circleRadius) * dist;
|
||||
}
|
||||
|
||||
mesh->updateVerts(meshData);
|
||||
|
||||
int minId = 0, maxId = 0;
|
||||
|
||||
for(int i = 0; i < numVerts; i++){
|
||||
if(verts[i].pos->y < verts[minId].pos->y)
|
||||
minId = i;
|
||||
|
||||
if(verts[i].pos->y > verts[maxId].pos->y)
|
||||
maxId = i;
|
||||
}
|
||||
|
||||
Vector3 mapSize = map->getMapSize();
|
||||
map->setBaseHeight(verts[minId].pos->y);
|
||||
map->setMapSize(Vector3(mapSize.x, verts[maxId].pos->y - verts[minId].pos->y, mapSize.z));
|
||||
}
|
||||
|
||||
void MapEditorAppState::MapEditor::generatePlane(Vector2 size){
|
||||
Root *root = Root::getSingleton();
|
||||
Material *mat = new Material(root->getLibPath() + "texture");
|
||||
mat->addBoolUniform("texturingEnabled", false);
|
||||
mat->addBoolUniform("lightingEnabled", false);
|
||||
mat->addVec4Uniform("diffuseColor", Vector4(1, 0, 0, 1));
|
||||
|
||||
Quad *mesh = new Quad(Vector3(size.x, size.y, 0), true, NUM_SUBDIVS, NUM_SUBDIVS);
|
||||
mesh->setMaterial(mat);
|
||||
|
||||
Node *node = new Node();
|
||||
node->attachMesh(mesh);
|
||||
map->getNodeParent()->attachChild(node);
|
||||
|
||||
oldLandmassVertHeights = new float[3 * mesh->getMeshBase().numTris];
|
||||
}
|
||||
|
||||
void MapEditorAppState::MapEditor::prepareTextures(string basePath, bool skybox, vector<Texture*> &textures){
|
||||
AssetManager *assetManager = AssetManager::getSingleton();
|
||||
assetManager->load(basePath, skybox);
|
||||
vector<string> texturePaths;
|
||||
|
||||
for(int i = 0; i < assetManager->getNumAssets(); i++){
|
||||
string assetPath = assetManager->getAsset(i)->path;
|
||||
|
||||
if(assetPath.length() >= basePath.length() && assetPath.substr(0, basePath.length()) == basePath)
|
||||
texturePaths.push_back(assetPath);
|
||||
}
|
||||
|
||||
if(skybox){
|
||||
const int numTex = 6;
|
||||
|
||||
for(int i = 0; i < texturePaths.size() / numTex; i++){
|
||||
string paths[]{
|
||||
texturePaths[i * numTex],
|
||||
texturePaths[i * numTex + 1],
|
||||
texturePaths[i * numTex + 2],
|
||||
texturePaths[i * numTex + 3],
|
||||
texturePaths[i * numTex + 4],
|
||||
texturePaths[i * numTex + 5],
|
||||
};
|
||||
|
||||
textures.push_back(new Texture(paths, numTex, true));
|
||||
}
|
||||
}
|
||||
else{
|
||||
for(int i = 0; i < texturePaths.size(); i++){
|
||||
string paths[]{texturePaths[i]};
|
||||
textures.push_back(new Texture(paths, 1, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MapEditorAppState::MapEditor::generateLandmassXml(){
|
||||
XMLDocument *doc = new XMLDocument();
|
||||
|
||||
char *nodeTagName = "node";
|
||||
XMLElement *rootEl = doc->NewElement(nodeTagName);
|
||||
rootEl->SetAttribute("name", "terrain");
|
||||
XMLNode *rootTag = doc->InsertEndChild(rootEl);
|
||||
|
||||
XMLElement *nodeEl = doc->NewElement(nodeTagName);
|
||||
nodeEl->SetAttribute("name", "plane");
|
||||
Node *landmassNode = map->getNodeParent()->getChild(0);
|
||||
nodeEl->SetAttribute("px", landmassNode->getPosition().x);
|
||||
nodeEl->SetAttribute("py", landmassNode->getPosition().y);
|
||||
nodeEl->SetAttribute("pz", landmassNode->getPosition().z);
|
||||
nodeEl->SetAttribute("rw", landmassNode->getOrientation().w);
|
||||
nodeEl->SetAttribute("rx", landmassNode->getOrientation().x);
|
||||
nodeEl->SetAttribute("ry", landmassNode->getOrientation().y);
|
||||
nodeEl->SetAttribute("rz", landmassNode->getOrientation().z);
|
||||
nodeEl->SetAttribute("sx", landmassNode->getScale().x);
|
||||
nodeEl->SetAttribute("sy", landmassNode->getScale().y);
|
||||
nodeEl->SetAttribute("sz", landmassNode->getScale().z);
|
||||
XMLNode *nodeTag = rootTag->InsertEndChild(nodeEl);
|
||||
|
||||
XMLElement *meshEl = doc->NewElement("mesh");
|
||||
MeshData meshData = map->getNodeParent()->getChild(0)->getMesh(0)->getMeshBase();
|
||||
meshEl->SetAttribute("name", "mesh");
|
||||
meshEl->SetAttribute("num_vertex_pos", 3 * meshData.numTris);
|
||||
meshEl->SetAttribute("num_faces", meshData.numTris);
|
||||
meshEl->SetAttribute("num_vertex_groups", 0);
|
||||
meshEl->SetAttribute("num_shape_keys", 0);
|
||||
XMLNode *meshTag = nodeTag->InsertEndChild(meshEl);
|
||||
|
||||
//TODO optimize vertex position extraction
|
||||
/*
|
||||
const int numSideQuads = NUM_SUBDIVS + 1, numSideVerts = numSideQuads + 1;
|
||||
Vector2 subQuadSize = Vector2(size.x / numSideQuads, size.y / numSideQuads);
|
||||
*/
|
||||
int numVerts = 3 * meshData.numTris;
|
||||
|
||||
for(int i = 0; i < numVerts; i++){
|
||||
XMLElement *vertEl = doc->NewElement("vertdata");
|
||||
vertEl->SetAttribute("px", meshData.vertices[i].pos->x);
|
||||
vertEl->SetAttribute("py", meshData.vertices[i].pos->y);
|
||||
vertEl->SetAttribute("pz", meshData.vertices[i].pos->z);
|
||||
/*
|
||||
vertEl->SetAttribute("nx", meshData.vertices[i].norm.x);
|
||||
vertEl->SetAttribute("ny", meshData.vertices[i].norm.y);
|
||||
vertEl->SetAttribute("nz", meshData.vertices[i].norm.z);
|
||||
*/
|
||||
XMLNode *vertNode = meshTag->InsertEndChild(vertEl);
|
||||
}
|
||||
|
||||
for(int i = 0; i < numVerts; i++){
|
||||
XMLElement *vertEl = doc->NewElement("vert");
|
||||
vertEl->SetAttribute("id", i);
|
||||
vertEl->SetAttribute("uvx", meshData.vertices[i].uv.x);
|
||||
vertEl->SetAttribute("uvy", meshData.vertices[i].uv.y);
|
||||
vertEl->SetAttribute("tx", meshData.vertices[i].tan.x);
|
||||
vertEl->SetAttribute("ty", meshData.vertices[i].tan.y);
|
||||
vertEl->SetAttribute("tz", meshData.vertices[i].tan.z);
|
||||
vertEl->SetAttribute("bx", meshData.vertices[i].biTan.x);
|
||||
vertEl->SetAttribute("by", meshData.vertices[i].biTan.y);
|
||||
vertEl->SetAttribute("bz", meshData.vertices[i].biTan.z);
|
||||
XMLNode *vertTag = meshTag->InsertEndChild(vertEl);
|
||||
}
|
||||
|
||||
string name = GameManager::getSingleton()->getPath() + "Models/Maps/" + map->getMapName() + "/" + map->getMapName() + ".xml";
|
||||
doc->SaveFile(name.c_str());
|
||||
}
|
||||
|
||||
//TODO add diagnally adjacent edges to underwater cells
|
||||
vector<Map::Cell> MapEditorAppState::MapEditor::generateMapCells(){
|
||||
Vector3 mapSize = map->getMapSize();
|
||||
Vector3 cellSize = map->getCellSize();
|
||||
Vector3 startPos = -.5 * (Vector3(mapSize.x, 0, mapSize.z) - Vector3(cellSize.x, 0, cellSize.z));
|
||||
|
||||
int numHorCells = int(mapSize.x / cellSize.x);
|
||||
int numVertCells = int(mapSize.z / cellSize.z);
|
||||
vector<Map::Cell> cells;
|
||||
vector<pair<int, float>> waterBodyBedPoints;
|
||||
Node *terrainNode = map->getNodeParent();
|
||||
|
||||
|
||||
for(int i = 0; i < numVertCells; i++)
|
||||
for(int j = 0; j < numHorCells; j++){
|
||||
Vector3 rayPos = startPos + Vector3(cellSize.x * j, 100, cellSize.z * i);
|
||||
vector<RayCaster::CollisionResult> res = RayCaster::cast(rayPos, -Vector3::VEC_J, terrainNode->getChild(0), 0, configData::DIST_FROM_RAY);
|
||||
|
||||
Map::Cell::Type type = Map::Cell::Type::LAND;
|
||||
Vector3 pos = res[0].pos;
|
||||
|
||||
for(int k = 1; k < terrainNode->getNumChildren(); k++){
|
||||
Vector3 waterPos = terrainNode->getChild(k)->getPosition();
|
||||
Vector3 waterSize = ((Quad*)terrainNode->getChild(k)->getMesh(0))->getSize();
|
||||
|
||||
if(pos.y < waterPos.y && fabs(res[0].pos.x - waterPos.x) < .5 * waterSize.x && fabs(res[0].pos.z - waterPos.z) < .5 * waterSize.y){
|
||||
type = Map::Cell::Type::WATER;
|
||||
pos.y = waterPos.y;
|
||||
waterBodyBedPoints.push_back(pair(numVertCells * j + i, res[0].pos.y));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
vector<Map::Edge> edges = Map::generateAdjacentNodeEdges(numVertCells, i, numHorCells, j, 10);
|
||||
Map::Cell cell = Map::Cell(pos, type, edges);
|
||||
cells.push_back(cell);
|
||||
}
|
||||
|
||||
vector<Map::Cell> surfaceWaterCells;
|
||||
int currUnderWaterCellId = cells.size();
|
||||
int weight = 20;
|
||||
|
||||
for(pair<int, float> p : waterBodyBedPoints){
|
||||
int numUnderWaterCells = (int)((cells[p.first].pos.y - p.second) / cellSize.y);
|
||||
|
||||
if(numUnderWaterCells > 0){
|
||||
cells[p.first].edges.push_back(Map::Edge(weight, p.first, currUnderWaterCellId));
|
||||
|
||||
for(int i = 0; i < numUnderWaterCells; i++, currUnderWaterCellId++)
|
||||
cells[p.first].underWaterCellIds.push_back(currUnderWaterCellId);
|
||||
|
||||
surfaceWaterCells.push_back(cells[p.first]);
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; i < surfaceWaterCells.size(); i++){
|
||||
for(int j = 0; j < surfaceWaterCells[i].underWaterCellIds.size(); j++){
|
||||
int aboveCellId = (j == 0 ? surfaceWaterCells[i].edges[0].srcCellId : surfaceWaterCells[i].underWaterCellIds[j - 1]);
|
||||
vector<Map::Edge> edges = vector<Map::Edge>{Map::Edge(weight, surfaceWaterCells[i].underWaterCellIds[j], aboveCellId)};
|
||||
|
||||
if(surfaceWaterCells[i].underWaterCellIds.size() > j + 1)
|
||||
edges.push_back(Map::Edge(weight, surfaceWaterCells[i].underWaterCellIds[j], surfaceWaterCells[i].underWaterCellIds[j + 1]));
|
||||
|
||||
for(int k = 0; k < surfaceWaterCells[i].edges.size() - 1; k++){
|
||||
Map::Cell adjacentUnderwaterCell = cells[surfaceWaterCells[i].edges[k].destCellId];
|
||||
|
||||
if(adjacentUnderwaterCell.underWaterCellIds.size() >= j + 1){
|
||||
edges.push_back(Map::Edge(weight, surfaceWaterCells[i].underWaterCellIds[j], adjacentUnderwaterCell.underWaterCellIds[j]));
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 cellPos = surfaceWaterCells[i].pos - Vector3::VEC_J * cellSize.y * (j + 1);
|
||||
cells.push_back(Map::Cell(cellPos, Map::Cell::Type::WATER, edges));
|
||||
}
|
||||
}
|
||||
|
||||
return cells;
|
||||
}
|
||||
|
||||
void MapEditorAppState::MapEditor::generateMinimap(string mapFolder, vector<Map::Cell> &cells){
|
||||
Vector3 mapSize = map->getMapSize(), cellSize = map->getCellSize();
|
||||
int width = int(mapSize.x / cellSize.x);
|
||||
int height = int(mapSize.z / cellSize.z);
|
||||
int numChannels = 3;
|
||||
int size = width * height * numChannels;
|
||||
int cellId = 0;
|
||||
float baseHeight = map->getBaseHeight();
|
||||
|
||||
u8 *imgData = new u8[size];
|
||||
|
||||
for(u8 *p = imgData; p != imgData + size; p+= numChannels, cellId++){
|
||||
float min = .6, max = 1.;
|
||||
float heightFactor = min + (max - min) * (cells[cellId].pos.y - baseHeight) / mapSize.y;
|
||||
Vector3 color = (cells[cellId].type == Map::Cell::Type::WATER ? Vector3::VEC_K : Vector3::VEC_J);
|
||||
|
||||
*p = color.x * heightFactor * 255.f;
|
||||
*(p + 1) = color.y * heightFactor * 255.f;
|
||||
*(p + 2) = color.z * heightFactor * 255.f;
|
||||
}
|
||||
|
||||
stbi_write_jpg(string(mapFolder + "minimap.jpg").c_str(), width, height, numChannels, imgData, 100);
|
||||
}
|
||||
|
||||
string MapEditorAppState::MapEditor::generatePlayerTableStr(Player* player){
|
||||
string mapScript = "";
|
||||
vector<ResourceDeposit*> resourceDeposits = player->getResourceDeposits();
|
||||
|
||||
if(!resourceDeposits.empty()){
|
||||
mapScript += "\t\t\tresourceDeposits = {\n";
|
||||
|
||||
for(ResourceDeposit *rd : resourceDeposits){
|
||||
Vector3 pos = rd->getPos();
|
||||
string posStr = "x = " + to_string(pos.x) + ", y = " + to_string(pos.y) + ", z = " + to_string(pos.z);
|
||||
|
||||
Quaternion rot = rd->getRot();
|
||||
string rotStr = "w = " + to_string(rot.w) + ", x = " + to_string(rot.x) + ", y = " + to_string(rot.y) + ", z = " + to_string(rot.z);
|
||||
|
||||
mapScript += "\t\t\t\t{id = " + to_string(rd->getId()) + ", pos = {" + posStr + "}, rot = {" + rotStr + "}},\n";
|
||||
}
|
||||
|
||||
mapScript += "\t\t\t},\n";
|
||||
}
|
||||
|
||||
vector<Unit*> units = player->getUnits();
|
||||
|
||||
if(!units.empty()){
|
||||
mapScript += "\t\t\tunits = {\n";
|
||||
|
||||
for(Unit *unit : units){
|
||||
string idStr = "id = " + to_string(unit->getId());
|
||||
|
||||
Vector3 unitPos = unit->getPos();
|
||||
string posStr = "pos = {x = " + to_string(unitPos.x) + ", y = " + to_string(unitPos.y) + ", z = " + to_string(unitPos.z) + "}";
|
||||
|
||||
Quaternion unitRot = unit->getRot();
|
||||
string rotStr = "rot = {w = " + to_string(unitRot.w) + ", x = " + to_string(unitRot.x) + ", y = " + to_string(unitRot.y) + ", z = " + to_string(unitRot.z) + "}";
|
||||
|
||||
mapScript += "\t\t\t\t{" + idStr + ", " + posStr + ", " + rotStr + "},\n";
|
||||
}
|
||||
|
||||
mapScript += "\t\t\t}\n";
|
||||
}
|
||||
|
||||
return mapScript;
|
||||
}
|
||||
|
||||
void MapEditorAppState::MapEditor::generateMapScript(vector<Map::Cell> &cells){
|
||||
int numWaterBodies = map->getNodeParent()->getNumChildren() - 1;
|
||||
|
||||
string mapScript = "metadata = {\n\tlights = {";
|
||||
|
||||
for(Node *light : map->getLights()){
|
||||
mapScript += "\n\t\t{type = " + to_string((int)light->getLight(0)->getLightType());
|
||||
|
||||
if(light->getLight(0)->getLightType() == Light::Type::DIRECTIONAL){
|
||||
Vector3 dir = light->getGlobalAxis(2);
|
||||
mapScript += ", dir = {x = " + to_string(dir.x) + ", y = " + to_string(dir.y) + "z = " + to_string(dir.z) + "}";
|
||||
}
|
||||
|
||||
Vector3 color = light->getLight(0)->getColor();
|
||||
mapScript += ", color = {x = " + to_string(color.x) + ", y = " + to_string(color.y) + ", z = " + to_string(color.z) + "}},";
|
||||
}
|
||||
|
||||
mapScript += "\n\t},\n";
|
||||
Vector3 mapSize = map->getMapSize();
|
||||
mapScript += "\tsize = {x = " + to_string(mapSize.x) + ", y = " + to_string(mapSize.y) + ", z = " + to_string(mapSize.z) + "},\n";
|
||||
mapScript += "\timpassibleNodeValue = " + to_string(IMPASS_NODE_VAL) + ",\n";
|
||||
|
||||
int numSpawnPoints = map->getNumSpawnPoints();
|
||||
mapScript += "\tspawnPoints = {\n";
|
||||
|
||||
for(int i = 0; i < numSpawnPoints; i++){
|
||||
Vector3 sp = map->getSpawnPoint(i);
|
||||
mapScript += "\t\t{x = " + to_string(sp.x) + ", y = " + to_string(sp.y) + ", z = " + to_string(sp.z) + "},\n";
|
||||
}
|
||||
|
||||
mapScript += "\t},\n";
|
||||
mapScript += "\tchoosablePlayers = {";
|
||||
Game *game = Game::getSingleton();
|
||||
|
||||
for(Player *player : game->getPlayers())
|
||||
mapScript += "\n\t\t{\n" + generatePlayerTableStr(player) + "\n\t\t},\n";
|
||||
|
||||
mapScript += "\t},\n";
|
||||
mapScript += "\tcivilianPlayer = {\n" + generatePlayerTableStr(game->getCivilianPlayer()) + "\n\t},\n";
|
||||
|
||||
Root *root = Root::getSingleton();
|
||||
string skyboxPath = "";
|
||||
|
||||
if(root->getSkybox()){
|
||||
Texture *tex = ((Material::TextureUniform*)root->getSkybox()->getMaterial()->getUniform("tex"))->value;
|
||||
string path = tex->getPath()[0];
|
||||
int slashId = path.find_last_of('/');
|
||||
skyboxPath = path.substr(0, slashId);
|
||||
|
||||
slashId = skyboxPath.find_last_of('/');
|
||||
skyboxPath = skyboxPath.substr(slashId + 1);
|
||||
}
|
||||
|
||||
mapScript += "\tskybox = \"" + skyboxPath + "\",\n";
|
||||
mapScript += "\tterrain = {model = \"" + map->getMapName() + ".xml\", albedo = \"" + map->getMapName() + ".jpg\"},\n";
|
||||
mapScript += "\twaterbodies = {\n";
|
||||
|
||||
for(int i = 0; i < numWaterBodies; i++){
|
||||
Node *waterNode = map->getNodeParent()->getChild(i + 1);
|
||||
Vector3 pos = waterNode->getPosition();
|
||||
Vector3 size = ((Quad*)waterNode->getMesh(0))->getSize();
|
||||
mapScript +=
|
||||
"\t\t{pos = {x = " + to_string(pos.x) + ", y = " + to_string(pos.y) + ", z = " + to_string(pos.z) + "},\
|
||||
size = {x = " + to_string(size.x) + ", y = " + to_string(size.y) + "}, albedo = \"water.png\"},";
|
||||
}
|
||||
|
||||
mapScript += "\t}\n}";
|
||||
|
||||
string cellsScript = "cells = {\n";
|
||||
|
||||
for(Map::Cell cell : cells){
|
||||
Vector3 p = cell.pos;
|
||||
cellsScript += "\t\t{type = " + to_string((int)cell.type) + ", pos = {x = " + to_string(p.x) + ", y = " + to_string(p.y) + ", z = " + to_string(p.z) + "}, numEdges = " + to_string(cell.edges.size()) + ", edges = {";
|
||||
|
||||
for(Map::Edge edge : cell.edges)
|
||||
cellsScript += "{srcCellId = " + to_string(edge.srcCellId) + ", destCellId = " + to_string(edge.destCellId) + ", weight = " + to_string(edge.weight) + "}, ";
|
||||
|
||||
int numSubCells = cell.underWaterCellIds.size();
|
||||
cellsScript += "}, numUnderWaterCells = " + to_string(numSubCells) + ",";
|
||||
|
||||
if(numSubCells > 0){
|
||||
cellsScript += "underWaterCellId = {";
|
||||
|
||||
for(int subCellId : cell.underWaterCellIds)
|
||||
cellsScript += to_string(subCellId) + ", ";
|
||||
|
||||
cellsScript += "}";
|
||||
}
|
||||
|
||||
cellsScript += "\t\t},\n";
|
||||
}
|
||||
|
||||
cellsScript += "\t}";
|
||||
|
||||
string basePath = GameManager::getSingleton()->getPath() + "Models/Maps/" + map->getMapName() + "/";
|
||||
|
||||
std::ofstream outFile(basePath + map->getMapName() + ".lua");
|
||||
outFile << mapScript;
|
||||
outFile.close();
|
||||
|
||||
outFile = std::ofstream(basePath + "cells.lua");
|
||||
outFile << cellsScript;
|
||||
outFile.close();
|
||||
}
|
||||
|
||||
void MapEditorAppState::MapEditor::exportMap(){
|
||||
string assetsPath = GameManager::getSingleton()->getPath();
|
||||
string mapFolder = assetsPath + "Models/Maps/" + map->getMapName() + "/";
|
||||
create_directory(mapFolder);
|
||||
copy_file(assetsPath + DEFAULT_TEXTURE, mapFolder + map->getMapName() + ".jpg", filesystem::copy_options::overwrite_existing);
|
||||
|
||||
vector<Map::Cell> cells = generateMapCells();
|
||||
generateLandmassXml();
|
||||
generateMapScript(cells);
|
||||
generateMinimap(mapFolder, cells);
|
||||
}
|
||||
|
||||
void MapEditorAppState::MapEditor::togglePush(bool push){
|
||||
this->pushing = push;
|
||||
|
||||
if(push){
|
||||
MeshData meshData = map->getNodeParent()->getChild(0)->getMesh(0)->getMeshBase();
|
||||
int numVerts = 3 * meshData.numTris;
|
||||
|
||||
for(int i = 0; i < numVerts; i++)
|
||||
oldLandmassVertHeights[i] = meshData.vertices[i].pos->y;
|
||||
}
|
||||
}
|
||||
|
||||
MapEditorAppState::MapEditorAppState(string name, Vector2 size, bool newMap) : AbstractAppState(
|
||||
AppStateType::MAP_EDITOR,
|
||||
configData::calcSumBinds(AppStateType::MAP_EDITOR, true),
|
||||
configData::calcSumBinds(AppStateType::MAP_EDITOR, false),
|
||||
GameManager::getSingleton()->getPath() + scripts[ScriptFiles::OPTIONS]){
|
||||
mapName = name;
|
||||
mapSize = size;
|
||||
this->newMap = newMap;
|
||||
}
|
||||
|
||||
void MapEditorAppState::update(){
|
||||
radiusText->setText(L"Radius: " + to_wstring(mapEditor->getCircleRadius()));
|
||||
weightsText->setText(L"Weights generated: " + to_wstring(mapEditor->isWeightsGenerated()));
|
||||
|
||||
CameraController *camCtr = CameraController::getSingleton();
|
||||
|
||||
if(!(camCtr->isLookingAround() || mapEditor->isPushing()))
|
||||
camCtr->updateCameraPosition();
|
||||
|
||||
GameObjectFrameController *ufCtr = GameObjectFrameController::getSingleton();
|
||||
|
||||
if(ufCtr->isPlacingOnSurface())
|
||||
ufCtr->update();
|
||||
}
|
||||
|
||||
void MapEditorAppState::onAttached(){
|
||||
AbstractAppState::onAttached();
|
||||
mapEditor = new MapEditor(mapName, mapSize, newMap);
|
||||
|
||||
Root *root = Root::getSingleton();
|
||||
Material *mat = new Material(root->getLibPath() + "text");
|
||||
mat->addBoolUniform("texturingEnabled", false);
|
||||
mat->addVec4Uniform("diffuseColor", Vector4::VEC_IJKL);
|
||||
|
||||
string fontPath = GameManager::getSingleton()->getPath() + "Fonts/batang.ttf";
|
||||
radiusText = new Text(fontPath, L"");
|
||||
radiusText->setMaterial(mat);
|
||||
weightsText = new Text(fontPath, L"");
|
||||
weightsText->setMaterial(mat);
|
||||
|
||||
Node *radiusNode = new Node(Vector3(0, 100, 0));
|
||||
radiusNode->addText(radiusText);
|
||||
root->getGuiNode()->attachChild(radiusNode);
|
||||
|
||||
Node *weightsNode = new Node(Vector3(0, 200, 0));
|
||||
weightsNode->addText(weightsText);
|
||||
root->getGuiNode()->attachChild(weightsNode);
|
||||
}
|
||||
|
||||
void MapEditorAppState::onDettached(){}
|
||||
|
||||
void MapEditorAppState::onAction(int bind, bool isPressed){
|
||||
GameObjectFrameController *ufCtr = GameObjectFrameController::getSingleton();
|
||||
|
||||
switch((Bind)bind){
|
||||
case Bind::LOOK_AROUND:
|
||||
if(!ufCtr->isPlacingOnSurface())
|
||||
CameraController::getSingleton()->setLookingAround(isPressed);
|
||||
|
||||
break;
|
||||
case Bind::ROTATE_OBJ_FRAME:
|
||||
if(isPressed && ufCtr->isPlacingOnSurface())
|
||||
ufCtr->setRotating(true);
|
||||
else if(!isPressed && ufCtr->isRotating()){
|
||||
Player *player = Game::getSingleton()->getPlayer(0);
|
||||
GameObjectFrame &frame = ufCtr->getGameObjectFrame(0);
|
||||
Model *model = frame.getModel();
|
||||
Vector3 pos = model->getPosition();
|
||||
Quaternion rot = model->getOrientation();
|
||||
|
||||
if(frame.getType() == GameObject::Type::RESOURCE_DEPOSIT)
|
||||
player->addResourceDeposit(GameObjectFactory::createResourceDeposit(player, frame.getId(), pos, rot));
|
||||
else
|
||||
player->addUnit(GameObjectFactory::createUnit(player, frame.getId(), pos, rot));
|
||||
|
||||
ufCtr->setRotating(false);
|
||||
}
|
||||
|
||||
break;
|
||||
case Bind::DESELECT_STRUCTURE:
|
||||
ufCtr->removeGameObjectFrames();
|
||||
ufCtr->setPlacingOnSurface(false);
|
||||
ufCtr->setRotating(false);
|
||||
break;
|
||||
case Bind::INCREASE_RADIUS:
|
||||
if(isPressed) mapEditor->updateCircleRadius(true);
|
||||
break;
|
||||
case Bind::DECREASE_RADIUS:
|
||||
if(isPressed) mapEditor->updateCircleRadius(false);
|
||||
break;
|
||||
case Bind::LEFT_CLICK:
|
||||
if(isPressed){
|
||||
Camera *cam = Root::getSingleton()->getCamera();
|
||||
Vector3 startPos = cam->getPosition();
|
||||
Vector2 cursorPos = getCursorPos();
|
||||
Vector3 endPos = screenToSpace(cursorPos);
|
||||
|
||||
vector<RayCaster::CollisionResult> results = RayCaster::cast(
|
||||
startPos,
|
||||
(endPos - startPos).norm(),
|
||||
Root::getSingleton()->getRootNode(),
|
||||
0,
|
||||
configData::DIST_FROM_RAY
|
||||
);
|
||||
|
||||
if(cursorPos.y < GameManager::getSingleton()->getHeight() - mapEditor->getGuiThreshold()){
|
||||
bool push = !results.empty();
|
||||
mapEditor->togglePush(push);
|
||||
|
||||
if(push)
|
||||
mapEditor->setPushPos(results[0].pos);
|
||||
|
||||
mapEditor->castSelectionRay();
|
||||
}
|
||||
else
|
||||
mapEditor->togglePush(false);
|
||||
}
|
||||
else
|
||||
mapEditor->togglePush(false);
|
||||
|
||||
break;
|
||||
case Bind::CREATE_WATERBODY:
|
||||
if(isPressed) mapEditor->createWaterbody();
|
||||
break;
|
||||
case Bind::MOVE_TERR_OBJ:
|
||||
if(isPressed){
|
||||
mapEditor->setMovingTerrainObject(true);
|
||||
mapEditor->setScalingTerrainObject(false);
|
||||
break;
|
||||
}
|
||||
case Bind::SCALE_TERR_OBJ:
|
||||
if(isPressed){
|
||||
mapEditor->setMovingTerrainObject(false);
|
||||
mapEditor->setScalingTerrainObject(true);
|
||||
break;
|
||||
}
|
||||
case Bind::STOP_TERR_OBJ:
|
||||
if(isPressed){
|
||||
mapEditor->setMovingTerrainObject(false);
|
||||
mapEditor->setScalingTerrainObject(false);
|
||||
break;
|
||||
}
|
||||
case Bind::ENABLE_X_AXIS:
|
||||
case Bind::ENABLE_Y_AXIS:
|
||||
case Bind::ENABLE_Z_AXIS:
|
||||
if(isPressed && (mapEditor->isMovingTerrainObject() || mapEditor->isScalingTerrainObject())){
|
||||
MapEditor::TransformAxis axis = MapEditor::TransformAxis((int)bind - (int)Bind::ENABLE_X_AXIS);
|
||||
mapEditor->setTransformAxis(axis);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MapEditorAppState::onAnalog(int bind, float strength){
|
||||
CameraController *camCtr = CameraController::getSingleton();
|
||||
GameObjectFrameController *ufCtr = GameObjectFrameController::getSingleton();
|
||||
|
||||
switch((Bind)bind){
|
||||
case Bind::LOOK_UP:
|
||||
case Bind::LOOK_DOWN:
|
||||
if(camCtr->isLookingAround()){
|
||||
Vector3 dirProj = Root::getSingleton()->getCamera()->getDirection();
|
||||
dirProj = Vector3(dirProj.x, 0, dirProj.z).norm();
|
||||
camCtr->orientCamera(Vector3(0, 1, 0).cross(dirProj), strength);
|
||||
}
|
||||
|
||||
break;
|
||||
case Bind::LOOK_LEFT:
|
||||
case Bind::LOOK_RIGHT:
|
||||
if(camCtr->isLookingAround())
|
||||
camCtr->orientCamera(Vector3(0, 1, 0), strength);
|
||||
else if(ufCtr->isRotating())
|
||||
ufCtr->rotateGameObjectFrames(100 * strength);
|
||||
|
||||
break;
|
||||
case Bind::PUSH_VERTS_UP:
|
||||
case Bind::PUSH_VERTS_DOWN:
|
||||
if(mapEditor->isPushing()) mapEditor->pushLandmassVerts(strength);
|
||||
else if(mapEditor->getSelectedNode() != Map::getSingleton()->getNodeParent()->getChild(0)){
|
||||
if(mapEditor->isScalingTerrainObject())
|
||||
mapEditor->scaleTerrainObject(strength);
|
||||
else if(mapEditor->isMovingTerrainObject())
|
||||
mapEditor->moveTerrainObject(strength);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MapEditorAppState::onRawMouseWheelScroll(bool up){
|
||||
CameraController::getSingleton()->zoomCamera(up);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
#ifndef MAP_EDITOR_APP_STATE_H
|
||||
#define MAP_EDITOR_APP_STATE_H
|
||||
|
||||
#include "map.h"
|
||||
#include "player.h"
|
||||
|
||||
#include <listbox.h>
|
||||
|
||||
#include <abstractAppState.h>
|
||||
|
||||
#include <vector.h>
|
||||
#include <util.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace vb01{
|
||||
class Texture;
|
||||
}
|
||||
|
||||
namespace battleship{
|
||||
class MapEditor;
|
||||
|
||||
class MapEditorAppState : public gameBase::AbstractAppState{
|
||||
public:
|
||||
class MapEditor{
|
||||
public:
|
||||
enum TransformAxis{
|
||||
X_AXIS,
|
||||
Y_AXIS,
|
||||
Z_AXIS
|
||||
};
|
||||
|
||||
MapEditor(std::string, vb01::Vector2, bool);
|
||||
void updateCircleRadius(bool);
|
||||
void pushLandmassVerts(float);
|
||||
void castSelectionRay();
|
||||
void createWaterbody();
|
||||
void moveTerrainObject(float);
|
||||
void scaleTerrainObject(float);
|
||||
void exportMap();
|
||||
void prepareTerrainObjects(int = 0, int = -1);
|
||||
void togglePush(bool);
|
||||
inline vb01::Node* getSelectedNode(){return selectedTerrainNode;}
|
||||
inline float getGuiThreshold(){return guiThreshold;}
|
||||
inline float getCircleRadius(){return circleRadius;}
|
||||
inline bool isPushing(){return pushing;}
|
||||
inline void setPushPos(vb01::Vector3 p){pushPos = p;}
|
||||
inline bool isMovingTerrainObject(){return movingTerrainObject;}
|
||||
inline void setMovingTerrainObject(bool m){movingTerrainObject = m;}
|
||||
inline bool isScalingTerrainObject(){return scalingTerrainObject;}
|
||||
inline void setScalingTerrainObject(bool s){scalingTerrainObject = s;}
|
||||
inline TransformAxis getTransformAxis(){return transformAxis;}
|
||||
inline void setTransformAxis(TransformAxis m){transformAxis = m;}
|
||||
inline bool isWeightsGenerated(){return weightsGenerated;}
|
||||
inline vb01::Texture* getSkyTexture(int i){return skyTextures[i];}
|
||||
inline vb01::Texture* getLandmassTexture(int i){return landmassTextures[i];}
|
||||
private:
|
||||
void generatePlane(vb01::Vector2);
|
||||
void prepareTextures(std::string, bool, std::vector<vb01::Texture*>&);
|
||||
void toggleSelection(vb01::Node*, bool);
|
||||
std::vector<Map::Cell> generateMapCells();
|
||||
void generateLandmassXml();
|
||||
void generateMinimap(std::string, std::vector<Map::Cell>&);
|
||||
std::string generatePlayerTableStr(Player*);
|
||||
void generateMapScript(std::vector<Map::Cell>&);
|
||||
void prepareTerrainObject(vb01::u32**, Map::Cell*, int[3], float, bool);
|
||||
|
||||
Map *map;
|
||||
vb01::Node *selectedTerrainNode = nullptr;
|
||||
TransformAxis transformAxis = X_AXIS;
|
||||
vb01Gui::Listbox *skyListbox = nullptr;
|
||||
float *oldLandmassVertHeights = nullptr;
|
||||
bool pushing = false, movingTerrainObject = false, scalingTerrainObject = false, weightsGenerated = false, newMap, cellMarkersVisible = false;
|
||||
const float MIN_RADIUS = 1, MAX_RADIUS = 100, INCREASE_RATE = 1;
|
||||
float circleRadius = MIN_RADIUS, guiThreshold = 200;
|
||||
vb01::Vector3 pushPos = vb01::Vector3::VEC_ZERO;
|
||||
std::vector<vb01::Texture*> skyTextures, landmassTextures, waterTextures;
|
||||
};
|
||||
|
||||
MapEditorAppState(std::string, vb01::Vector2, bool);
|
||||
void update();
|
||||
void onAttached();
|
||||
void onDettached();
|
||||
void onAction(int, bool);
|
||||
void onAnalog(int, float);
|
||||
void onRawMouseWheelScroll(bool);
|
||||
inline MapEditor* getMapEditor(){return mapEditor;}
|
||||
private:
|
||||
MapEditor *mapEditor = nullptr;
|
||||
std::string mapName;
|
||||
vb01::Vector2 mapSize;
|
||||
bool newMap;
|
||||
vb01::Text *radiusText = nullptr, *weightsText = nullptr;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,62 @@
|
||||
#ifndef BINDS_H
|
||||
#define BINDS_H
|
||||
|
||||
namespace battleship{
|
||||
enum Bind{
|
||||
LEFT_CLICK,
|
||||
SCROLLING_UP,
|
||||
SCROLLING_DOWN,
|
||||
LEFT,
|
||||
RIGHT,
|
||||
DELETE_CHAR,
|
||||
TOGGLE_MAIN_MENU,
|
||||
LOOK_UP,
|
||||
LOOK_DOWN,
|
||||
LOOK_LEFT,
|
||||
LOOK_RIGHT,
|
||||
LOOK_AROUND,
|
||||
DRAG_BOX,
|
||||
ROTATE_OBJ_FRAME,
|
||||
HALT,
|
||||
ZOOM_IN,
|
||||
ZOOM_OUT,
|
||||
LEFT_CONTROL,
|
||||
LEFT_SHIFT,
|
||||
SELECT_PATROL_POINTS,
|
||||
LAUNCH,
|
||||
SHIFT_SUB_DEPTH,
|
||||
GROUP_0,
|
||||
GROUP_1,
|
||||
GROUP_2,
|
||||
GROUP_3,
|
||||
GROUP_4,
|
||||
GROUP_5,
|
||||
GROUP_6,
|
||||
GROUP_7,
|
||||
GROUP_8,
|
||||
GROUP_9,
|
||||
SELECT_STRUCTURE,
|
||||
DESELECT_STRUCTURE,
|
||||
DECREASE_RADIUS,
|
||||
INCREASE_RADIUS,
|
||||
PUSH_VERTS_UP,
|
||||
PUSH_VERTS_DOWN,
|
||||
MOVE_TERR_OBJ,
|
||||
SCALE_TERR_OBJ,
|
||||
STOP_TERR_OBJ,
|
||||
ENABLE_X_AXIS,
|
||||
ENABLE_Y_AXIS,
|
||||
ENABLE_Z_AXIS,
|
||||
CREATE_WATERBODY,
|
||||
GENERATE_WEIGHTS,
|
||||
TOGGLE_CELL_MARKERS,
|
||||
EJECT_GARRISON,
|
||||
ENABLE_CHASE_STATE,
|
||||
ENABLE_STAND_GROUND_STATE,
|
||||
ENABLE_HOLD_FIRE_STATE,
|
||||
HACK,
|
||||
MOVE_CAMERA
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,33 @@
|
||||
#include "abstractCommand.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <vector.h>
|
||||
|
||||
namespace battleship{
|
||||
using namespace std;
|
||||
|
||||
void AbstractCommand::handle(){
|
||||
if(cmdStr.find(" ") == -1)
|
||||
return;
|
||||
|
||||
vector<int> spaceIds;
|
||||
arguments.clear();
|
||||
|
||||
for(int i = 0; i < cmdStr.length(); i++)
|
||||
if(cmdStr[i] == ' ')
|
||||
spaceIds.push_back(i);
|
||||
|
||||
arguments.push_back(cmdStr.substr(0, spaceIds[0]));
|
||||
|
||||
for(int i = 0; i < spaceIds.size(); i++){
|
||||
bool lastSpace = (i == spaceIds.size() - 1);
|
||||
string argument = cmdStr.substr(spaceIds[i] + 1, lastSpace ? string::npos : spaceIds[i + 1] - spaceIds[i] - 1);
|
||||
arguments.push_back(argument);
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractCommand::execute(){
|
||||
handle();
|
||||
validate();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#ifndef ABSTRACT_COMMAND_H
|
||||
#define ABSTRACT_COMMAND_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace battleship{
|
||||
class AbstractCommand{
|
||||
protected:
|
||||
AbstractCommand(std::string str) : cmdStr(str){}
|
||||
virtual void handle();
|
||||
virtual void validate(){}
|
||||
virtual void execute();
|
||||
|
||||
std::string cmdStr;
|
||||
std::vector<std::string> arguments;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,30 @@
|
||||
#include "addResourceCommand.h"
|
||||
#include "game.h"
|
||||
#include "player.h"
|
||||
#include "trader.h"
|
||||
|
||||
namespace battleship{
|
||||
void AddResourceCommand::validate(){
|
||||
if(arguments.size() != 3)
|
||||
return;
|
||||
|
||||
playerId = atoi(arguments[0].c_str());
|
||||
|
||||
if(playerId != 0 && playerId != 1)
|
||||
return;
|
||||
|
||||
resourceId = atoi(arguments[1].c_str());
|
||||
|
||||
if(!(0 <= resourceId && resourceId <= 2))
|
||||
return;
|
||||
|
||||
resourceAmmount = atoi(arguments[2].c_str());
|
||||
}
|
||||
|
||||
void AddResourceCommand::execute(){
|
||||
AbstractCommand::execute();
|
||||
|
||||
Player *player = Game::getSingleton()->getPlayer(playerId);
|
||||
player->updateResource(ResourceType(resourceId), resourceAmmount, true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef ADD_RESOURCE_COMMAND_H
|
||||
#define ADD_RESOURCE_COMMAND_H
|
||||
|
||||
#include "abstractCommand.h"
|
||||
|
||||
namespace battleship{
|
||||
class AddResourceCommand : public AbstractCommand{
|
||||
public:
|
||||
AddResourceCommand(std::string argsStr) : AbstractCommand(argsStr){}
|
||||
void execute();
|
||||
private:
|
||||
void validate();
|
||||
|
||||
int playerId, resourceId, resourceAmmount;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,37 @@
|
||||
#include "addTechnologyCommand.h"
|
||||
#include "game.h"
|
||||
#include "player.h"
|
||||
|
||||
#include <solUtil.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace battleship{
|
||||
using namespace std;
|
||||
using namespace gameBase;
|
||||
|
||||
void AddTechnologyCommand::validate(){
|
||||
if(arguments.size() != 2)
|
||||
return;
|
||||
|
||||
playerId = atoi(arguments[0].c_str());
|
||||
int numPlayers = Game::getSingleton()->getNumPlayers();
|
||||
|
||||
if(!(0 <= playerId && playerId < numPlayers))
|
||||
return;
|
||||
|
||||
sol::state_view SOL_LUA_VIEW = generateView();
|
||||
SOL_LUA_VIEW.script("numTechs = #technologies");
|
||||
int numTechs = SOL_LUA_VIEW["numTechs"];
|
||||
|
||||
techId = atoi(arguments[1].c_str());
|
||||
|
||||
if(!(0 <= techId && techId < numTechs))
|
||||
return;
|
||||
}
|
||||
|
||||
void AddTechnologyCommand::execute(){
|
||||
AbstractCommand::execute();
|
||||
Game::getSingleton()->getPlayer(playerId)->addTechnology(techId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef ADD_TECHNOLOGY_H
|
||||
#define ADD_TECHNOLOGY_H
|
||||
|
||||
#include "abstractCommand.h"
|
||||
|
||||
namespace battleship{
|
||||
class AddTechnologyCommand : public AbstractCommand{
|
||||
public:
|
||||
AddTechnologyCommand(std::string argsStr) : AbstractCommand(argsStr){}
|
||||
void execute();
|
||||
private:
|
||||
void validate();
|
||||
|
||||
int playerId, techId;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,63 @@
|
||||
#include <solUtil.h>
|
||||
#include <stateManager.h>
|
||||
|
||||
#include "addUnitCommand.h"
|
||||
#include "console.h"
|
||||
#include "addUnitCommand.h"
|
||||
#include "inGameAppState.h"
|
||||
#include "game.h"
|
||||
#include "player.h"
|
||||
#include "gameObjectFactory.h"
|
||||
|
||||
namespace battleship{
|
||||
using namespace gameBase;
|
||||
using namespace vb01;
|
||||
using namespace std;
|
||||
|
||||
//TODO implement structure build status argument
|
||||
void AddUnitCommand::validate(){
|
||||
if(!(arguments.size() == 2 || arguments.size() == 5 || arguments.size() == 9))
|
||||
return;
|
||||
|
||||
playerId = atoi(arguments[0].c_str());
|
||||
|
||||
if(playerId != 0 && playerId != 1)
|
||||
return;
|
||||
|
||||
unitId = atoi(arguments[1].c_str());
|
||||
|
||||
sol::state_view SOL_LUA_VIEW = generateView();
|
||||
string varName = "numUnits";
|
||||
SOL_LUA_VIEW.script(varName + " = #units");
|
||||
int numUnits = SOL_LUA_VIEW[varName];
|
||||
|
||||
if(!(0 <= unitId && unitId <= numUnits))
|
||||
return;
|
||||
|
||||
if(arguments.size() >= 5){
|
||||
float x = atoi(arguments[2].c_str());
|
||||
float y = atoi(arguments[3].c_str());
|
||||
float z = atoi(arguments[4].c_str());
|
||||
pos = Vector3(x, y, z);
|
||||
}
|
||||
else if(2 < arguments.size() && arguments.size() < 5)
|
||||
return;
|
||||
|
||||
if(arguments.size() == 9){
|
||||
float w = atoi(arguments[5].c_str());
|
||||
float x = atoi(arguments[6].c_str());
|
||||
float y = atoi(arguments[7].c_str());
|
||||
float z = atoi(arguments[8].c_str());
|
||||
rot = Quaternion(w, x, y, z);
|
||||
}
|
||||
else if(5 < arguments.size() && arguments.size() < 9)
|
||||
return;
|
||||
}
|
||||
|
||||
void AddUnitCommand::execute(){
|
||||
AbstractCommand::execute();
|
||||
|
||||
Player* player = Game::getSingleton()->getPlayer(playerId);
|
||||
player->addUnit(GameObjectFactory::createUnit(player, unitId, pos, rot, 100));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
#ifndef ADD_UNIT_COMMAND_H
|
||||
#define ADD_UNIT_COMMAND_H
|
||||
|
||||
#include "abstractCommand.h"
|
||||
|
||||
#include <vector.h>
|
||||
#include <quaternion.h>
|
||||
|
||||
namespace battleship{
|
||||
class AddUnitCommand : public AbstractCommand{
|
||||
public:
|
||||
AddUnitCommand(std::string argsStr) : AbstractCommand(argsStr){}
|
||||
void validate();
|
||||
void execute();
|
||||
private:
|
||||
int playerId, unitId;
|
||||
bool posEnabled, rotEnabled;
|
||||
vb01::Vector3 pos = vb01::Vector3::VEC_ZERO;
|
||||
vb01::Quaternion rot = vb01::Quaternion::QUAT_W;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,28 @@
|
||||
#include "console.h"
|
||||
#include "addUnitCommand.h"
|
||||
#include "addResourceCommand.h"
|
||||
#include "addTechnologyCommand.h"
|
||||
#include "toggleDebugCommand.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace battleship{
|
||||
void Console::execute(string cmdStr) {
|
||||
int space = cmdStr.find(" ");
|
||||
string cmdName = cmdStr, argsStr = "";
|
||||
|
||||
if(space != -1){
|
||||
cmdName = cmdStr.substr(0, space);
|
||||
argsStr = cmdStr.substr(space + 1, string::npos);
|
||||
}
|
||||
|
||||
if(cmdName == "add-unit")
|
||||
AddUnitCommand(argsStr).execute();
|
||||
else if(cmdName == "add-resource")
|
||||
AddResourceCommand(argsStr).execute();
|
||||
else if(cmdName == "add-technology")
|
||||
AddTechnologyCommand(argsStr).execute();
|
||||
else if(cmdName == "toggle-debug")
|
||||
ToggleDebugCommand(argsStr).execute();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#ifndef CONSOLE_COMMAND_H
|
||||
#define CONSOLE_COMMAND_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace battleship{
|
||||
class Console{
|
||||
public:
|
||||
static void execute(std::string);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,15 @@
|
||||
#include "toggleDebugCommand.h"
|
||||
#include "game.h"
|
||||
|
||||
namespace battleship{
|
||||
void ToggleDebugCommand::validate(){
|
||||
if(!arguments.empty()) return;
|
||||
}
|
||||
|
||||
void ToggleDebugCommand::execute(){
|
||||
AbstractCommand::execute();
|
||||
|
||||
Game *game = Game::getSingleton();
|
||||
game->setDebug(!game->isDebug());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
#ifndef TOGGLE_DEBUG_COMMAND_H
|
||||
#define TOGGLE_DEBUG_COMMAND_H
|
||||
|
||||
#include "abstractCommand.h"
|
||||
|
||||
namespace battleship{
|
||||
class ToggleDebugCommand : public AbstractCommand{
|
||||
public:
|
||||
ToggleDebugCommand(std::string str) : AbstractCommand(str){}
|
||||
void validate();
|
||||
void execute();
|
||||
private:
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,72 @@
|
||||
#include "cameraController.h"
|
||||
#include "defConfigs.h"
|
||||
|
||||
#include <quaternion.h>
|
||||
#include <root.h>
|
||||
#include <camera.h>
|
||||
|
||||
namespace battleship{
|
||||
using namespace vb01;
|
||||
using namespace configData;
|
||||
|
||||
static CameraController *cameraController = nullptr;
|
||||
|
||||
CameraController* CameraController::getSingleton(){
|
||||
if(!cameraController)
|
||||
cameraController = new CameraController();
|
||||
|
||||
return cameraController;
|
||||
}
|
||||
|
||||
void CameraController::updateCameraPosition() {
|
||||
GameManager *gm = GameManager::getSingleton();
|
||||
Vector2 cursorPos = getCursorPos();
|
||||
|
||||
Camera *cam = Root::getSingleton()->getCamera();
|
||||
Vector3 camDir = cam->getDirection();
|
||||
Vector3 forwVec = Vector3(camDir.x, 0, camDir.z).norm();
|
||||
Vector3 camLeft = cam->getLeft();
|
||||
camLeft = Vector3(camLeft.x, 0, camLeft.z).norm();
|
||||
|
||||
int width, height;
|
||||
glfwGetWindowSize(Root::getSingleton()->getWindow(), &width, &height);
|
||||
|
||||
if (cursorPos.x <= 0 && 0 < cursorPos.y && cursorPos.y < height)
|
||||
cam->setPosition(cam->getPosition() - camLeft * camPanSpeed);
|
||||
|
||||
if (cursorPos.x >= width && 0 < cursorPos.y && cursorPos.y < height)
|
||||
cam->setPosition(cam->getPosition() + camLeft * camPanSpeed);
|
||||
|
||||
if (cursorPos.y <= 0 && 0 < cursorPos.x && cursorPos.x < width)
|
||||
cam->setPosition(cam->getPosition() + forwVec * camPanSpeed);
|
||||
|
||||
if (cursorPos.y >= height && 0 < cursorPos.x && cursorPos.x < width)
|
||||
cam->setPosition(cam->getPosition() - forwVec * camPanSpeed);
|
||||
}
|
||||
|
||||
void CameraController::orientCamera(Vector3 rotAxis, double str){
|
||||
Quaternion rotQuat = Quaternion(.025 * str, rotAxis);
|
||||
Camera *cam = Root::getSingleton()->getCamera();
|
||||
Vector3 dir = rotQuat * cam->getDirection(), up = rotQuat * cam->getUp();
|
||||
cam->lookAt(dir, up);
|
||||
}
|
||||
|
||||
void CameraController::zoomCamera(bool zoomIn){
|
||||
if((zoomIn && numZooms > configData::NUM_MAX_ZOOMS) || (!zoomIn && numZooms < -configData::NUM_MAX_ZOOMS)) return;
|
||||
|
||||
Vector3 newPos;
|
||||
float offset;
|
||||
|
||||
if(zoomIn){
|
||||
numZooms++;
|
||||
offset = configData::CAMERA_ZOOM_INCREMENT;
|
||||
}
|
||||
else{
|
||||
numZooms--;
|
||||
offset = -configData::CAMERA_ZOOM_INCREMENT;
|
||||
}
|
||||
|
||||
Camera *cam = Root::getSingleton()->getCamera();
|
||||
cam->setPosition(cam->getPosition() + cam->getDirection() * offset);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
#ifndef CAMERA_CONTROLLER_H
|
||||
#define CAMERA_CONTROLLER_H
|
||||
|
||||
#include <vector.h>
|
||||
|
||||
namespace battleship{
|
||||
class CameraController{
|
||||
public:
|
||||
static CameraController* getSingleton();
|
||||
void updateCameraPosition();
|
||||
void orientCamera(vb01::Vector3, double);
|
||||
void zoomCamera(bool);
|
||||
inline bool isLookingAround(){return lookingAround;}
|
||||
inline void setLookingAround(bool l){lookingAround = l;}
|
||||
private:
|
||||
CameraController(){}
|
||||
|
||||
bool lookingAround = false;
|
||||
int numZooms = 0;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,652 @@
|
||||
#include <solUtil.h>
|
||||
#include <soundManager.h>
|
||||
|
||||
#include <quad.h>
|
||||
|
||||
#include "concreteGuiManager.h"
|
||||
#include "unit.h"
|
||||
#include "gameManager.h"
|
||||
#include "singlePlayerButton.h"
|
||||
#include "mapEditorButton.h"
|
||||
#include "optionsButton.h"
|
||||
#include "exitButton.h"
|
||||
#include "tabButton.h"
|
||||
#include "okButton.h"
|
||||
#include "defaultsButton.h"
|
||||
#include "backButton.h"
|
||||
#include "newMapButton.h"
|
||||
#include "loadMapButton.h"
|
||||
#include "exportButton.h"
|
||||
#include "mapListbox.h"
|
||||
#include "skyboxTextureListbox.h"
|
||||
#include "landTextureListbox.h"
|
||||
#include "gameObjectListbox.h"
|
||||
#include "playButton.h"
|
||||
#include "inGameAppState.h"
|
||||
#include "mainMenuButton.h"
|
||||
#include "buildButton.h"
|
||||
#include "trainButton.h"
|
||||
#include "statsButton.h"
|
||||
#include "researchButton.h"
|
||||
#include "tradeButton.h"
|
||||
#include "activeStateButton.h"
|
||||
#include "playerTradeButton.h"
|
||||
#include "tradingScreenButton.h"
|
||||
#include "offerButton.h"
|
||||
#include "resourceAmmountButton.h"
|
||||
#include "orderButton.h"
|
||||
#include "stateToggleButton.h"
|
||||
#include "minimapButton.h"
|
||||
#include "activeStateBackButton.h"
|
||||
|
||||
namespace battleship{
|
||||
using namespace std;
|
||||
using namespace gameBase;
|
||||
using namespace vb01;
|
||||
using namespace vb01Gui;
|
||||
|
||||
static ConcreteGuiManager *concreteGuiManager = nullptr;
|
||||
|
||||
ConcreteGuiManager::ConcreteGuiManager(){
|
||||
string assetPath = GameManager::getSingleton()->getPath();
|
||||
texBasePath = assetPath + "Textures/";
|
||||
fontBasePath = assetPath + "Fonts/";
|
||||
}
|
||||
|
||||
ConcreteGuiManager* ConcreteGuiManager::getSingleton(){
|
||||
if(!concreteGuiManager)
|
||||
concreteGuiManager = new ConcreteGuiManager();
|
||||
|
||||
return concreteGuiManager;
|
||||
}
|
||||
|
||||
//TODO refactor player difficulty and faction listbox selection
|
||||
//TODO remove hardcoded font path values
|
||||
//TODO use configurable map path values
|
||||
Button* ConcreteGuiManager::parseButton(int guiId){
|
||||
sol::state_view SOL_LUA_STATE = generateView();
|
||||
sol::table guiTable = SOL_LUA_STATE["gui"][guiId + 1];
|
||||
|
||||
sol::table posTable = guiTable["pos"];
|
||||
Vector3 pos = Vector3(posTable["x"], posTable["y"], posTable["z"]);
|
||||
|
||||
sol::table sizeTable = guiTable["size"];
|
||||
Vector2 size = Vector2(sizeTable["x"], sizeTable["y"]);
|
||||
|
||||
//TODO factor out repetetive optional lua key checks
|
||||
string name = "", nk = "name";
|
||||
sol::optional<string> nameOpt = guiTable[nk];
|
||||
|
||||
if(nameOpt != sol::nullopt) name = guiTable[nk];
|
||||
|
||||
ButtonType type = (ButtonType)guiTable["buttonType"];
|
||||
|
||||
string imagePath = "", ipk = "imagePath";
|
||||
sol::optional<string> pathOpt = guiTable[ipk];
|
||||
bool texturingEnabled = false;
|
||||
|
||||
if(pathOpt != sol::nullopt){
|
||||
imagePath = texBasePath;
|
||||
imagePath += guiTable[ipk];
|
||||
bool texturingEnabled = true;
|
||||
}
|
||||
|
||||
Button *button = nullptr;
|
||||
string guiScreen = "";
|
||||
|
||||
switch(type){
|
||||
case SINGLE_PLAYER:
|
||||
button = new SinglePlayerButton(pos, size, name);
|
||||
break;
|
||||
case EDITOR:
|
||||
button = new MapEditorButton(pos, size);
|
||||
break;
|
||||
case OPTIONS:
|
||||
button = new OptionsButton(pos, size, name, true);
|
||||
break;
|
||||
case EXIT:
|
||||
button = new ExitButton(pos, size);
|
||||
break;
|
||||
case OK:
|
||||
button = new OkButton(pos, size, name);
|
||||
break;
|
||||
case DEFAULTS:
|
||||
button = new DefaultsButton(pos, size, name);
|
||||
break;
|
||||
case BACK: {
|
||||
string screen = guiTable["screen"];
|
||||
button = new BackButton(pos, size, name, screen);
|
||||
break;
|
||||
}
|
||||
case CONTROLS_TAB:
|
||||
case MOUSE_TAB:
|
||||
case VIDEO_TAB:
|
||||
case AUDIO_TAB:
|
||||
case MULTIPLAYER_TAB: {
|
||||
string screens[]{
|
||||
"controlsTab.lua",
|
||||
"mouseTab.lua",
|
||||
"videoTab.lua",
|
||||
"audioTab.lua",
|
||||
"multiplayerTab.lua"
|
||||
};
|
||||
int diff = ((int)type - (int)CONTROLS_TAB);
|
||||
button = new TabButton(pos, size, name, screens[diff]);
|
||||
break;
|
||||
}
|
||||
case NEW_MAP:
|
||||
button = new NewMapButton(pos, size);
|
||||
break;
|
||||
case NEW_MAP_OK:{
|
||||
int numTextboxes = guiTable["numDependencies"];
|
||||
vector<Textbox*> t;
|
||||
|
||||
for(int i = 0; i < numTextboxes; i++){
|
||||
int tid = guiTable["dependencies"][i + 1]["id"];
|
||||
t.push_back((Textbox*)guiElements[tid].second);
|
||||
}
|
||||
|
||||
button = new NewMapButton::OkButton(pos, size, t[0], t[1], t[2]);
|
||||
break;
|
||||
}
|
||||
case LOAD_MAP:
|
||||
button = new LoadMapButton(pos, size);
|
||||
break;
|
||||
case LOAD_MAP_OK:{
|
||||
int lid = guiTable["dependencies"][1]["id"];
|
||||
button = new LoadMapButton::OkButton(pos, size, (Listbox*)guiElements[lid].second);
|
||||
break;
|
||||
}
|
||||
case EXPORT:
|
||||
button = new ExportButton(pos, size);
|
||||
break;
|
||||
case PLAY:{
|
||||
int mid = guiTable["dependencies"][1]["id"];
|
||||
Listbox *mapListbox = (MapListbox*)guiElements[mid].second;
|
||||
button = new PlayButton(mapListbox, pos, size, name, true);
|
||||
break;
|
||||
}
|
||||
case RESUME:
|
||||
button = new InGameAppState::ResumeButton(pos, size);
|
||||
break;
|
||||
case CONSOLE_SCREEN:
|
||||
button = new InGameAppState::ConsoleButton(pos, size);
|
||||
break;
|
||||
case MAIN_MENU:
|
||||
button = new MainMenuButton(pos, size, name);
|
||||
break;
|
||||
case CONSOLE_COMMAND_OK:{
|
||||
int lid = guiTable["dependencies"][1]["id"];
|
||||
Listbox *listbox = (Listbox*)guiElements[lid].second;
|
||||
|
||||
int tid = guiTable["dependencies"][2]["id"];
|
||||
Textbox *textbox = (Textbox*)guiElements[tid].second;
|
||||
|
||||
button = new InGameAppState::ConsoleButton::ConsoleCommandEntryButton(textbox, listbox, pos, size, name);
|
||||
break;
|
||||
}
|
||||
case BUILD:
|
||||
button = new BuildButton(pos, size, name, (int)guiTable["trigger"], imagePath, (int)guiTable["slotId"]);
|
||||
break;
|
||||
case TRAIN:
|
||||
button = new TrainButton(pos, size, name, (int)guiTable["trigger"], imagePath, (int)guiTable["slotId"]);
|
||||
break;
|
||||
case STATISTICS:
|
||||
button = new StatsButton(pos, size, name, (int)guiTable["trigger"], imagePath);
|
||||
break;
|
||||
case RESEARCH:
|
||||
button = new ResearchButton(pos, size, name, (int)guiTable["trigger"], imagePath, (int)guiTable["techId"]);
|
||||
break;
|
||||
case BUY_REFINEDS:
|
||||
button = new TradeButton(pos, size, name, (int)guiTable["trigger"], imagePath, TradeButton::Type::BUY_REFINEDS);
|
||||
break;
|
||||
case SELL_REFINEDS:
|
||||
button = new TradeButton(pos, size, name, (int)guiTable["trigger"], imagePath, TradeButton::Type::SELL_REFINEDS);
|
||||
break;
|
||||
case BUY_RESEARCH:
|
||||
button = new TradeButton(pos, size, name, (int)guiTable["trigger"], imagePath, TradeButton::Type::BUY_RESEARCH);
|
||||
break;
|
||||
case SELL_RESEARCH:
|
||||
button = new TradeButton(pos, size, name, (int)guiTable["trigger"], imagePath, TradeButton::Type::SELL_RESEARCH);
|
||||
break;
|
||||
case ACTIVE_STATE_BUTTON:
|
||||
button = new ActiveStateButton(pos, size, guiTable["guiScreen"], name, fontBasePath + "batang.ttf", (int)guiTable["trigger"], imagePath);
|
||||
break;
|
||||
case ACTIVE_STATE_BACK:
|
||||
button = new ActiveStateBackButton(pos, size, name);
|
||||
break;
|
||||
case PLAYER_TRADE:
|
||||
guiScreen = guiTable["guiScreen"];
|
||||
button = new PlayerTradeButton(pos, size, guiScreen, name, (int)guiTable["trigger"], imagePath);
|
||||
break;
|
||||
case TRADING_SCREEN:{
|
||||
int lid = guiTable["dependencies"][1]["id"];
|
||||
Listbox *listbox = (Listbox*)guiElements[lid].second;
|
||||
guiScreen = guiTable["guiScreen"];
|
||||
|
||||
button = new TradingScreenButton(pos, size, listbox, (int)SOL_LUA_STATE["playerId"], guiScreen, name, (int)guiTable["trigger"], imagePath);
|
||||
break;
|
||||
}
|
||||
case TRADE_OFFER:
|
||||
button = new OfferButton(pos, size, (int)SOL_LUA_STATE["playerId"], name, (int)guiTable["trigger"], imagePath);
|
||||
break;
|
||||
case RESOURCE_AMMOUNT:
|
||||
button = new ResourceAmmountButton(pos, size, name, (int)guiTable["ammount"], (int)guiTable["trigger"], imagePath);
|
||||
break;
|
||||
case ORDER:
|
||||
button = new OrderButton(pos, size, name, (int)guiTable["trigger"], imagePath, (int)guiTable["orderType"]);
|
||||
break;
|
||||
case UNIT_STATE:
|
||||
button = new StateToggleButton(pos, size, name, (int)guiTable["trigger"], imagePath);
|
||||
break;
|
||||
case MINIMAP:{
|
||||
string minimapPath = GameManager::getSingleton()->getPath() + "Models/Maps/" + Map::getSingleton()->getMapName() + "/minimap.jpg";
|
||||
button = new MinimapButton(pos, size, minimapPath);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int typeArr[2]{(int)GuiElementType::BUTTON, (int)type};
|
||||
guiElements.push_back(make_pair(typeArr, (void*)button));
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
Listbox* ConcreteGuiManager::parseGameObjectListbox(){
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Listbox* ConcreteGuiManager::parseListbox(int guiId){
|
||||
sol::state_view SOL_LUA_STATE = generateView();
|
||||
sol::table guiTable = SOL_LUA_STATE["gui"][guiId + 1];
|
||||
|
||||
string posTable = "pos";
|
||||
Vector3 pos = Vector3(guiTable[posTable]["x"], guiTable[posTable]["y"], guiTable[posTable]["z"]);
|
||||
|
||||
string sizeTable = "size";
|
||||
Vector2 size = Vector2(guiTable[sizeTable]["x"], guiTable[sizeTable]["y"]);
|
||||
|
||||
int numMaxDisplay = guiTable["numMaxDisplay"];
|
||||
ListboxType listboxType = (ListboxType)guiTable["listboxType"];
|
||||
|
||||
int maxDisplay, numLines;
|
||||
bool closable;
|
||||
vector<string> lines;
|
||||
sol::optional<sol::table> linesOpt = guiTable["lines"];
|
||||
|
||||
if(linesOpt != sol::nullopt){
|
||||
sol::table linesTbl = guiTable["lines"];
|
||||
|
||||
for(int i = 0; i < linesTbl.size(); i++)
|
||||
lines.push_back(guiTable["lines"][i + 1]);
|
||||
}
|
||||
|
||||
Listbox *listbox = nullptr;
|
||||
string fontPath = fontBasePath + "batang.ttf";
|
||||
sol::optional<string> nameOpt = guiTable["name"];
|
||||
string name = "";
|
||||
|
||||
if(nameOpt != sol::nullopt) name = guiTable["name"];
|
||||
|
||||
switch(listboxType){
|
||||
case CONTROLS:{
|
||||
numLines = 6;
|
||||
closable = false;
|
||||
|
||||
for(int i = 0; i < numLines; i++)
|
||||
lines.push_back(to_string(i));
|
||||
|
||||
maxDisplay = (numLines > numMaxDisplay ? numMaxDisplay : numLines);
|
||||
listbox = new Listbox(pos, size, lines, maxDisplay, fontPath, closable);
|
||||
|
||||
break;
|
||||
}
|
||||
case RESOLUTION:{
|
||||
numLines = guiTable["numLines"];
|
||||
|
||||
for(int i = 0; i < numLines; i++)
|
||||
lines.push_back(guiTable["lines"][i + 1]);
|
||||
|
||||
closable = true;
|
||||
maxDisplay = (numLines > numMaxDisplay ? numMaxDisplay : numLines);
|
||||
|
||||
listbox = new Listbox(pos, size, lines, maxDisplay, fontPath, closable);
|
||||
|
||||
break;
|
||||
}
|
||||
case MAPS:{
|
||||
lines = readDir(GameManager::getSingleton()->getPath() + "Models/Maps/", true);
|
||||
numLines = lines.size();
|
||||
closable = true;
|
||||
maxDisplay = (numLines > numMaxDisplay ? numMaxDisplay : numLines);
|
||||
bool addPlayers = guiTable["addPlayerGui"];
|
||||
|
||||
listbox = new MapListbox(pos, size, lines, maxDisplay, addPlayers, fontPath, closable);
|
||||
break;
|
||||
}
|
||||
case VEHICLES:
|
||||
case STRUCTURES:
|
||||
case RESOURCE_DEPOSITS:{
|
||||
bool resources = (listboxType == RESOURCE_DEPOSITS);
|
||||
sol::table gameObjTable = SOL_LUA_STATE[resources ? "resources" : "units"];
|
||||
int numGameObjs = gameObjTable.size();
|
||||
std::vector<int> gameObjIds;
|
||||
|
||||
for(int i = 0; i < numGameObjs; i++){
|
||||
bool canAdd = true;
|
||||
|
||||
if(!resources){
|
||||
bool vehicles = (listboxType == VEHICLES);
|
||||
bool v = gameObjTable[i + 1]["isVehicle"];
|
||||
canAdd = (v == vehicles);
|
||||
}
|
||||
|
||||
if(canAdd){
|
||||
lines.push_back(gameObjTable[i + 1]["name"]);
|
||||
gameObjIds.push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
numLines = lines.size();
|
||||
closable = true;
|
||||
maxDisplay = (numLines > numMaxDisplay ? numMaxDisplay : numLines);
|
||||
|
||||
listbox = new GameObjectListbox(!resources, pos, size, lines, gameObjIds, maxDisplay, fontPath);
|
||||
break;
|
||||
}
|
||||
case SKYBOX_TEXTURES:
|
||||
lines = readDir(texBasePath + "Skyboxes", true);
|
||||
numLines = lines.size();
|
||||
closable = true;
|
||||
maxDisplay = (numLines > numMaxDisplay ? numMaxDisplay : numLines);
|
||||
|
||||
listbox = new SkyboxTextureListbox(pos, size, lines, maxDisplay, fontPath);
|
||||
break;
|
||||
case LAND_TEXTURES:
|
||||
lines = readDir(texBasePath + "Landmass", false);
|
||||
numLines = lines.size();
|
||||
closable = true;
|
||||
maxDisplay = (numLines > numMaxDisplay ? numMaxDisplay : numLines);
|
||||
|
||||
listbox = new LandTextureListbox(pos, size, lines, maxDisplay, fontPath);
|
||||
break;
|
||||
case CPU_DIFFICULTIES:
|
||||
case FACTIONS:
|
||||
case COLORS:
|
||||
case TEAMS:
|
||||
numLines = lines.size();
|
||||
closable = true;
|
||||
maxDisplay = (numLines > numMaxDisplay ? numMaxDisplay : numLines);
|
||||
|
||||
listbox = new Listbox(pos, size, lines, maxDisplay, fontPath);
|
||||
break;
|
||||
case CONSOLE:{
|
||||
for(int i = 0; i < numMaxDisplay; i++)
|
||||
lines.push_back("");
|
||||
|
||||
closable = false;
|
||||
maxDisplay = (numLines > numMaxDisplay ? numMaxDisplay : numLines);
|
||||
|
||||
listbox = new Listbox(pos, size, lines, maxDisplay, fontPath, closable);
|
||||
}
|
||||
break;
|
||||
case TRADE_OFFERS:
|
||||
closable = true;
|
||||
listbox = new Listbox(pos, size, lines, numMaxDisplay, fontPath, closable);
|
||||
break;
|
||||
}
|
||||
|
||||
int typeArr[2]{(int)GuiElementType::LISTBOX, (int)listboxType};
|
||||
guiElements.push_back(make_pair(typeArr, (void*)listbox));
|
||||
|
||||
listbox->setName(name);
|
||||
|
||||
return listbox;
|
||||
}
|
||||
|
||||
Checkbox* ConcreteGuiManager::parseCheckbox(int guiId){
|
||||
sol::state_view SOL_LUA_STATE = generateView();
|
||||
sol::table guiTable = SOL_LUA_STATE["gui"][guiId + 1];
|
||||
|
||||
string posTable = "pos";
|
||||
Vector3 pos = Vector3(guiTable[posTable]["x"], guiTable[posTable]["y"], guiTable[posTable]["z"]);
|
||||
Checkbox *checkbox = new Checkbox(pos, fontBasePath + "batang.ttf");
|
||||
|
||||
int typeArr[2]{(int)GuiElementType::CHECKBOX, -1};
|
||||
guiElements.push_back(make_pair(typeArr, (void*)checkbox));
|
||||
|
||||
return checkbox;
|
||||
}
|
||||
|
||||
Slider* ConcreteGuiManager::parseSlider(int guiId){
|
||||
sol::state_view SOL_LUA_STATE = generateView();
|
||||
sol::table guiTable = SOL_LUA_STATE["gui"][guiId + 1];
|
||||
|
||||
string posTable = "pos", sizeTable = "size";
|
||||
Vector3 pos = Vector3(guiTable[posTable]["x"], guiTable[posTable]["y"], guiTable[posTable]["z"]);
|
||||
Vector2 size = Vector2(guiTable[sizeTable]["x"], guiTable[sizeTable]["y"]);
|
||||
|
||||
Slider *slider = new Slider(pos, size, guiTable["minValue"], guiTable["maxValue"]);
|
||||
|
||||
int typeArr[2]{(int)GuiElementType::SLIDER, -1};
|
||||
guiElements.push_back(make_pair(typeArr, (void*)slider));
|
||||
|
||||
return slider;
|
||||
}
|
||||
|
||||
Textbox* ConcreteGuiManager::parseTextbox(int guiId){
|
||||
sol::state_view SOL_LUA_STATE = generateView();
|
||||
sol::table guiTable = SOL_LUA_STATE["gui"][guiId + 1];
|
||||
|
||||
string posTable = "pos", sizeTable = "size";
|
||||
Vector3 pos = Vector3(guiTable[posTable]["x"], guiTable[posTable]["y"], guiTable[posTable]["z"]);
|
||||
Vector2 size = Vector2(guiTable[sizeTable]["x"], guiTable[sizeTable]["y"]);
|
||||
Textbox *textbox = new Textbox(pos, size, fontBasePath + "batang.ttf");
|
||||
|
||||
int typeArr[2]{(int)GuiElementType::TEXTBOX, -1};
|
||||
guiElements.push_back(make_pair(typeArr, (void*)textbox));
|
||||
|
||||
return textbox;
|
||||
}
|
||||
|
||||
//TODO factor out checking for optional lua values
|
||||
Node* ConcreteGuiManager::parseGuiRectangle(int guiId){
|
||||
sol::state_view SOL_LUA_STATE = generateView();
|
||||
sol::table guiTable = SOL_LUA_STATE["gui"][guiId + 1];
|
||||
|
||||
Root *root = Root::getSingleton();
|
||||
Material *mat = new Material(root->getLibPath() + "gui");
|
||||
mat->setTransparent(true);
|
||||
|
||||
bool texturingEnabled = false;
|
||||
string imagePath = "", ipk = "imagePath";
|
||||
sol::optional<string> pathOpt = guiTable[ipk];
|
||||
|
||||
if(pathOpt != sol::nullopt){
|
||||
imagePath = guiTable[ipk];
|
||||
texturingEnabled = true;
|
||||
}
|
||||
|
||||
string name = "", nk = "name";
|
||||
sol::optional<string> nameOpt = guiTable[nk];
|
||||
|
||||
if(nameOpt != sol::nullopt) name = guiTable[nk];
|
||||
|
||||
mat->addBoolUniform("texturingEnabled", texturingEnabled);
|
||||
|
||||
if(texturingEnabled){
|
||||
string p[]{texBasePath + imagePath};
|
||||
Texture *tex = new Texture(p, 1, false);
|
||||
mat->addTexUniform("diffuseMap", tex, false);
|
||||
}
|
||||
else{
|
||||
sol::table colorTable = guiTable["color"];
|
||||
mat->addVec4Uniform("diffuseColor", Vector4(colorTable["x"], colorTable["y"], colorTable["z"], colorTable["w"]));
|
||||
}
|
||||
|
||||
sol::table sizeTable = guiTable["size"];
|
||||
Quad *quad = new Quad(Vector3(sizeTable["x"], sizeTable["y"], 1), false);
|
||||
quad->setMaterial(mat);
|
||||
|
||||
sol::table posTable = guiTable["pos"];
|
||||
Node *guiRectangle = new Node(Vector3(posTable["x"], posTable["y"], posTable["z"]), Quaternion::QUAT_W, Vector3::VEC_IJK, name);
|
||||
guiRectangle->attachMesh(quad);
|
||||
root->getGuiNode()->attachChild(guiRectangle);
|
||||
|
||||
int typeArr[2]{(int)GuiElementType::GUI_RECTANGLE, -1};
|
||||
guiElements.push_back(make_pair(typeArr, (void*)guiRectangle));
|
||||
|
||||
return guiRectangle;
|
||||
}
|
||||
|
||||
//TODO distinguish between floats and vector-like tables for scale
|
||||
Text* ConcreteGuiManager::parseText(int guiId){
|
||||
sol::state_view SOL_LUA_STATE = generateView();
|
||||
sol::table guiTable = SOL_LUA_STATE["gui"][guiId + 1];
|
||||
sol::table posTable = guiTable["pos"];
|
||||
|
||||
Root *root = Root::getSingleton();
|
||||
|
||||
Material *mat = new Material(root->getLibPath() + "text");
|
||||
mat->addBoolUniform("texturingEnabled", false);
|
||||
sol::table colorTable = guiTable["color"];
|
||||
mat->addVec4Uniform("diffuseColor", Vector4(colorTable["x"], colorTable["y"], colorTable["z"], colorTable["w"]));
|
||||
|
||||
string font = guiTable["font"];
|
||||
wstring entry = guiTable["text"];
|
||||
Text *text = new Text(fontBasePath + font, entry, guiTable["fontFirstChar"], guiTable["fontLastChar"]);
|
||||
text->setMaterial(mat);
|
||||
|
||||
Vector3 pos = Vector3(posTable["x"], posTable["y"], posTable["z"]);
|
||||
|
||||
SOL_LUA_STATE.script("tp = type(gui[" + to_string(guiId + 1) + "].scale)");
|
||||
string st = SOL_LUA_STATE["tp"];
|
||||
Vector3 scale;
|
||||
|
||||
if(st == "table"){
|
||||
sol::table scaleTable = guiTable["scale"];
|
||||
scale = Vector3(scaleTable["x"], scaleTable["y"], 1);
|
||||
}
|
||||
else if(st == "number"){
|
||||
float sc = guiTable["scale"];
|
||||
scale = Vector3(sc, sc, 1);
|
||||
}
|
||||
|
||||
Node *node = new Node(pos, Quaternion::QUAT_W, scale, guiTable["name"]);
|
||||
node->addText(text);
|
||||
root->getGuiNode()->attachChild(node);
|
||||
|
||||
int typeArr[2]{(int)GuiElementType::TEXT, -1};
|
||||
guiElements.push_back(make_pair(typeArr, (void*)text));
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
void ConcreteGuiManager::parseMusic(){
|
||||
sol::state_view SOL_STATE_VIEW = generateView();
|
||||
sol::optional<sol::table> musicTblOpt = SOL_STATE_VIEW["music"];
|
||||
|
||||
if(musicTblOpt == sol::nullopt) return;
|
||||
|
||||
sol::table musicTbl = SOL_STATE_VIEW["music"], tracksTbl = musicTbl["tracks"];
|
||||
SoundManager *sm = SoundManager::getSingleton();
|
||||
|
||||
if(tracksTbl.size() == 0){
|
||||
sm->clearPlaylist();
|
||||
return;
|
||||
}
|
||||
|
||||
bool loop = musicTbl["loop"], shuffle = musicTbl["shuffle"];
|
||||
int delay = musicTbl["delay"].get_or(0);
|
||||
int numTracks = tracksTbl.size();
|
||||
|
||||
vector<string> trackPaths;
|
||||
|
||||
for(int i = 0; i < numTracks; i++){
|
||||
string track = tracksTbl[i + 1];
|
||||
trackPaths.push_back(GameManager::getSingleton()->getPath() + "Sounds/Music/" + track);
|
||||
}
|
||||
|
||||
sm->play(trackPaths, 100, delay, loop, shuffle);
|
||||
}
|
||||
|
||||
void ConcreteGuiManager::readLuaScreenScript(
|
||||
string script,
|
||||
vector<Button*> buttonExceptions,
|
||||
vector<Listbox*> listboxExceptions,
|
||||
vector<Checkbox*> checkboxExceptions,
|
||||
vector<Slider*> sliderExceptions,
|
||||
vector<Textbox*> textboxExceptions,
|
||||
vector<Node*> guiRectboxExceptions,
|
||||
vector<Text*> textExceptions,
|
||||
string luaCode
|
||||
){
|
||||
removeAllGuiElements(buttonExceptions, listboxExceptions, checkboxExceptions, sliderExceptions, textboxExceptions, guiRectboxExceptions, textExceptions);
|
||||
parseLuaScript(script, luaCode);
|
||||
}
|
||||
|
||||
void ConcreteGuiManager::readLuaScreenScriptDel(
|
||||
string script,
|
||||
vector<Button*> buttons,
|
||||
vector<Listbox*> listboxs,
|
||||
vector<Checkbox*> checkboxs,
|
||||
vector<Slider*> sliders,
|
||||
vector<Textbox*> textboxs,
|
||||
vector<Node*> guiRectboxs,
|
||||
vector<Text*> texts
|
||||
){
|
||||
for(Button *b : buttons) removeButton(b);
|
||||
for(Listbox *l : listboxs) removeListbox(l);
|
||||
for(Checkbox *c : checkboxs) removeCheckbox(c);
|
||||
for(Slider *s : sliders) removeSlider(s);
|
||||
for(Textbox *t : textboxs) removeTextbox(t);
|
||||
for(Node *r : guiRectboxs) removeGuiRectangle(r);
|
||||
for(Text *t : texts) removeText(t);
|
||||
|
||||
parseLuaScript(script);
|
||||
}
|
||||
|
||||
void ConcreteGuiManager::parseLuaScript(string script, string luaCode){
|
||||
guiElements.clear();
|
||||
|
||||
string basePath = GameManager::getSingleton()->getPath() + "Scripts/Gui/";
|
||||
sol::state_view SOL_LUA_VIEW = generateView();
|
||||
SOL_LUA_VIEW.script("music = nil");
|
||||
SOL_LUA_VIEW.script_file(basePath + script);
|
||||
|
||||
if(luaCode != "") SOL_LUA_VIEW.script(luaCode);
|
||||
|
||||
SOL_LUA_VIEW.script("numGui = #gui");
|
||||
int numGuiElements = SOL_LUA_VIEW["numGui"];
|
||||
|
||||
for(int i = 0; i < numGuiElements; i++){
|
||||
int guiTypeId = SOL_LUA_VIEW["gui"][i + 1]["guiType"];
|
||||
|
||||
switch((GuiElementType)guiTypeId){
|
||||
case BUTTON:
|
||||
addButton(parseButton(i));
|
||||
break;
|
||||
case LISTBOX:
|
||||
addListbox(parseListbox(i));
|
||||
break;
|
||||
case CHECKBOX:
|
||||
addCheckbox(parseCheckbox(i));
|
||||
break;
|
||||
case SLIDER:
|
||||
addSlider(parseSlider(i));
|
||||
break;
|
||||
case TEXTBOX:
|
||||
addTextbox(parseTextbox(i));
|
||||
break;
|
||||
case GUI_RECTANGLE:
|
||||
addGuiRectangle(parseGuiRectangle(i));
|
||||
break;
|
||||
case TEXT:
|
||||
addText(parseText(i));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
parseMusic();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
#ifndef CONCRETE_GUI_MANAGER_H
|
||||
#define CONCRETE_GUI_MANAGER_H
|
||||
|
||||
#include <abstractGuiManager.h>
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace vb01{
|
||||
class Node;
|
||||
class Text;
|
||||
}
|
||||
|
||||
namespace battleship{
|
||||
enum GuiElementType {BUTTON, LISTBOX, CHECKBOX, SLIDER, TEXTBOX, GUI_RECTANGLE, TEXT, MUSIC};
|
||||
enum ButtonType {
|
||||
SINGLE_PLAYER,
|
||||
EDITOR,
|
||||
OPTIONS,
|
||||
EXIT,
|
||||
OK,
|
||||
DEFAULTS,
|
||||
BACK,
|
||||
CONTROLS_TAB,
|
||||
MOUSE_TAB,
|
||||
VIDEO_TAB,
|
||||
AUDIO_TAB,
|
||||
MULTIPLAYER_TAB,
|
||||
NEW_MAP,
|
||||
NEW_MAP_OK,
|
||||
LOAD_MAP,
|
||||
LOAD_MAP_OK,
|
||||
EXPORT,
|
||||
PLAY,
|
||||
RESUME,
|
||||
CONSOLE_SCREEN,
|
||||
MAIN_MENU,
|
||||
CONSOLE_COMMAND_OK,
|
||||
BUILD,
|
||||
TRAIN,
|
||||
STATISTICS,
|
||||
RESEARCH,
|
||||
BUY_REFINEDS,
|
||||
SELL_REFINEDS,
|
||||
BUY_RESEARCH,
|
||||
SELL_RESEARCH,
|
||||
ACTIVE_STATE_BUTTON,
|
||||
ACTIVE_STATE_BACK,
|
||||
PLAYER_TRADE,
|
||||
TRADING_SCREEN,
|
||||
TRADE_OFFER,
|
||||
RESOURCE_AMMOUNT,
|
||||
UNIT_STATE,
|
||||
ORDER,
|
||||
MINIMAP,
|
||||
};
|
||||
enum ListboxType {
|
||||
CONTROLS,
|
||||
RESOLUTION,
|
||||
MAPS,
|
||||
VEHICLES,
|
||||
STRUCTURES,
|
||||
RESOURCE_DEPOSITS,
|
||||
SKYBOX_TEXTURES,
|
||||
LAND_TEXTURES,
|
||||
CPU_DIFFICULTIES,
|
||||
FACTIONS,
|
||||
COLORS,
|
||||
TEAMS,
|
||||
CONSOLE,
|
||||
TRADE_OFFERS
|
||||
};
|
||||
|
||||
class ConcreteGuiManager : public vb01Gui::AbstractGuiManager{
|
||||
public:
|
||||
static ConcreteGuiManager* getSingleton();
|
||||
void readLuaScreenScript(
|
||||
std::string,
|
||||
std::vector<vb01Gui::Button*> = std::vector<vb01Gui::Button*>{},
|
||||
std::vector<vb01Gui::Listbox*> = std::vector<vb01Gui::Listbox*>{},
|
||||
std::vector<vb01Gui::Checkbox*> = std::vector<vb01Gui::Checkbox*>{},
|
||||
std::vector<vb01Gui::Slider*> = std::vector<vb01Gui::Slider*>{},
|
||||
std::vector<vb01Gui::Textbox*> = std::vector<vb01Gui::Textbox*>{},
|
||||
std::vector<vb01::Node*> = std::vector<vb01::Node*>{},
|
||||
std::vector<vb01::Text*> = std::vector<vb01::Text*>{},
|
||||
std::string = ""
|
||||
);
|
||||
void readLuaScreenScriptDel(
|
||||
std::string,
|
||||
std::vector<vb01Gui::Button*> = std::vector<vb01Gui::Button*>{},
|
||||
std::vector<vb01Gui::Listbox*> = std::vector<vb01Gui::Listbox*>{},
|
||||
std::vector<vb01Gui::Checkbox*> = std::vector<vb01Gui::Checkbox*>{},
|
||||
std::vector<vb01Gui::Slider*> = std::vector<vb01Gui::Slider*>{},
|
||||
std::vector<vb01Gui::Textbox*> = std::vector<vb01Gui::Textbox*>{},
|
||||
std::vector<vb01::Node*> = std::vector<vb01::Node*>{},
|
||||
std::vector<vb01::Text*> = std::vector<vb01::Text*>{}
|
||||
);
|
||||
void parseLuaScript(std::string, std::string = "");
|
||||
private:
|
||||
ConcreteGuiManager();
|
||||
vb01Gui::Button* parseButton(int);
|
||||
vb01Gui::Listbox* parseGameObjectListbox();
|
||||
vb01Gui::Listbox* parseListbox(int);
|
||||
vb01Gui::Checkbox* parseCheckbox(int);
|
||||
vb01Gui::Slider* parseSlider(int);
|
||||
vb01Gui::Textbox* parseTextbox(int);
|
||||
vb01::Node* parseGuiRectangle(int);
|
||||
vb01::Text* parseText(int);
|
||||
void parseMusic();
|
||||
|
||||
std::vector<std::pair<int*, void*>> guiElements;
|
||||
std::string texBasePath, fontBasePath;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,296 @@
|
||||
#include <solUtil.h>
|
||||
|
||||
#include "gameObjectFrameController.h"
|
||||
#include "activeGameState.h"
|
||||
#include "resourceDeposit.h"
|
||||
#include "defConfigs.h"
|
||||
#include "player.h"
|
||||
#include "game.h"
|
||||
#include "unit.h"
|
||||
#include "util.h"
|
||||
#include "map.h"
|
||||
|
||||
#include <material.h>
|
||||
#include <meshData.h>
|
||||
#include <quad.h>
|
||||
#include <model.h>
|
||||
#include <root.h>
|
||||
|
||||
#include <stateManager.h>
|
||||
#include <solUtil.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace battleship{
|
||||
using namespace std;
|
||||
using namespace vb01;
|
||||
using namespace gameBase;
|
||||
|
||||
static GameObjectFrameController *gameObjectFrameController = nullptr;
|
||||
|
||||
GameObjectFrameController* GameObjectFrameController::getSingleton(){
|
||||
if(!gameObjectFrameController)
|
||||
gameObjectFrameController = new GameObjectFrameController();
|
||||
|
||||
return gameObjectFrameController;
|
||||
}
|
||||
|
||||
void GameObjectFrameController::paintSelect(Vector3 rowEnd){
|
||||
Vector3 rowDir = rowEnd - paintSelectRowStart;
|
||||
float lenRow = rowDir.getLength();
|
||||
float width = gameObjectFrames[0].getWidth();
|
||||
float length = gameObjectFrames[0].getLength();
|
||||
float hypothenuse = sqrt(width * width + length * length);
|
||||
int numStructsInRow = int(lenRow / hypothenuse);
|
||||
|
||||
while(gameObjectFrames.size() > numStructsInRow && gameObjectFrames.size() > 1)
|
||||
removeGameObjectFrame(gameObjectFrames.size() - 1);
|
||||
|
||||
if(gameObjectFrames.size() < numStructsInRow){
|
||||
int structureId = gameObjectFrames[0].getId();
|
||||
Vector3 buildDir = rowDir;
|
||||
|
||||
if(gameObjectFrames.size() > 1)
|
||||
buildDir = gameObjectFrames[1].getModel()->getPosition() - gameObjectFrames[0].getModel()->getPosition();
|
||||
|
||||
Vector3 pos = paintSelectRowStart + buildDir.norm() * hypothenuse * gameObjectFrames.size();
|
||||
addGameObjectFrame(GameObjectFrame(structureId, GameObject::Type::UNIT, gameObjectFrames[0].getPlayer(), nullptr, pos));
|
||||
}
|
||||
}
|
||||
|
||||
void GameObjectFrameController::snapToObj(GameObjectFrame &s, vector<GameObject*> snapTargets, float maxDist){
|
||||
s.status = GameObjectFrame::BLOCKED_BY_DIFF_TERR;
|
||||
|
||||
for(GameObject *st : snapTargets){
|
||||
Vector3 stPos = st->getPos();
|
||||
|
||||
if(s.getPos().getDistanceFrom(stPos) < maxDist){
|
||||
s.status = GameObjectFrame::PLACEABLE;
|
||||
s.placeAt(stPos);
|
||||
checkPlacement(s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TODO include checking if frame is outside of line of sight
|
||||
void GameObjectFrameController::checkPlacement(GameObjectFrame &s){
|
||||
s.status = GameObjectFrame::PLACEABLE;
|
||||
|
||||
Map *map = Map::getSingleton();
|
||||
Vector3 mapSize = map->getMapSize();
|
||||
Vector3 cellSize = map->getCellSize();
|
||||
int dirMult[][2]{{1, 1}, {1, -1}, {-1, 1}, {-1, -1}};
|
||||
vector<Map::Cell> &cells = map->getCells();
|
||||
|
||||
sol::table tbl = generateView()["units"][s.getId() + 1];
|
||||
UnitType ut = (UnitType)tbl["unitType"];
|
||||
|
||||
vector<Unit*> friendlyUnits = (s.getPlayer() ? s.getPlayer()->getFriendlyUnits() : vector<Unit*>{});
|
||||
bool withinLos = false;
|
||||
|
||||
for(int i = 0; i < 4; i++){
|
||||
Vector3 cornerPos = (s.getPos() + s.getDirVec() * .5 * dirMult[i][0] * s.getLength() + s.getLeftVec() * .5 * dirMult[i][1] * s.getWidth());
|
||||
int cellId = map->getCellId(cornerPos, false);
|
||||
|
||||
if(cellId < 0 || !(fabs(cornerPos.x) <= .5 * mapSize.x && fabs(cornerPos.z) <= .5 * mapSize.z)){
|
||||
s.status = GameObjectFrame::BLOCKED_BY_MAP_BOUNDS;
|
||||
return;
|
||||
}
|
||||
|
||||
Map::Cell cell = cells[cellId];
|
||||
bool landUnitOnWater = (ut == UnitType::LAND && cell.type == Map::Cell::Type::WATER);
|
||||
bool waterUnitOnLand = ((ut == UnitType::SEA_LEVEL || ut == UnitType::UNDERWATER) && cell.type == Map::Cell::Type::LAND);
|
||||
bool withinCell = (fabs(cell.pos.x - cornerPos.x) < .5 * cellSize.x && fabs(cell.pos.z - cornerPos.z) < .5 * cellSize.z);
|
||||
|
||||
if((landUnitOnWater || waterUnitOnLand) && withinCell){
|
||||
s.status = GameObjectFrame::BLOCKED_BY_DIFF_TERR;
|
||||
return;
|
||||
}
|
||||
|
||||
if(!withinLos)
|
||||
for(Unit *fu : friendlyUnits)
|
||||
if(fu->getPos().getDistanceFrom(s.getPos()) < fu->getLineOfSight()){
|
||||
withinLos = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!withinLos){
|
||||
s.status = GameObjectFrame::BLOCKED_BY_FOG_OF_WAR;
|
||||
return;
|
||||
}
|
||||
|
||||
MeshData meshData = map->getNodeParent()->getChild(0)->getMesh(0)->getMeshBase();
|
||||
MeshData::Vertex *verts = meshData.vertices;
|
||||
int numVerts = 3 * meshData.numTris;
|
||||
|
||||
if(s.getMaxUnevenness() > 0)
|
||||
for(int i = 0; i < numVerts; i++){
|
||||
float diffX = fabs(s.getPos().x - verts[i].pos->x);
|
||||
float diffY = fabs(s.getPos().y - verts[i].pos->y);
|
||||
float diffZ = fabs(s.getPos().z - verts[i].pos->z);
|
||||
|
||||
if(diffX < 0.5 * s.getWidth() && diffZ < 0.5 * s.getLength() && diffY > s.getMaxUnevenness()){
|
||||
s.status = GameObjectFrame::BLOCKED_BY_BUMPY_TERR;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
vector<Unit*> units;
|
||||
|
||||
for(Player *player : Game::getSingleton()->getPlayers(true)){
|
||||
vector<Unit*> u = player->getUnits();
|
||||
units.insert(units.end(), u.begin(), u.end());
|
||||
}
|
||||
|
||||
for(Unit *unit : units){
|
||||
if(unit == s.getOriginalUnit()) continue;
|
||||
|
||||
Vector3 gm1Pos = s.getPos();
|
||||
Vector3 gm1Dir = s.getDirVec();
|
||||
gm1Dir = Vector3(gm1Dir.x, 0, gm1Dir.z).norm();
|
||||
|
||||
Vector3 gm1Left = s.getLeftVec();
|
||||
gm1Left = Vector3(gm1Left.x, 0, gm1Left.z).norm();
|
||||
|
||||
Vector3 gm2Pos = unit->getPos();
|
||||
|
||||
Vector3 gm2Dir = unit->getDirVec();
|
||||
gm2Dir = Vector3(gm2Dir.x, 0, gm2Dir.z).norm();
|
||||
|
||||
Vector3 gm2Left = unit->getLeftVec();
|
||||
gm2Left = Vector3(gm2Left.x, 0, gm2Left.z).norm();
|
||||
|
||||
bool intersects = rectanglesIntersect(
|
||||
Vector2(gm1Pos.x, gm1Pos.z),
|
||||
Vector2(gm1Dir.x, gm1Dir.z),
|
||||
Vector2(gm1Left.x, gm1Left.z),
|
||||
Vector2(s.getWidth(), s.getLength()),
|
||||
Vector2(gm2Pos.x, gm2Pos.z),
|
||||
Vector2(gm2Dir.x, gm2Dir.z),
|
||||
Vector2(gm2Left.x, gm2Left.z),
|
||||
Vector2(unit->getWidth(), unit->getLength())
|
||||
);
|
||||
|
||||
if(intersects){
|
||||
s.status = GameObjectFrame::BLOCKED_BY_UNIT;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TODO replace the magic number for ray casting height
|
||||
void GameObjectFrameController::shiftVerticalPlacement(){
|
||||
if(!minDepthCalculated){
|
||||
Map *map = Map::getSingleton();
|
||||
Node *nodeParent = map->getNodeParent();
|
||||
Vector3 cellSize = map->getCellSize(), waterBodyPos;
|
||||
bool inWater = false;
|
||||
|
||||
for(int i = 1; i < nodeParent->getNumChildren(); i++){
|
||||
Vector3 wPos = nodeParent->getChild(i)->getPosition();
|
||||
Vector3 wSize = ((Quad*)nodeParent->getChild(i)->getMesh(0))->getSize();
|
||||
|
||||
if(fabs(wPos.x - placementPos.x) < .5 * wSize.x && fabs(wPos.z - placementPos.z) < .5 * wSize.y){
|
||||
waterBodyPos = wPos;
|
||||
inWater = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!inWater) return;
|
||||
|
||||
vector<RayCaster::CollisionResult> res = map->raycastTerrain(
|
||||
Vector3(placementPos.x, 100, placementPos.z),
|
||||
-Vector3::VEC_J,
|
||||
false
|
||||
);
|
||||
|
||||
vector<Map::Cell> &cells = map->getCells();
|
||||
int cid = map->getCellId(placementPos, false);
|
||||
int numSubmarineCells = cells[cid].underWaterCellIds.size();
|
||||
maxDepth = cells[cid].pos.y;
|
||||
minDepth = (numSubmarineCells > 0 ? cells[cells[cid].underWaterCellIds[numSubmarineCells - 1]].pos.y : maxDepth) - .5 * cellSize.y;
|
||||
minDepthCalculated = true;
|
||||
}
|
||||
else{
|
||||
ActiveGameState *activeState = (ActiveGameState*)(GameManager::getSingleton()->getStateManager()->getAppStateByType((int)AppStateType::ACTIVE_STATE));
|
||||
float newDepth = minDepth + activeState->getDepth() * (maxDepth - minDepth);
|
||||
placementPos.y = newDepth;
|
||||
}
|
||||
}
|
||||
|
||||
void GameObjectFrameController::update(){
|
||||
Map *map = Map::getSingleton();
|
||||
Vector3 startPos = Root::getSingleton()->getCamera()->getPosition();
|
||||
Vector3 endPos = screenToSpace(getCursorPos());
|
||||
vector<RayCaster::CollisionResult> results = map->raycastTerrain(startPos, (screenToSpace(getCursorPos()) - startPos).norm(), true);
|
||||
|
||||
if(results.empty()) return;
|
||||
|
||||
if(paintSelecting) paintSelect(results[0].pos);
|
||||
|
||||
if(placingVertically) shiftVerticalPlacement();
|
||||
else if(placingOnSurface) placementPos = results[0].pos;
|
||||
|
||||
vector<GameObject*> deposits;
|
||||
for(ResourceDeposit *rd : Game::getSingleton()->getCivilianPlayer()->getResourceDeposits())
|
||||
deposits.push_back((GameObject*)rd);
|
||||
|
||||
for(int i = 0; i < gameObjectFrames.size(); i++){
|
||||
gameObjectFrames[i].update();
|
||||
|
||||
if(paintSelecting){
|
||||
float width = gameObjectFrames[0].getWidth();
|
||||
float length = gameObjectFrames[0].getLength();
|
||||
float hypothenuse = sqrt(width * width + length * length);
|
||||
Vector3 dir = (results[0].pos - paintSelectRowStart).norm();
|
||||
placementPos = paintSelectRowStart + dir * hypothenuse * i;
|
||||
}
|
||||
|
||||
if(!rotating && (placingOnSurface || placingVertically))
|
||||
gameObjectFrames[i].placeAt(placementPos);
|
||||
|
||||
bool extractor = false;
|
||||
|
||||
if(gameObjectFrames[i].getType() == GameObject::Type::UNIT){
|
||||
sol::table tbl = generateView()["units"][gameObjectFrames[i].getId() + 1];
|
||||
extractor = ((UnitClass)tbl["unitClass"] == UnitClass::EXTRACTOR);
|
||||
}
|
||||
|
||||
if(extractor)
|
||||
snapToObj(gameObjectFrames[i], deposits, 20);
|
||||
else
|
||||
checkPlacement(gameObjectFrames[i]);
|
||||
|
||||
bool placeable = (gameObjectFrames[i].status == GameObjectFrame::PLACEABLE);
|
||||
Vector4 color = (placeable ? Vector4(0, 1, 0, 1) : Vector4(1, 0, 0, 1));
|
||||
gameObjectFrames[i].getModel()->getMaterial()->setVec4Uniform("diffuseColor", color);
|
||||
}
|
||||
|
||||
if(!placingVertically) minDepthCalculated = false;
|
||||
}
|
||||
|
||||
void GameObjectFrameController::addGameObjectFrame(GameObjectFrame u){
|
||||
gameObjectFrames.push_back(u);
|
||||
vector<RayCaster::CollisionResult> results = Map::getSingleton()->raycastTerrain(u.getPos(), -Vector3::VEC_J, true);
|
||||
|
||||
if(!results.empty()) placementPos = results[0].pos;
|
||||
}
|
||||
|
||||
void GameObjectFrameController::removeGameObjectFrame(int i){
|
||||
gameObjectFrames[i].destroy();
|
||||
gameObjectFrames.erase(gameObjectFrames.begin() + i);
|
||||
}
|
||||
|
||||
void GameObjectFrameController::removeGameObjectFrames(){
|
||||
while(gameObjectFrames.size() > 0)
|
||||
removeGameObjectFrame(0);
|
||||
}
|
||||
|
||||
void GameObjectFrameController::rotateGameObjectFrames(float angle){
|
||||
for(GameObjectFrame &s : gameObjectFrames)
|
||||
s.orientAt(Quaternion(angle, Vector3::VEC_J) * s.getRot());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
#ifndef GAME_OBJECT_FRAME_CONTROLLER_H
|
||||
#define GAME_OBJECT_FRAME_CONTROLLER_H
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include <vector.h>
|
||||
#include <quaternion.h>
|
||||
|
||||
#include "gameObjectFrame.h"
|
||||
|
||||
namespace vb01{
|
||||
class Model;
|
||||
}
|
||||
|
||||
namespace battleship{
|
||||
class GameObjectFrameController{
|
||||
public:
|
||||
static GameObjectFrameController* getSingleton();
|
||||
void update();
|
||||
void removeGameObjectFrame(int);
|
||||
void removeGameObjectFrames();
|
||||
void rotateGameObjectFrames(float);
|
||||
void checkPlacement(GameObjectFrame&);
|
||||
void addGameObjectFrame(GameObjectFrame);
|
||||
inline int getNumGameObjectFrames(){return gameObjectFrames.size();}
|
||||
inline GameObjectFrame& getGameObjectFrame(int i){return gameObjectFrames[i];}
|
||||
inline bool isPaintSelecting(){return paintSelecting;}
|
||||
inline void setPaintSelecting(bool ps){paintSelecting = ps;}
|
||||
inline bool isRotating(){return rotating;}
|
||||
inline void setRotating(bool rs){rotating = rs;}
|
||||
inline bool isPlacingOnSurface(){return placingOnSurface;}
|
||||
inline void setPlacingOnSurface(bool ps){placingOnSurface = ps;}
|
||||
inline bool isPlacingVertically(){return placingVertically;}
|
||||
inline void setPlacingVertically(bool v){this->placingVertically = v;}
|
||||
inline void setPaintSelectRowStart(vb01::Vector3 st){paintSelectRowStart = st;}
|
||||
inline void toggleFrameTransformations(bool rot, bool pos, bool pv){
|
||||
setRotating(rot);
|
||||
setPlacingOnSurface(pos);
|
||||
setPlacingVertically(pv);
|
||||
}
|
||||
private:
|
||||
GameObjectFrameController(){}
|
||||
void paintSelect(vb01::Vector3);
|
||||
void snapToObj(GameObjectFrame&, std::vector<GameObject*>, float);
|
||||
void shiftVerticalPlacement();
|
||||
|
||||
std::vector<GameObjectFrame> gameObjectFrames;
|
||||
vb01::Vector3 paintSelectRowStart, placementPos;
|
||||
float minDepth, maxDepth;
|
||||
bool paintSelecting = false, rotating = false, placingOnSurface = false, placingVertically = false, minDepthCalculated = false;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,33 @@
|
||||
#include "defConfigs.h"
|
||||
|
||||
namespace battleship{
|
||||
namespace configData{
|
||||
int calcSumStaticBinds(int id, bool calcPrev){
|
||||
int numBinds = 0;
|
||||
|
||||
if(calcPrev)
|
||||
for(int i = 0; i < id; i++)
|
||||
numBinds += numStaticBinds[i];
|
||||
else
|
||||
numBinds = numStaticBinds[id];
|
||||
|
||||
return numBinds;
|
||||
}
|
||||
|
||||
int calcSumConfBinds(int id, bool calcPrev){
|
||||
int numBinds = 0;
|
||||
|
||||
if(calcPrev)
|
||||
for(int i = 0; i < id; i++)
|
||||
numBinds += numConfBinds[i];
|
||||
else
|
||||
numBinds = numConfBinds[id];
|
||||
|
||||
return numBinds;
|
||||
}
|
||||
|
||||
int calcSumBinds(int id, bool calcPrev){
|
||||
return calcSumStaticBinds(id, calcPrev) + calcSumConfBinds(id, calcPrev);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
#ifndef DEF_CONFIGS_H
|
||||
#define DEF_CONFIGS_H
|
||||
#define SOL_ALL_SAFETIES_ON 1
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <util.h>
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include <mapping.h>
|
||||
#include <sol/sol.hpp>
|
||||
|
||||
#include "binds.h"
|
||||
#include "gameManager.h"
|
||||
|
||||
namespace battleship{
|
||||
namespace configData{
|
||||
using namespace gameBase;
|
||||
|
||||
const std::string DEFAULT_TEXTURE = "Textures/defaultTexture.jpg";
|
||||
const double camPanSpeed = .5, CAMERA_DISTANCE = 100, CAMERA_ZOOM_INCREMENT = 1, cellLength = 7, cellWidth = 7, cellDepth = 7, DIST_FROM_RAY = 15;
|
||||
const int maxNumGroups = 10, NUM_MAX_ZOOMS = 300, NUM_SUBDIVS = 100;
|
||||
const vb01::u32 IMPASS_NODE_VAL = 65535;
|
||||
|
||||
const static int numAppStates = 5;
|
||||
const static int numStaticBinds[numAppStates]{6, 0, 5, 19, 0};
|
||||
const static int numConfBinds[numAppStates]{0, 1, 27, 0, 0};
|
||||
const static int maxStaticBinds = 19;
|
||||
const static int maxConfBinds = 23;
|
||||
const static int numScripts = 5;
|
||||
|
||||
const static std::string scriptPathBase = "Scripts/";
|
||||
enum ScriptFiles{
|
||||
CORE_MAIN,
|
||||
GUI_MAIN,
|
||||
OPTIONS,
|
||||
RESOURCE_DATA,
|
||||
PROJECTILE_DATA,
|
||||
UNIT_DATA,
|
||||
AI_AGENT,
|
||||
PLAYER
|
||||
};
|
||||
const static std::vector<std::string> scripts = std::vector<std::string>{
|
||||
"Scripts/Core/main.lua",
|
||||
"Scripts/Gui/main.lua",
|
||||
"Scripts/Core/options.lua",
|
||||
"Scripts/GameObjects/resourceData.lua",
|
||||
"Scripts/GameObjects/Projectiles/projectileData.lua",
|
||||
"Scripts/GameObjects/Units/unitData.lua",
|
||||
"Scripts/aiAgent.lua",
|
||||
"Scripts/Core/player.lua",
|
||||
"Scripts/Technologies/technologyData.lua",
|
||||
"Scripts/Abilities/abilityData.lua",
|
||||
"Scripts/Trading/traderData.lua"
|
||||
};
|
||||
|
||||
const static Bind staticBinds[numAppStates][maxStaticBinds]{
|
||||
{
|
||||
Bind::LEFT_CLICK,
|
||||
Bind::SCROLLING_UP,
|
||||
Bind::SCROLLING_DOWN,
|
||||
Bind::LEFT,
|
||||
Bind::RIGHT,
|
||||
Bind::DELETE_CHAR,
|
||||
},
|
||||
{},
|
||||
{
|
||||
Bind::LOOK_UP,
|
||||
Bind::LOOK_DOWN,
|
||||
Bind::LOOK_LEFT,
|
||||
Bind::LOOK_RIGHT,
|
||||
Bind::LOOK_AROUND,
|
||||
},
|
||||
{
|
||||
Bind::LOOK_UP,
|
||||
Bind::LOOK_DOWN,
|
||||
Bind::LOOK_LEFT,
|
||||
Bind::LOOK_RIGHT,
|
||||
Bind::LOOK_AROUND,
|
||||
},
|
||||
{}
|
||||
};
|
||||
const static Bind confBinds[numAppStates][maxConfBinds]{
|
||||
{},
|
||||
{
|
||||
Bind::TOGGLE_MAIN_MENU
|
||||
},
|
||||
{
|
||||
Bind::DRAG_BOX,
|
||||
Bind::MOVE_CAMERA,
|
||||
Bind::ROTATE_OBJ_FRAME,
|
||||
Bind::HALT,
|
||||
Bind::ZOOM_IN,
|
||||
Bind::ZOOM_OUT,
|
||||
Bind::LEFT_CONTROL,
|
||||
Bind::LEFT_SHIFT,
|
||||
Bind::SELECT_PATROL_POINTS,
|
||||
Bind::LAUNCH,
|
||||
Bind::SHIFT_SUB_DEPTH,
|
||||
Bind::GROUP_0,
|
||||
Bind::GROUP_1,
|
||||
Bind::GROUP_2,
|
||||
Bind::GROUP_3,
|
||||
Bind::GROUP_4,
|
||||
Bind::GROUP_5,
|
||||
Bind::GROUP_6,
|
||||
Bind::GROUP_7,
|
||||
Bind::GROUP_8,
|
||||
Bind::GROUP_9,
|
||||
Bind::SELECT_STRUCTURE,
|
||||
Bind::DESELECT_STRUCTURE
|
||||
},
|
||||
{},
|
||||
{}
|
||||
};
|
||||
|
||||
const static int staticTriggers[numAppStates][maxStaticBinds]{
|
||||
{
|
||||
0,
|
||||
GLFW_KEY_W,
|
||||
GLFW_KEY_S,
|
||||
GLFW_KEY_LEFT,
|
||||
GLFW_KEY_RIGHT,
|
||||
GLFW_KEY_BACKSPACE
|
||||
},
|
||||
{},
|
||||
{
|
||||
Mapping::MOUSE_AXIS_UP,
|
||||
Mapping::MOUSE_AXIS_DOWN,
|
||||
Mapping::MOUSE_AXIS_LEFT,
|
||||
Mapping::MOUSE_AXIS_RIGHT,
|
||||
0
|
||||
},
|
||||
{
|
||||
Mapping::MOUSE_AXIS_UP,
|
||||
Mapping::MOUSE_AXIS_DOWN,
|
||||
Mapping::MOUSE_AXIS_LEFT,
|
||||
Mapping::MOUSE_AXIS_RIGHT,
|
||||
0
|
||||
},
|
||||
{}
|
||||
};
|
||||
const static int confTriggers[numAppStates][maxConfBinds]{
|
||||
{},
|
||||
{
|
||||
GLFW_KEY_ESCAPE
|
||||
},
|
||||
{
|
||||
GLFW_KEY_LEFT,
|
||||
GLFW_KEY_RIGHT,
|
||||
GLFW_KEY_H,
|
||||
3,
|
||||
4,
|
||||
GLFW_KEY_LEFT_CONTROL,
|
||||
GLFW_KEY_LEFT_SHIFT,
|
||||
GLFW_KEY_P,
|
||||
GLFW_KEY_C,
|
||||
GLFW_KEY_S,
|
||||
GLFW_KEY_0,
|
||||
GLFW_KEY_1,
|
||||
GLFW_KEY_2,
|
||||
GLFW_KEY_3,
|
||||
GLFW_KEY_4,
|
||||
GLFW_KEY_5,
|
||||
GLFW_KEY_6,
|
||||
GLFW_KEY_7,
|
||||
GLFW_KEY_8,
|
||||
GLFW_KEY_9,
|
||||
GLFW_KEY_B,
|
||||
GLFW_KEY_ESCAPE
|
||||
},
|
||||
{},
|
||||
{}
|
||||
};
|
||||
|
||||
const static bool isStaticKey[numAppStates][maxStaticBinds]{
|
||||
{0, 1, 1, 1, 1, 1},
|
||||
{},
|
||||
{0, 0, 0, 0, 1},
|
||||
{0, 0, 0, 0, 1},
|
||||
{}
|
||||
};
|
||||
const static bool isConfKey[numAppStates][maxConfBinds]{
|
||||
{},
|
||||
{1},
|
||||
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
|
||||
{},
|
||||
{}
|
||||
};
|
||||
|
||||
const static bool isStaticAction[numAppStates][maxStaticBinds]{
|
||||
{1, 1, 1, 1, 1, 1},
|
||||
{},
|
||||
{0, 0, 0, 0, 1},
|
||||
{0, 0, 0, 0, 1},
|
||||
{}
|
||||
};
|
||||
const static bool isConfAction[numAppStates][maxConfBinds]{
|
||||
{},
|
||||
{1},
|
||||
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
|
||||
{},
|
||||
{}
|
||||
};
|
||||
|
||||
int calcSumStaticBinds(int, bool);
|
||||
int calcSumConfBinds(int, bool);
|
||||
int calcSumBinds(int, bool);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,247 @@
|
||||
#include "game.h"
|
||||
#include "player.h"
|
||||
#include "projectile.h"
|
||||
#include "gameManager.h"
|
||||
#include "activeGameState.h"
|
||||
#include "inGameAppState.h"
|
||||
#include "concreteGuiManager.h"
|
||||
#include "fxManager.h"
|
||||
#include "factory.h"
|
||||
#include "defConfigs.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <assetManager.h>
|
||||
#include <particleEmitter.h>
|
||||
|
||||
#include <stateManager.h>
|
||||
|
||||
#include <solUtil.h>
|
||||
|
||||
#include <SFML/Audio.hpp>
|
||||
|
||||
namespace battleship{
|
||||
using namespace std;
|
||||
using namespace vb01;
|
||||
using namespace gameBase;
|
||||
|
||||
static Game *game = nullptr;
|
||||
|
||||
Game* Game::getSingleton(){
|
||||
if(!game)
|
||||
game = new Game();
|
||||
|
||||
return game;
|
||||
}
|
||||
|
||||
void Game::endGame(bool victory){
|
||||
ended = true;
|
||||
|
||||
StateManager *sm = GameManager::getSingleton()->getStateManager();
|
||||
sm->dettachAppState(sm->getAppStateByType(AppStateType::ACTIVE_STATE));
|
||||
|
||||
ConcreteGuiManager::getSingleton()->parseLuaScript(victory ? "victory.lua" : "defeat.lua");
|
||||
}
|
||||
|
||||
void Game::update(){
|
||||
sol::state_view SOL_LUA_VIEW = generateView();
|
||||
|
||||
for(int i = 0; i < getCpuPlayers().size(); i++) {
|
||||
string plStr = "game.cpuPlayers[" + to_string(i + 1) + "]";
|
||||
SOL_LUA_VIEW.script("executeBtNode(" + plStr + ", " + plStr + ".behaviour)");
|
||||
SOL_LUA_VIEW.collect_garbage();
|
||||
}
|
||||
|
||||
int numPlayersWithUnits = 0;
|
||||
|
||||
for(int i = 0; i < players.size(); i++){
|
||||
players[i]->update();
|
||||
|
||||
if(players[i]->getNumUnits() > 0)
|
||||
numPlayersWithUnits++;
|
||||
}
|
||||
|
||||
ActiveGameState *activeState = (ActiveGameState*)GameManager::getSingleton()->getStateManager()->getAppStateByType(AppStateType::ACTIVE_STATE);
|
||||
Player *mainPlayer = (activeState ? activeState->getPlayer() : nullptr);
|
||||
|
||||
if(mainPlayer && !ended){
|
||||
int numMainPlayerUnits = mainPlayer->getNumUnits();
|
||||
|
||||
if(numMainPlayerUnits > 0 && numPlayersWithUnits == 1)
|
||||
endGame(true);
|
||||
else if(numMainPlayerUnits == 0)
|
||||
endGame(false);
|
||||
}
|
||||
|
||||
FxManager::getSingleton()->update();
|
||||
}
|
||||
|
||||
void Game::initLuaPlayers(){
|
||||
sol::state_view SOL_LUA_VIEW = generateView();
|
||||
vector<Player*> cpuPlayers = getCpuPlayers();
|
||||
|
||||
for(int i = 0; i < cpuPlayers.size(); i++)
|
||||
SOL_LUA_VIEW["game"]["cpuPlayers"][i + 1] = cpuPlayers[i];
|
||||
|
||||
SOL_LUA_VIEW.script_file(GameManager::getSingleton()->getPath() + "Scripts/Core/playerInit.lua");
|
||||
}
|
||||
|
||||
void Game::removeAllElements(){
|
||||
generateView().script("game.cpuPlayers = {}");
|
||||
|
||||
while(!players.empty()){
|
||||
delete players[0];
|
||||
players.erase(players.begin());
|
||||
}
|
||||
|
||||
ended = false;
|
||||
paused = false;
|
||||
}
|
||||
|
||||
void Game::togglePause(){
|
||||
GameManager *gm = GameManager::getSingleton();
|
||||
ConcreteGuiManager *guiManager = ConcreteGuiManager::getSingleton();
|
||||
ActiveGameState *activeState = ((InGameAppState*)gm->getStateManager()->getAppStateByType(AppStateType::IN_GAME_STATE))->getActiveState();
|
||||
|
||||
if (!paused) {
|
||||
gm->getStateManager()->dettachAppState(activeState);
|
||||
guiManager->parseLuaScript("gamePaused.lua");
|
||||
}
|
||||
else {
|
||||
guiManager->readLuaScreenScript("inGame.lua", activeState->getGuiButtons());
|
||||
|
||||
if(debug){
|
||||
sol::state_view SOL_LUA_VIEW = generateView();
|
||||
|
||||
for(string f : configData::scripts)
|
||||
SOL_LUA_VIEW.script_file(gm->getPath() + f);
|
||||
|
||||
initLuaPlayers();
|
||||
|
||||
vector<GameObject*> gameObjs;
|
||||
|
||||
for(Player *pl : Game::getSingleton()->getPlayers()){
|
||||
for(Unit *u : pl->getUnits())
|
||||
gameObjs.push_back((GameObject*)u);
|
||||
|
||||
for(Projectile *proj : pl->getProjectiles())
|
||||
gameObjs.push_back((GameObject*)proj);
|
||||
}
|
||||
|
||||
for(ResourceDeposit *dep : civilianPlayer->getResourceDeposits())
|
||||
gameObjs.push_back((GameObject*)dep);
|
||||
|
||||
string gop = SOL_LUA_VIEW["gameObjPrefix"], vfxp = SOL_LUA_VIEW["vfxPrefix"];
|
||||
AssetManager::getSingleton()->load(gm->getPath() + gop, true);
|
||||
AssetManager::getSingleton()->load(gm->getPath() + vfxp, true);
|
||||
|
||||
for(GameObject *obj : gameObjs)
|
||||
obj->reinit();
|
||||
}
|
||||
|
||||
gm->getStateManager()->attachAppState(activeState);
|
||||
}
|
||||
|
||||
paused = !paused;
|
||||
}
|
||||
|
||||
vector<int> Game::parseTechTable(int tid, string key, string numVarKey, string varKey){
|
||||
sol::state_view SOL_LUA_VIEW = generateView();
|
||||
SOL_LUA_VIEW.script(numVarKey + " = #" + key + "[" + to_string(tid + 1) + "]." + varKey);
|
||||
int numVar = SOL_LUA_VIEW[numVarKey];
|
||||
sol::table techTable = SOL_LUA_VIEW[key][tid + 1];
|
||||
|
||||
vector<int> varVec;
|
||||
|
||||
for(int i = 0; i < numVar; i++)
|
||||
varVec.push_back(techTable[varKey][i + 1]);
|
||||
|
||||
return varVec;
|
||||
}
|
||||
|
||||
//TODO clean this method up
|
||||
void Game::initTechnologies(){
|
||||
technologies.clear();
|
||||
|
||||
sol::state_view SOL_LUA_VIEW = generateView();
|
||||
string techKey = "technologies";
|
||||
SOL_LUA_VIEW.script("numTechs = #" + techKey);
|
||||
int numTechs = SOL_LUA_VIEW["numTechs"];
|
||||
|
||||
for(int i = 0; i < numTechs; i++){
|
||||
sol::table techTable = SOL_LUA_VIEW[techKey][i + 1];
|
||||
|
||||
Technology t;
|
||||
t.cost = techTable["cost"];
|
||||
t.name = techTable["name"];
|
||||
t.icon = techTable["icon"];
|
||||
t.description = techTable["description"];
|
||||
t.parents = parseTechTable(i, techKey, "numParents", "parents");
|
||||
t.abilities = parseTechTable(i, techKey, "numAbilities", "abilities");
|
||||
|
||||
technologies.push_back(t);
|
||||
}
|
||||
|
||||
techKey = "abilities";
|
||||
SOL_LUA_VIEW.script("numAbilities = #" + techKey);
|
||||
int numAbilities = SOL_LUA_VIEW["numAbilities"];
|
||||
|
||||
for(int i = 0; i < numAbilities; i++){
|
||||
sol::table techTable = SOL_LUA_VIEW[techKey][i + 1];
|
||||
|
||||
Ability ability;
|
||||
ability.type = techTable["type"];
|
||||
ability.ammount = techTable["ammount"].get_or(0.0);
|
||||
ability.gameObjType = techTable["gameObjType"];
|
||||
ability.gameObjIds = parseTechTable(i, techKey, "numGameObjIds", "gameObjIds");
|
||||
abilities.push_back(ability);
|
||||
}
|
||||
}
|
||||
|
||||
float Game::calcAbilFromTech(Ability::Type type, vector<int> techResearch, int gameObjType, int unitId){
|
||||
float ammount = 0;
|
||||
|
||||
for(int techId : techResearch)
|
||||
for(int abilId : technologies[techId].abilities)
|
||||
if(
|
||||
abilities[abilId].type == type &&
|
||||
abilities[abilId].gameObjType == gameObjType &&
|
||||
find(abilities[abilId].gameObjIds.begin(), abilities[abilId].gameObjIds.end(), unitId) != abilities[abilId].gameObjIds.end()
|
||||
){
|
||||
ammount += abilities[abilId].ammount;
|
||||
}
|
||||
|
||||
return ammount;
|
||||
}
|
||||
|
||||
bool Game::isUnitUnlocked(vector<int> techResearch, int unitId){
|
||||
for(int techId : techResearch){
|
||||
for(int abilId : technologies[techId].abilities){
|
||||
vector<int> ids = abilities[abilId].gameObjIds;
|
||||
|
||||
if(find(ids.begin(), ids.end(), unitId) != ids.end())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
vector<Player*> Game::getPlayers(bool civPl){
|
||||
vector<Player*> playersVec = players;
|
||||
|
||||
if(civPl) playersVec.push_back(civilianPlayer);
|
||||
|
||||
return playersVec;
|
||||
}
|
||||
|
||||
vector<Player*> Game::getCpuPlayers(){
|
||||
vector<Player*> playersVec;
|
||||
|
||||
for(Player *pl : players)
|
||||
if(pl->isCpuPlayer())
|
||||
playersVec.push_back(pl);
|
||||
|
||||
return playersVec;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
#ifndef GAME_H
|
||||
#define GAME_H
|
||||
|
||||
#include "technology.h"
|
||||
#include "ability.h"
|
||||
#include "tradeOffer.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace sf{
|
||||
class Sound;
|
||||
}
|
||||
|
||||
namespace battleship{
|
||||
class Unit;
|
||||
class Player;
|
||||
class Projectile;
|
||||
|
||||
class Game{
|
||||
public:
|
||||
static Game* getSingleton();
|
||||
void update();
|
||||
void initLuaPlayers();
|
||||
void togglePause();
|
||||
void removeAllElements();
|
||||
void initTechnologies();
|
||||
float calcAbilFromTech(Ability::Type, std::vector<int>, int, int);
|
||||
bool isUnitUnlocked(std::vector<int>, int);
|
||||
std::vector<Player*> getPlayers(bool = false);
|
||||
std::vector<Player*> getCpuPlayers();
|
||||
inline void setDebug(bool d){this->debug = d;}
|
||||
inline void addPlayer(Player *pl){players.push_back(pl);}
|
||||
inline bool isDebug(){return debug;}
|
||||
inline Player* getPlayer(int id){return players[id];}
|
||||
inline void setCivilianPlayer(Player *pl){this->civilianPlayer = pl;}
|
||||
inline Player* getCivilianPlayer(){return civilianPlayer;}
|
||||
inline int getNumPlayers(){return players.size();}
|
||||
inline Technology getTechnology(int id){return technologies[id];}
|
||||
inline Ability getAbility(int id){return abilities[id];}
|
||||
private:
|
||||
Game(){}
|
||||
void endGame(bool);
|
||||
std::vector<int> parseTechTable(int, std::string, std::string, std::string);
|
||||
|
||||
bool paused = false, ended = false, debug = false;
|
||||
std::vector<Technology> technologies;
|
||||
std::vector<Ability> abilities;
|
||||
std::vector<Player*> players;
|
||||
Player *civilianPlayer = nullptr;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,279 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include <stateManager.h>
|
||||
#include <inputManager.h>
|
||||
#include <soundManager.h>
|
||||
|
||||
#include <assetManager.h>
|
||||
#include <root.h>
|
||||
|
||||
#include "gameManager.h"
|
||||
#include "gameObjectFrameController.h"
|
||||
#include "gameObjectFactory.h"
|
||||
#include "map.h"
|
||||
#include "game.h"
|
||||
#include "guiAppState.h"
|
||||
#include "defConfigs.h"
|
||||
#include "player.h"
|
||||
#include "extractor.h"
|
||||
#include "factory.h"
|
||||
#include "vehicle.h"
|
||||
#include "engineer.h"
|
||||
#include "destructable.h"
|
||||
#include "pointDefense.h"
|
||||
#include "pathfinder.h"
|
||||
#include "resourceDeposit.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vb01;
|
||||
using namespace gameBase;
|
||||
|
||||
namespace battleship{
|
||||
static GameManager *gameManager = nullptr;
|
||||
|
||||
GameManager* GameManager::getSingleton(){
|
||||
if(!gameManager)
|
||||
gameManager = new GameManager();
|
||||
|
||||
return gameManager;
|
||||
}
|
||||
|
||||
void GameManager::registerMembers(){
|
||||
sol::state_view SOL_LUA_STATE = generateView();
|
||||
|
||||
SOL_LUA_STATE.new_usertype<Order>(
|
||||
"Order", sol::constructors<Order(), Order(Order::TYPE, vector<Order::Target>, Vector3, int)>(),
|
||||
"type", &Order::type,
|
||||
"direction", &Order::direction,
|
||||
"targets", &Order::targets
|
||||
);
|
||||
|
||||
SOL_LUA_STATE.new_usertype<Order::Target>(
|
||||
"Target", sol::constructors<Order::Target(), Order::Target(GameObject*, Vector3)>(),
|
||||
"unit", &Order::Target::unit,
|
||||
"pos", &Order::Target::pos
|
||||
);
|
||||
|
||||
SOL_LUA_STATE.new_usertype<GameObjectFactory>(
|
||||
"GameObjectFactory",
|
||||
"createUnit", &GameObjectFactory::createUnit,
|
||||
"createResourceDeposit", &GameObjectFactory::createResourceDeposit
|
||||
);
|
||||
|
||||
SOL_LUA_STATE.new_usertype<Unit::GarrisonSlot>(
|
||||
"GarrisonSlot",
|
||||
"vehicle", &Unit::GarrisonSlot::vehicle,
|
||||
"category", &Unit::GarrisonSlot::category
|
||||
);
|
||||
|
||||
SOL_LUA_STATE.new_usertype<Unit>(
|
||||
"Unit", sol::constructors<Unit(Player*, int, Vector3, Quaternion)>(),
|
||||
"setState", &Unit::setState,
|
||||
"getDestructable", &Unit::getDestructable,
|
||||
"getGarrisonSlots", &Unit::getGarrisonSlots,
|
||||
"getNumFreeGarrisonSlots", &Unit::getNumFreeGarrisonSlots,
|
||||
"getNumGarrisonSlots", &Unit::getNumGarrisonSlots,
|
||||
"isGarrisonEmpty", &Unit::isGarrisonEmpty,
|
||||
"getOrder", &Unit::getOrder,
|
||||
"getNumOrders", &Unit::getNumOrders,
|
||||
"getDirVec", &GameObject::getDirVec,
|
||||
"getLeftVec", &GameObject::getLeftVec,
|
||||
"getPos", &GameObject::getPos,
|
||||
"getUnitClass", &Unit::getUnitClass,
|
||||
"getLineOfSight", &Unit::getLineOfSight,
|
||||
"getBuildableUnit", &Unit::getBuildableUnit,
|
||||
"getBuildableUnits", &Unit::getBuildableUnits,
|
||||
"getNumBuildableUnits", &Unit::getNumBuildableUnits,
|
||||
"toGameObject", [](Unit *u){return (GameObject*)u;},
|
||||
"toVehicle", [](Unit *u){return (Vehicle*)u;},
|
||||
"toEngineer", [](Unit *u){return (Engineer*)u;},
|
||||
"toStructure", [](Unit *u){return (Structure*)u;},
|
||||
"toFactory", [](Unit *u){return (Factory*)u;},
|
||||
"toExtractor", [](Unit *u){return (Extractor*)u;},
|
||||
"toPointDefense", [](Unit *u){return (PointDefense*)u;}
|
||||
);
|
||||
|
||||
SOL_LUA_STATE.new_usertype<Vehicle>(
|
||||
"Engineer", sol::constructors<Vehicle(Player*, int, Vector3, Quaternion, Unit::State)>(),
|
||||
"getGarrisonable", &Vehicle::getGarrisonable
|
||||
);
|
||||
|
||||
SOL_LUA_STATE.new_usertype<Engineer>(
|
||||
"Engineer", sol::constructors<Engineer(Player*, int, Vector3, Quaternion, Unit::State)>(),
|
||||
"getBuildableUnit", &Unit::getBuildableUnit,
|
||||
"getBuildableUnits", &Unit::getBuildableUnits,
|
||||
"getNumBuildableUnits", &Unit::getNumBuildableUnits
|
||||
);
|
||||
|
||||
SOL_LUA_STATE.new_usertype<Structure>(
|
||||
"Structure", sol::constructors<Structure(Player*, int, Vector3, Quaternion, int)>(),
|
||||
"getPos", &GameObject::getPos,
|
||||
"isComplete", &Structure::isComplete,
|
||||
"getBuildStatus", &Structure::getBuildStatus
|
||||
);
|
||||
|
||||
SOL_LUA_STATE.new_usertype<BuildableUnit>(
|
||||
"BuildableUnit", sol::constructors<BuildableUnit(int, bool)>(),
|
||||
"id", &BuildableUnit::id,
|
||||
"buildable", &BuildableUnit::buildable
|
||||
);
|
||||
|
||||
SOL_LUA_STATE.new_usertype<Factory>(
|
||||
"Factory", sol::constructors<Factory(Player*, int, Vector3, Quaternion, int)>(),
|
||||
"getBuildableUnit", &Unit::getBuildableUnit,
|
||||
"getBuildableUnits", &Unit::getBuildableUnits,
|
||||
"getNumBuildableUnits", &Unit::getNumBuildableUnits,
|
||||
"getDirVec", &GameObject::getDirVec,
|
||||
"getLeftVec", &GameObject::getLeftVec,
|
||||
"getPos", &GameObject::getPos,
|
||||
"appendToQueue", &Factory::appendToQueue,
|
||||
"getBuildStatus", &Structure::getBuildStatus,
|
||||
"getNumQueueUnitsById", &Factory::getNumQueueUnitsById,
|
||||
"getRallyPoint", &Factory::getRallyPoint,
|
||||
"setRallyPoint", &Factory::setRallyPoint,
|
||||
"getQueue", &Factory::getQueue
|
||||
);
|
||||
|
||||
SOL_LUA_STATE.new_usertype<Player>(
|
||||
"Player", sol::constructors<Player(int, int, int, Vector3, bool, int, string)>(),
|
||||
"getSelectedUnits", &Player::getSelectedUnits,
|
||||
"haltUnits", &Player::haltUnits,
|
||||
"addUnit", &Player::addUnit,
|
||||
"getUnit", &Player::getUnit,
|
||||
"getNumUnits", &Player::getNumUnits,
|
||||
"getResourceDeposits", &Player::getResourceDeposits,
|
||||
"issueOrder", &Player::issueOrder,
|
||||
"selectUnits", &Player::selectUnits,
|
||||
"deselectUnits", &Player::deselectUnits,
|
||||
"getSpawnPointId", &Player::getSpawnPointId,
|
||||
"getFaction", &Player::getFaction,
|
||||
"getTeam", &Player::getTeam,
|
||||
"getUnits", &Player::getUnits,
|
||||
"getHostileUnits", &Player::getHostileUnits,
|
||||
"getFriendlyUnits", &Player::getFriendlyUnits,
|
||||
"getUnitsById", &Player::getUnitsById,
|
||||
"getUnitsByClass", &Player::getUnitsByClass,
|
||||
"isObjectVisible", &Player::isObjectVisible
|
||||
);
|
||||
|
||||
SOL_LUA_STATE.new_usertype<Extractor>(
|
||||
"Extractor", sol::constructors<Extractor(Player*, int, Vector3, Quaternion, int, ResourceDeposit*, Unit::State)>(),
|
||||
"getDeposit", &Extractor::getDeposit
|
||||
);
|
||||
|
||||
SOL_LUA_STATE.new_usertype<ResourceDeposit>(
|
||||
"ResourceDeposit", sol::constructors<ResourceDeposit(Player*, int, Vector3, Quaternion, int)>(),
|
||||
"getExtractor", &ResourceDeposit::getExtractor,
|
||||
"getAmmount", &ResourceDeposit::getAmmount,
|
||||
"getPos", &GameObject::getPos,
|
||||
"toGameObject", [](ResourceDeposit *rd){return (GameObject*)rd;}
|
||||
);
|
||||
|
||||
SOL_LUA_STATE.new_usertype<Game>(
|
||||
"Game",
|
||||
"getSingleton", &Game::getSingleton,
|
||||
"getPlayers", &Game::getPlayers
|
||||
);
|
||||
|
||||
SOL_LUA_STATE.new_usertype<Vector3>(
|
||||
"Vector3", sol::constructors<Vector3(), Vector3(float, float, float)>(),
|
||||
"x", &Vector3::x,
|
||||
"y", &Vector3::y,
|
||||
"z", &Vector3::z,
|
||||
"norm", &Vector3::norm,
|
||||
"getAngleBetween", &Vector3::getAngleBetween,
|
||||
"getDistanceFrom", &Vector3::getDistanceFrom,
|
||||
"neg", [](Vector3 v){return -v;},
|
||||
"add", [](Vector3 v1, Vector3 v2){return v1 + v2;},
|
||||
"subtr", [](Vector3 v1, Vector3 v2){return v1 - v2;},
|
||||
"mult", [](Vector3 v1, float s){return v1 * s;},
|
||||
"div", [](Vector3 v1, float s){return v1 / s;}
|
||||
);
|
||||
|
||||
SOL_LUA_STATE.new_usertype<Quaternion>(
|
||||
"Quaternion", sol::constructors<Quaternion(), Quaternion(float, float, float, float), Quaternion(float, Vector3)>(),
|
||||
"w", &Quaternion::w,
|
||||
"x", &Quaternion::x,
|
||||
"y", &Quaternion::y,
|
||||
"z", &Quaternion::z,
|
||||
"getAngle", &Quaternion::getAngle,
|
||||
"getAxis", &Quaternion::getAxis,
|
||||
"multVec", [](Quaternion q, Vector3 v){return q * v;}
|
||||
);
|
||||
|
||||
SOL_LUA_STATE.new_usertype<Map::Cell>(
|
||||
"Cell",
|
||||
"pos", &Map::Cell::pos,
|
||||
"type", &Map::Cell::type
|
||||
);
|
||||
|
||||
SOL_LUA_STATE.new_usertype<Map>(
|
||||
"Map",
|
||||
"getSingleton", &Map::getSingleton,
|
||||
"getCell", &Map::getCell,
|
||||
"getCells", &Map::getCells,
|
||||
"getCellId", &Map::getCellId,
|
||||
"getMapSize", &Map::getMapSize,
|
||||
"getSpawnPoint", &Map::getSpawnPoint,
|
||||
"getNumSpawnPoints", &Map::getNumSpawnPoints
|
||||
);
|
||||
|
||||
SOL_LUA_STATE.new_usertype<Pathfinder>(
|
||||
"Pathfinder",
|
||||
"getSingleton", &Pathfinder::getSingleton,
|
||||
"calcHeuristics", &Pathfinder::calcHeuristics,
|
||||
"findPath", &Pathfinder::findPath
|
||||
);
|
||||
|
||||
SOL_LUA_STATE.new_usertype<GameObjectFrame>(
|
||||
"GameObjectFrame", sol::constructors<GameObjectFrame(int, GameObject::Type, Player*, Unit*, Vector3, Quaternion)>(),
|
||||
"getOriginalUnit", &GameObjectFrame::getOriginalUnit,
|
||||
"destroy", &GameObjectFrame::destroy,
|
||||
"placeAt", &GameObjectFrame::placeAt,
|
||||
"getDirVec", &GameObjectFrame::getDirVec,
|
||||
"getLeftVec", &GameObjectFrame::getLeftVec,
|
||||
"getLength", &GameObjectFrame::getLength,
|
||||
"getWidth", &GameObjectFrame::getWidth,
|
||||
"status", &GameObjectFrame::status
|
||||
);
|
||||
|
||||
SOL_LUA_STATE.new_usertype<GameObjectFrameController>(
|
||||
"GameObjectFrameController",
|
||||
"getSingleton", &GameObjectFrameController::getSingleton,
|
||||
"checkPlacement", &GameObjectFrameController::checkPlacement
|
||||
);
|
||||
}
|
||||
|
||||
void GameManager::initLua(string gameDir){
|
||||
sol::state_view SOL_LUA_STATE = generateView();
|
||||
|
||||
path = gameDir + "Assets/";
|
||||
SOL_LUA_STATE.script("PATH = \"" + path + "\";");
|
||||
|
||||
for(string f : configData::scripts)
|
||||
SOL_LUA_STATE.script_file(path + f);
|
||||
|
||||
sol::table resTable = SOL_LUA_STATE["graphics"]["resolution"];
|
||||
width = resTable["x"];
|
||||
height = resTable["y"];
|
||||
}
|
||||
|
||||
void GameManager::start(string gameDir) {
|
||||
running = true;
|
||||
registerMembers();
|
||||
initLua(gameDir);
|
||||
|
||||
Root *root = Root::getSingleton();
|
||||
root->start(width, height, path + "../external/vb01/", "Battleship");
|
||||
|
||||
stateManager = new StateManager();
|
||||
inputManager = new InputManager(stateManager, root->getWindow());
|
||||
}
|
||||
|
||||
void GameManager::update() {
|
||||
Root::getSingleton()->update();
|
||||
SoundManager::getSingleton()->update();
|
||||
inputManager->update();
|
||||
stateManager->update();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
#ifndef GAME_MANAGER_H
|
||||
#define GAME_MANAGER_H
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#include <mapping.h>
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace gameBase{
|
||||
class InputManager;
|
||||
class StateManager;
|
||||
}
|
||||
|
||||
namespace battleship{
|
||||
class GameManager {
|
||||
public:
|
||||
static GameManager* getSingleton();
|
||||
void start(std::string);
|
||||
void update();
|
||||
inline int getWidth(){return width;}
|
||||
inline int getHeight(){return height;}
|
||||
inline std::string getPath(){return path;}
|
||||
inline gameBase::InputManager* getInputManager(){return inputManager;}
|
||||
inline bool isServerSide(){return serverSide;}
|
||||
inline bool isRunning(){return running;}
|
||||
inline void setRunning(bool r){this->running = r;}
|
||||
inline gameBase::StateManager* getStateManager(){return stateManager;}
|
||||
private:
|
||||
GameManager(){}
|
||||
~GameManager(){}
|
||||
void registerMembers();
|
||||
void initLua(std::string);
|
||||
|
||||
gameBase::StateManager *stateManager = nullptr;
|
||||
gameBase::InputManager *inputManager = nullptr;
|
||||
int width, height;
|
||||
std::string path = "";
|
||||
bool serverSide, running = false;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,38 @@
|
||||
#include "util.h"
|
||||
#include "gameManager.h"
|
||||
#include "guiAppState.h"
|
||||
#include "concreteGuiManager.h"
|
||||
|
||||
#include <stateManager.h>
|
||||
|
||||
#include <assetManager.h>
|
||||
#include <root.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
using namespace battleship;
|
||||
using namespace vb01;
|
||||
using namespace std;
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
string gamePath = string(argv[0]);
|
||||
|
||||
for(int i = 0; i < gamePath.length(); i++)
|
||||
if(gamePath[i] == '\\')
|
||||
gamePath[i] = '/';
|
||||
|
||||
gamePath = gamePath.substr(0, gamePath.find_last_of("/") + 1) + "../";
|
||||
|
||||
GameManager *gm = GameManager::getSingleton();
|
||||
gm->start(gamePath);
|
||||
gm->getStateManager()->attachAppState(new GuiAppState());
|
||||
AssetManager::getSingleton()->load(gm->getPath() + "Fonts/batang.ttf");
|
||||
|
||||
ConcreteGuiManager::getSingleton()->readLuaScreenScript("mainMenu.lua");
|
||||
|
||||
while(gm->isRunning()){
|
||||
gm->update();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
#include "environment.h"
|
||||
#include "fxManager.h"
|
||||
#include "player.h"
|
||||
#include "unit.h"
|
||||
#include "game.h"
|
||||
#include "destructable.h"
|
||||
|
||||
#include <root.h>
|
||||
#include <node.h>
|
||||
#include <material.h>
|
||||
#include <texture.h>
|
||||
#include <particleEmitter.h>
|
||||
|
||||
namespace battleship{
|
||||
using namespace std;
|
||||
using namespace vb01;
|
||||
|
||||
static Environment *environment = nullptr;
|
||||
|
||||
Environment* Environment::getSingleton(){
|
||||
if(!environment)
|
||||
environment = new Environment();
|
||||
|
||||
return environment;
|
||||
}
|
||||
|
||||
//TODO use the pos argument from the fx
|
||||
void Environment::explode(FxManager::Fx *fx, Detonation det, Vector3 pos, int damage, float radius){
|
||||
FxManager::getSingleton()->addFx(fx);
|
||||
|
||||
if(radius == 0) return;
|
||||
|
||||
for(Player *pl : Game::getSingleton()->getPlayers()){
|
||||
for(Unit *un : pl->getUnits()){
|
||||
float distance = un->getPos().getDistanceFrom(pos);
|
||||
|
||||
if(distance < radius){
|
||||
switch(det){
|
||||
case Detonation::EXPLOSION:
|
||||
un->getDestructable()->takeDamage(int(damage * (1.f - distance / radius)));
|
||||
break;
|
||||
case Detonation::EMP:
|
||||
un->setCondition(Unit::Condition::EM_JAMMED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#ifndef ENVIRONMENT_H
|
||||
#define ENVIRONMENT_H
|
||||
|
||||
#include <vector.h>
|
||||
|
||||
#include "fxManager.h"
|
||||
|
||||
namespace battleship{
|
||||
class Environment{
|
||||
public:
|
||||
enum class Detonation{EXPLOSION, EMP, CRYO};
|
||||
|
||||
static Environment* getSingleton();
|
||||
static void explode(FxManager::Fx*, Detonation, vb01::Vector3, int = 0, float = 0);
|
||||
private:
|
||||
Environment(){}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,50 @@
|
||||
#include <SFML/Audio.hpp>
|
||||
|
||||
#include "explosion.h"
|
||||
#include "util.h"
|
||||
#include "inGameAppState.h"
|
||||
#include "game.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vb01;
|
||||
|
||||
namespace battleship{
|
||||
void detonate(string p){
|
||||
sf::SoundBuffer *sfxBuffer = new sf::SoundBuffer();
|
||||
sf::Sound *sfx = nullptr;
|
||||
string p = GameManager::getSingleton()->getPath() + "Sounds/Explosions/explosion0" + to_string(rand() % 4) + ".ogg";
|
||||
|
||||
if(sfxBuffer->loadFromFile(p.c_str())){
|
||||
sfx = new sf::Sound(*sfxBuffer);
|
||||
sfx->play();
|
||||
}
|
||||
|
||||
Game::getSingleton()->addFx(Fx(sfx, 2500));
|
||||
}
|
||||
|
||||
void detonateDepthCharge(){
|
||||
sf::SoundBuffer *sfxBuffer = new sf::SoundBuffer();
|
||||
sf::Sound *sfx = nullptr;
|
||||
string p = GameManager::getSingleton()->getPath() + "Sounds/Destroyers/depthCharge.ogg";
|
||||
|
||||
if(sfxBuffer->loadFromFile(p.c_str())){
|
||||
sfx = new sf::Sound(*sfxBuffer);
|
||||
sfx->play();
|
||||
}
|
||||
|
||||
Game::getSingleton()->addFx(Fx(sfx, 2000));
|
||||
}
|
||||
|
||||
void detonateTorpedo(){
|
||||
sf::SoundBuffer *sfxBuffer = new sf::SoundBuffer();
|
||||
sf::Sound *sfx = nullptr;
|
||||
string p = GameManager::getSingleton()->getPath() + "Sounds/Submarines/torpedo.ogg";
|
||||
|
||||
if(sfxBuffer->loadFromFile(p.c_str())){
|
||||
sfx = new sf::Sound(*sfxBuffer);
|
||||
sfx->play();
|
||||
}
|
||||
|
||||
Game::getSingleton()->addFx(Fx(sfx, 250));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#ifndef EXPLOSION_H
|
||||
#define EXPLOSION_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace battleship{
|
||||
void detonate(std::string);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,232 @@
|
||||
#include "fxManager.h"
|
||||
#include "gameObject.h"
|
||||
|
||||
#include <root.h>
|
||||
#include <model.h>
|
||||
#include <box.h>
|
||||
#include <material.h>
|
||||
#include <vector.h>
|
||||
#include <particleEmitter.h>
|
||||
|
||||
#include <SFML/Audio.hpp>
|
||||
|
||||
namespace battleship{
|
||||
using namespace std;
|
||||
using namespace vb01;
|
||||
|
||||
FxManager::Fx::Component::Component(void *c, bool v, s64 dur, vb01::Vector3 p, s64 ot) : comp(c), vfx(v), duration(dur), pos(p), offsetTime(ot) {
|
||||
if(v) ((vb01::Node*)c)->setVisible(false);
|
||||
}
|
||||
|
||||
FxManager::Fx::Fx(std::vector<FxManager::Fx::Component> comps, bool re) : components(comps), reuse(re){
|
||||
toggleComponents(!re);
|
||||
}
|
||||
|
||||
FxManager::Fx* FxManager::initFx(sol::table fxTbl, Node *baseNode, bool attached, Vector3 cp){
|
||||
int numComponents = fxTbl.size();
|
||||
|
||||
if(numComponents == 0) return nullptr;
|
||||
|
||||
vector<FxManager::Fx::Component> fxComponents;
|
||||
|
||||
for(int i = 0; i < numComponents; i++){
|
||||
sol::table compTbl = fxTbl[i + 1];
|
||||
|
||||
bool vfx = compTbl["vfx"];
|
||||
s64 duration = compTbl["duration"], offset = compTbl["offset"].get_or(0);
|
||||
|
||||
if(vfx){
|
||||
sol::table meshTbl = compTbl["mesh"];
|
||||
|
||||
string meshPath = "";
|
||||
Material *mat = nullptr;
|
||||
Node *flashNode = nullptr;
|
||||
|
||||
sol::optional<sol::table> posOpt = compTbl["pos"], rotOpt = compTbl["rot"];
|
||||
Vector3 compPos = cp;
|
||||
Quaternion compRot = Quaternion::QUAT_W;
|
||||
float sc = compTbl["scale"].get_or(1);
|
||||
|
||||
if(posOpt != sol::nullopt){
|
||||
sol::table posTable = compTbl["pos"];
|
||||
compPos = Vector3(posTable["x"], posTable["y"], posTable["z"]);
|
||||
}
|
||||
|
||||
if(rotOpt != sol::nullopt){
|
||||
sol::table rotTable = compTbl["rot"];
|
||||
compRot = Quaternion(rotTable["w"], rotTable["x"], rotTable["y"], rotTable["z"]);
|
||||
}
|
||||
|
||||
sol::optional<string> pathOpt = meshTbl["path"];
|
||||
sol::optional<int> numPartOpt = meshTbl["numParticles"];
|
||||
|
||||
if(pathOpt != sol::nullopt){
|
||||
mat = new Material(Root::getSingleton()->getLibPath() + "texture");
|
||||
|
||||
meshPath = meshTbl["path"];
|
||||
flashNode = new Model(meshPath);
|
||||
((Model*)flashNode)->setMaterial(mat);
|
||||
flashNode->setPosition(compPos);
|
||||
flashNode->setOrientation(compRot);
|
||||
flashNode->setScale(Vector3(sc, sc, sc));
|
||||
}
|
||||
else if(numPartOpt != sol::nullopt){
|
||||
mat = new Material(Root::getSingleton()->getLibPath() + "particle");
|
||||
|
||||
int numParticles = meshTbl["numParticles"];
|
||||
ParticleEmitter *pe = new ParticleEmitter(numParticles);
|
||||
pe->setMaterial(mat);
|
||||
pe->setLowLife(meshTbl["lowLife"]);
|
||||
pe->setHighLife(meshTbl["highLife"]);
|
||||
pe->setSpeed(0);
|
||||
|
||||
sol::table sizeTbl = meshTbl["size"];
|
||||
pe->setSize(Vector2(sizeTbl["x"], sizeTbl["y"]));
|
||||
|
||||
flashNode = new Node(compPos + Vector3(0, 2, 0), compRot, Vector3(sc, sc, sc));
|
||||
flashNode->attachParticleEmitter(pe);
|
||||
flashNode->lookAt(Vector3::VEC_J, Vector3::VEC_K);
|
||||
}
|
||||
else{
|
||||
mat = new Material(Root::getSingleton()->getLibPath() + "texture");
|
||||
|
||||
sol::table sizeTbl = meshTbl["size"];
|
||||
Box *box = new Box(Vector3(sizeTbl["x"], sizeTbl["y"], 0));
|
||||
box->setMaterial(mat);
|
||||
|
||||
flashNode = new Node(compPos, compRot, Vector3(sc, sc, sc), "laser");
|
||||
flashNode->attachMesh(box);
|
||||
}
|
||||
|
||||
sol::optional<string> texOpt = meshTbl["texture"];
|
||||
|
||||
if(texOpt != sol::nullopt){
|
||||
string p[]{meshTbl["texture"]};
|
||||
Texture *tex = new Texture(p, 1, false);
|
||||
mat->addBoolUniform("texturingEnabled", true);
|
||||
mat->addTexUniform("diffuseMap[0]", tex, false);
|
||||
}
|
||||
else{
|
||||
sol::table colorTable = meshTbl["color"];
|
||||
mat->addVec4Uniform("diffuseColor", Vector4(colorTable["x"], colorTable["y"], colorTable["z"], colorTable["a"]));
|
||||
mat->addBoolUniform("texturingEnabled", false);
|
||||
}
|
||||
|
||||
flashNode->setVisible(false);
|
||||
Node *parNode = (attached ? baseNode : Root::getSingleton()->getRootNode());
|
||||
sol::optional<string> parNameOpt = compTbl["parent"];
|
||||
|
||||
if(parNameOpt != sol::nullopt){
|
||||
string parName = compTbl["parent"];
|
||||
parNode = baseNode->findDescendant(parName, true);
|
||||
}
|
||||
|
||||
parNode->attachChild(flashNode);
|
||||
fxComponents.push_back(FxManager::Fx::Component((void*)flashNode, vfx, duration, compPos, offset));
|
||||
}
|
||||
else{
|
||||
sf::SoundBuffer *sfxBuffer = new sf::SoundBuffer();
|
||||
sf::Sound *sfx = GameObject::prepareSfx(sfxBuffer, compTbl["path"]);
|
||||
fxComponents.push_back(FxManager::Fx::Component((void*)sfx, vfx, duration, Vector3::VEC_ZERO, offset));
|
||||
}
|
||||
}
|
||||
|
||||
return new FxManager::Fx(fxComponents, attached);
|
||||
}
|
||||
|
||||
void FxManager::Fx::toggleComponents(bool active){
|
||||
for(Component &component : components){
|
||||
component.active = active;
|
||||
component.initTime = getTime();
|
||||
}
|
||||
}
|
||||
|
||||
static FxManager *fxManager = nullptr;
|
||||
|
||||
FxManager* FxManager::getSingleton(){
|
||||
if(!fxManager)
|
||||
fxManager = new FxManager();
|
||||
|
||||
return fxManager;
|
||||
}
|
||||
|
||||
void FxManager::update(){
|
||||
for(int i = 0; i < fxs.size(); i++){
|
||||
s64 currTime = getTime();
|
||||
Fx *fx = fxs[i];
|
||||
|
||||
for(int j = 0; j < fx->components.size(); j++){
|
||||
Fx::Component &comp = fx->components[j];
|
||||
s64 currTime = getTime();
|
||||
|
||||
if(comp.comp && currTime - comp.initTime > comp.offsetTime){
|
||||
if(comp.active){
|
||||
if(comp.vfx)
|
||||
((Node*)comp.comp)->setVisible(true);
|
||||
else
|
||||
((sf::Sound*)comp.comp)->play();
|
||||
|
||||
comp.active = false;
|
||||
comp.initTime = getTime();
|
||||
}
|
||||
else if(!comp.active && currTime - comp.initTime > comp.duration){
|
||||
if(fx->reuse){
|
||||
if(comp.vfx)
|
||||
((Node*)comp.comp)->setVisible(false);
|
||||
else
|
||||
((sf::Sound*)comp.comp)->stop();
|
||||
}
|
||||
else{
|
||||
destroyFxComponent(i, j);
|
||||
fx->components.erase(fx->components.begin() + j);
|
||||
j--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(fx->components.empty()){
|
||||
delete fx;
|
||||
fxs.erase(fxs.begin() + i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FxManager::destroyFxComponent(int fid, int cid){
|
||||
Fx *fx = fxs[fid];
|
||||
|
||||
if(fx->components[cid].vfx){
|
||||
Node *vfxNode = (Node*)fx->components[cid].comp, *parNode = vfxNode->getParent();
|
||||
parNode->dettachChild(vfxNode);
|
||||
delete vfxNode;
|
||||
}
|
||||
else{
|
||||
sf::Sound *sfx = (sf::Sound*)fx->components[cid].comp;
|
||||
const sf::SoundBuffer *buffer = &sfx->getBuffer();
|
||||
sfx->stop();
|
||||
|
||||
delete sfx;
|
||||
delete buffer;
|
||||
}
|
||||
|
||||
fx->components[cid].comp = nullptr;
|
||||
}
|
||||
|
||||
void FxManager::removeFx(Fx *fx){
|
||||
int id = -1;
|
||||
|
||||
for(int i = 0; i < fxs.size(); i++)
|
||||
if(fxs[i] == fx){
|
||||
id = i;
|
||||
break;
|
||||
}
|
||||
|
||||
for(int i = 0; i < fx->components.size(); i++)
|
||||
destroyFxComponent(id, i);
|
||||
|
||||
fxs.erase(fxs.begin() + id);
|
||||
delete fx;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
#ifndef FX_MANAGER_H
|
||||
#define FX_MANAGER_H
|
||||
|
||||
#include <util.h>
|
||||
|
||||
#include <solUtil.h>
|
||||
|
||||
namespace vb01{
|
||||
class Node;
|
||||
}
|
||||
|
||||
namespace battleship{
|
||||
class FxManager{
|
||||
public:
|
||||
struct Fx {
|
||||
struct Component{
|
||||
vb01::s64 duration, initTime = 0, offsetTime = 0;
|
||||
vb01::Vector3 pos = vb01::Vector3::VEC_ZERO;
|
||||
bool vfx, active = false;
|
||||
void *comp = nullptr;
|
||||
|
||||
Component(void*, bool, vb01::s64, vb01::Vector3 = vb01::Vector3::VEC_ZERO, vb01::s64 = 0);
|
||||
};
|
||||
|
||||
bool reuse;
|
||||
std::vector<Component> components;
|
||||
|
||||
Fx(std::vector<Component>, bool = false);
|
||||
void toggleComponents(bool);
|
||||
};
|
||||
|
||||
static FxManager* getSingleton();
|
||||
FxManager::Fx* initFx(sol::table, vb01::Node*, bool, vb01::Vector3 = vb01::Vector3::VEC_ZERO);
|
||||
void update();
|
||||
void removeFx(Fx*);
|
||||
inline void addFx(Fx *fx){fxs.push_back(fx);}
|
||||
private:
|
||||
FxManager(){}
|
||||
void destroyFxComponent(int, int);
|
||||
std::vector<Fx*> fxs;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,754 @@
|
||||
#include <root.h>
|
||||
#include <quad.h>
|
||||
#include <model.h>
|
||||
#include <light.h>
|
||||
#include <material.h>
|
||||
#include <imageAsset.h>
|
||||
#include <assetManager.h>
|
||||
|
||||
#include <button.h>
|
||||
|
||||
#include <solUtil.h>
|
||||
#include <stateManager.h>
|
||||
|
||||
#include "map.h"
|
||||
#include "util.h"
|
||||
#include "vehicle.h"
|
||||
#include "game.h"
|
||||
#include "player.h"
|
||||
#include "gameObject.h"
|
||||
#include "pathfinder.h"
|
||||
#include "gameManager.h"
|
||||
#include "defConfigs.h"
|
||||
#include "resourceDeposit.h"
|
||||
#include "activeGameState.h"
|
||||
#include "concreteGuiManager.h"
|
||||
#include "gameObjectFactory.h"
|
||||
|
||||
|
||||
namespace battleship{
|
||||
using namespace std;
|
||||
using namespace vb01;
|
||||
using namespace vb01Gui;
|
||||
using namespace gameBase;
|
||||
using namespace configData;
|
||||
|
||||
static Map *map = nullptr;
|
||||
static Map::Minimap *minimap = nullptr;
|
||||
|
||||
Map::Minimap* Map::Minimap::getSingleton(){
|
||||
if(!minimap) minimap = new Map::Minimap();
|
||||
|
||||
return minimap;
|
||||
}
|
||||
|
||||
Map::Minimap::Minimap(){
|
||||
sol::state_view SOL_STATE_VIEW = generateView();
|
||||
SOL_STATE_VIEW.script_file(GameManager::getSingleton()->getPath() + "Scripts/Gui/activeGameState.lua");
|
||||
|
||||
string refIconFile = SOL_STATE_VIEW["refIcon"];
|
||||
string basePath = GameManager::getSingleton()->getPath() + "Textures/Icons/Minimap/";
|
||||
|
||||
for(ResourceDeposit *rd : Game::getSingleton()->getCivilianPlayer()->getResourceDeposits())
|
||||
depositIcons.push_back(initIcon(rd->getPos(), basePath + refIconFile));
|
||||
|
||||
string camIconFile = SOL_STATE_VIEW["eyeIcon"];
|
||||
camIcon = initIcon(Root::getSingleton()->getCamera()->getPosition(), basePath + camIconFile);
|
||||
}
|
||||
|
||||
Map::Minimap::~Minimap(){
|
||||
Node *guiNode = Root::getSingleton()->getGuiNode();
|
||||
|
||||
for(Node *node : depositIcons){
|
||||
guiNode->dettachChild(node);
|
||||
delete node;
|
||||
}
|
||||
|
||||
depositIcons.clear();
|
||||
|
||||
guiNode->dettachChild(camIcon);
|
||||
delete camIcon;
|
||||
}
|
||||
|
||||
Node* Map::Minimap::initIcon(Vector3 posOnMap, string iconPath){
|
||||
string p[]{iconPath};
|
||||
ImageAsset *asset = (ImageAsset*)AssetManager::getSingleton()->getAsset(iconPath);
|
||||
Vector3 iconSize = Vector3(asset->width, asset->height, 0);
|
||||
Texture *tex = new Texture(p, 1, false);
|
||||
|
||||
Root *root = Root::getSingleton();
|
||||
Material *mat = new Material(root->getLibPath() + "gui");
|
||||
mat->addBoolUniform("texturingEnabled", true);
|
||||
mat->addTexUniform("diffuseMap", tex, false);
|
||||
|
||||
sol::state_view SOL_LUA_VIEW = generateView();
|
||||
sol::table posTbl = SOL_LUA_VIEW["minimapPos"], sizeTbl = SOL_LUA_VIEW["minimapSize"];
|
||||
Vector2 minimapSize = Vector2(sizeTbl["x"], sizeTbl["y"]);
|
||||
Vector3 minimapPos = Vector3(posTbl["x"], posTbl["y"], posTbl["z"]);
|
||||
|
||||
Vector3 mapSize = Map::getSingleton()->getMapSize();
|
||||
Vector2 iconPos = Vector2(
|
||||
minimapSize.x * (posOnMap.x + .5 * mapSize.x) / mapSize.x,
|
||||
minimapSize.y * (posOnMap.z + .5 * mapSize.z) / mapSize.z
|
||||
);
|
||||
|
||||
Quad *quad = new Quad(iconSize, false);
|
||||
quad->setMaterial(mat);
|
||||
|
||||
Node *node = new Node(minimapPos + Vector3(iconPos.x, iconPos.y, .1) - .5 * iconSize);
|
||||
node->attachMesh(quad);
|
||||
node->setVisible(false);
|
||||
root->getGuiNode()->attachChild(node);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
//TODO add a flag to Player::getUnits* whether to include garrisoned units
|
||||
void Map::Minimap::updateImage(){
|
||||
GameManager *gm = GameManager::getSingleton();
|
||||
Map *map = Map::getSingleton();
|
||||
|
||||
string imagePath = gm->getPath() + "Models/Maps/" + map->getMapName() + "/minimap.jpg";
|
||||
ImageAsset *asset = (ImageAsset*)AssetManager::getSingleton()->getAsset(imagePath);
|
||||
int width = asset->width, height = asset->height;
|
||||
|
||||
Vector3 mapSize = map->getMapSize();
|
||||
vector<pair<Unit*, Vector2>> unitMinimapPos;
|
||||
|
||||
ActiveGameState *activeState = (ActiveGameState*)gm->getStateManager()->getAppStateByType(AppStateType::ACTIVE_STATE);
|
||||
|
||||
for(Player *pl : Game::getSingleton()->getPlayers(true))
|
||||
if(pl->getTeam() == activeState->getPlayer()->getTeam()){
|
||||
vector<Unit*> units = pl->getUnits();
|
||||
|
||||
for(Unit *u : units){
|
||||
if(u->isVehicle() && ((Vehicle*)u)->getGarrisonable()) continue;
|
||||
|
||||
Vector2 coords = Vector2(
|
||||
int(u->getPos().x / mapSize.x * width),
|
||||
int(-u->getPos().z / mapSize.z * height)
|
||||
);
|
||||
unitMinimapPos.push_back(make_pair(u, coords));
|
||||
}
|
||||
}
|
||||
|
||||
int pxId = 0, numChannels = asset->numChannels, size = width * height * numChannels;
|
||||
float losFactor = .6;
|
||||
|
||||
for(u8 *p = asset->image; p != asset->image + size; p += numChannels, pxId += numChannels){
|
||||
*(p + 0) = losFactor * oldImageData[pxId + 0];
|
||||
*(p + 1) = losFactor * oldImageData[pxId + 1];
|
||||
*(p + 2) = losFactor * oldImageData[pxId + 2];
|
||||
}
|
||||
|
||||
int unitPxRadius = 1;
|
||||
|
||||
for(pair<Unit*, Vector2> unitPair : unitMinimapPos){
|
||||
Unit *losUnit = unitPair.first;
|
||||
Vector2 losUnitCoords = unitPair.second;
|
||||
float minimapLos = losUnit->getLineOfSight() / mapSize.x * width;
|
||||
|
||||
for(int x = max(-.5f * width, losUnitCoords.x - minimapLos); x < min(.5f * width, losUnitCoords.x + minimapLos); x++){
|
||||
for(int y = max(-.5f * height, losUnitCoords.y - minimapLos); y < min(.5f * height, losUnitCoords.y + minimapLos); y++){
|
||||
int pxId = width * (y + .5 * height) + (x + .5 * width);
|
||||
Vector2 coords = Vector2(x, y);
|
||||
|
||||
if(coords.getDistanceFrom(losUnitCoords) < minimapLos){
|
||||
asset->image[numChannels * pxId + 0] = oldImageData[numChannels * pxId + 0];
|
||||
asset->image[numChannels * pxId + 1] = oldImageData[numChannels * pxId + 1];
|
||||
asset->image[numChannels * pxId + 2] = oldImageData[numChannels * pxId + 2];
|
||||
|
||||
for(pair<Unit*, Vector2> addUnitPair : unitMinimapPos)
|
||||
if(fabs(addUnitPair.second.x - coords.x) < unitPxRadius && fabs(addUnitPair.second.y - coords.y) < unitPxRadius){
|
||||
Vector3 unitCol = addUnitPair.first->getPlayer()->getColor();
|
||||
asset->image[numChannels * pxId + 0] = unitCol.x * 255;
|
||||
asset->image[numChannels * pxId + 1] = unitCol.y * 255;
|
||||
asset->image[numChannels * pxId + 2] = unitCol.z * 255;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Node *rectNode = ConcreteGuiManager::getSingleton()->getButton("minimap")->getRectNode();
|
||||
Material *mat = rectNode->getMesh(0)->getMaterial();
|
||||
Texture *tex = ((Material::TextureUniform*)mat->getUniform("diffuseMap"))->value;
|
||||
tex->loadImageData(asset, false);
|
||||
}
|
||||
|
||||
void Map::Minimap::updateCamFrame(Button *minimapButton){
|
||||
Vector3 camPos = Root::getSingleton()->getCamera()->getPosition();
|
||||
Vector3 mapSize = Map::getSingleton()->getMapSize();
|
||||
Vector2 minimapSize = minimapButton->getSize();
|
||||
Vector2 iconPos = Vector2(
|
||||
minimapSize.x * (camPos.x + .5 * mapSize.x) / mapSize.x,
|
||||
minimapSize.y * (camPos.z + .5 * mapSize.z) / mapSize.z
|
||||
);
|
||||
|
||||
camIcon->setPosition(minimapButton->getPos() + Vector3(iconPos.x, iconPos.y, .1));
|
||||
}
|
||||
|
||||
void Map::Minimap::update(){
|
||||
if(!GameManager::getSingleton()->getStateManager()->getAppStateByType(AppStateType::ACTIVE_STATE)) return;
|
||||
|
||||
Button *mb = ConcreteGuiManager::getSingleton()->getButton("minimap");
|
||||
updateCamFrame(mb);
|
||||
}
|
||||
|
||||
void Map::Minimap::load(){
|
||||
for(Node *node : depositIcons)
|
||||
node->setVisible(true);
|
||||
|
||||
AssetManager *am = AssetManager::getSingleton();
|
||||
string minimapPath = GameManager::getSingleton()->getPath() + "Models/Maps/" + Map::getSingleton()->getMapName() + "/minimap.jpg";
|
||||
|
||||
am->load(minimapPath);
|
||||
ImageAsset *asset = (ImageAsset*)am->getAsset(minimapPath);
|
||||
int imgSize = asset->width * asset->height * asset->numChannels;
|
||||
oldImageData = new u8[imgSize];
|
||||
|
||||
for(int i = 0; i < imgSize; i++)
|
||||
oldImageData[i] = asset->image[i];
|
||||
}
|
||||
|
||||
void Map::Minimap::unload(){
|
||||
for(Node *node : depositIcons)
|
||||
node->setVisible(false);
|
||||
|
||||
delete[] oldImageData;
|
||||
}
|
||||
|
||||
Map* Map::getSingleton(){
|
||||
if(!map) map = new Map;
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
vector<Map::Edge> Map::generateAdjacentNodeEdges(int numVertCells, int i, int numHorCells, int j, int weight){
|
||||
vector<Map::Edge> edges;
|
||||
bool checkUp = (i > 0), checkRight = (j < numHorCells - 1), checkDown = (i < numVertCells - 1), checkLeft = (j > 0);
|
||||
|
||||
if(checkLeft)
|
||||
edges.push_back(Map::Edge(weight, numHorCells * i + j, numHorCells * i + j - 1));
|
||||
|
||||
if(checkRight)
|
||||
edges.push_back(Map::Edge(weight, numHorCells * i + j, numHorCells * i + j + 1));
|
||||
|
||||
if(checkUp)
|
||||
edges.push_back(Map::Edge(weight, numHorCells * i + j, numHorCells * (i - 1) + j));
|
||||
|
||||
if(checkDown)
|
||||
edges.push_back(Map::Edge(weight, numHorCells * i + j, numHorCells * (i + 1) + j));
|
||||
|
||||
if(checkUp && checkLeft)
|
||||
edges.push_back(Map::Edge(int(sqrt(2 * weight * weight)), numHorCells * i + j, numHorCells * (i - 1) + j - 1));
|
||||
|
||||
if(checkUp && checkRight)
|
||||
edges.push_back(Map::Edge(int(sqrt(2 * weight * weight)), numHorCells * i + j, numHorCells * (i - 1) + j + 1));
|
||||
|
||||
if(checkDown && checkLeft)
|
||||
edges.push_back(Map::Edge(int(sqrt(2 * weight * weight)), numHorCells * i + j, numHorCells * (i + 1) + j - 1));
|
||||
|
||||
if(checkDown && checkRight)
|
||||
edges.push_back(Map::Edge(int(sqrt(2 * weight * weight)), numHorCells * i + j, numHorCells * (i + 1) + j + 1));
|
||||
|
||||
return edges;
|
||||
}
|
||||
|
||||
void Map::update(){
|
||||
Minimap::getSingleton()->update();
|
||||
}
|
||||
|
||||
void Map::loadSkybox(){
|
||||
sol::state_view SOL_LUA_STATE = generateView();
|
||||
string skyboxName = SOL_LUA_STATE[mapTable]["skybox"];
|
||||
string basePath = GameManager::getSingleton()->getPath() + "Textures/Skyboxes/" + skyboxName;
|
||||
|
||||
const int numPaths = 6;
|
||||
string path[numPaths] = {
|
||||
basePath + "/left.jpg",
|
||||
basePath + "/right.jpg",
|
||||
basePath + "/up.jpg",
|
||||
basePath + "/down.jpg",
|
||||
basePath + "/front.jpg",
|
||||
basePath + "/back.jpg"
|
||||
};
|
||||
|
||||
for(int i = 0; i < numPaths; i++)
|
||||
AssetManager::getSingleton()->load(path[i]);
|
||||
|
||||
Root::getSingleton()->createSkybox(path);
|
||||
}
|
||||
|
||||
void Map::loadLights(){
|
||||
sol::state_view SOL_LUA_VIEW = generateView();
|
||||
sol::table lightsTbl = SOL_LUA_VIEW[mapTable]["lights"];
|
||||
int numLights = lightsTbl.size();
|
||||
|
||||
for(int i = 0; i < numLights; i++){
|
||||
int id = i + 1;
|
||||
Light::Type type = (Light::Type)lightsTbl[id]["type"];
|
||||
sol::table colTbl = lightsTbl[id]["color"];
|
||||
|
||||
Light *light = new Light(type);
|
||||
light->setColor(Vector3(colTbl["x"], colTbl["y"], colTbl["z"]));
|
||||
|
||||
Node *lightNode = new Node();
|
||||
lights.push_back(lightNode);
|
||||
lightNode->addLight(light);
|
||||
|
||||
if(type == Light::Type::DIRECTIONAL){
|
||||
sol::table dirTbl = lightsTbl[id]["dir"];
|
||||
Vector3 dir = Vector3(dirTbl["x"], dirTbl["y"], dirTbl["z"]).norm();
|
||||
lightNode->lookAt(dir);
|
||||
}
|
||||
|
||||
Root::getSingleton()->getRootNode()->attachChild(lightNode);
|
||||
}
|
||||
}
|
||||
|
||||
void Map::loadTerrainObject(int id){
|
||||
string texPath = "", albedoPath = "";
|
||||
Quad *quad = nullptr;
|
||||
Node *node = nullptr;
|
||||
sol::state_view SOL_LUA_STATE = generateView();
|
||||
|
||||
if(id == -1){
|
||||
string basePath = GameManager::getSingleton()->getPath() + "Models/Maps/" + mapName + "/";
|
||||
|
||||
albedoPath = SOL_LUA_STATE[mapTable]["terrain"]["albedo"];
|
||||
texPath = basePath + albedoPath;
|
||||
|
||||
string modelPath = SOL_LUA_STATE[mapTable]["terrain"]["model"];
|
||||
string terrainFile = basePath + modelPath;
|
||||
|
||||
AssetManager::getSingleton()->load(terrainFile);
|
||||
node = (Model*)((new Model(terrainFile))->getChild(0));
|
||||
|
||||
Node *par = node->getParent();
|
||||
par->dettachChild(node);
|
||||
delete par;
|
||||
}
|
||||
else{
|
||||
sol::table waterBodyTable = SOL_LUA_STATE[mapTable]["waterbodies"][id + 1], posTable = waterBodyTable["pos"];
|
||||
albedoPath = waterBodyTable["albedo"];
|
||||
texPath = GameManager::getSingleton()->getPath() + "Textures/Water/" + albedoPath;
|
||||
|
||||
quad = new Quad(Vector3(waterBodyTable["size"]["x"], waterBodyTable["size"]["y"], 1), true);
|
||||
Vector3 pos = Vector3(posTable["x"], posTable["y"], posTable["z"]);
|
||||
node = new Node(pos);
|
||||
node->attachMesh(quad);
|
||||
}
|
||||
|
||||
terrainNode->attachChild(node);
|
||||
|
||||
Material *mat = new Material(Root::getSingleton()->getLibPath() + "texture");
|
||||
mat->addBoolUniform("texturingEnabled", true);
|
||||
mat->addBoolUniform("lightingEnabled", true);
|
||||
mat->addBoolUniform("constLightingEnabled", true);
|
||||
mat->addBoolUniform("normalMapEnabled", false);
|
||||
mat->addBoolUniform("specularMapEnabled", false);
|
||||
mat->addBoolUniform("castShadow", false);
|
||||
|
||||
string fr[]{texPath};
|
||||
AssetManager::getSingleton()->load(fr[0]);
|
||||
Texture *t = new Texture(fr, 1, false);
|
||||
|
||||
mat->addTexUniform("textures[0]", t, true);
|
||||
|
||||
if(id == -1)
|
||||
((Model*)node)->setMaterial(mat);
|
||||
else{
|
||||
mat->setTransparent(true);
|
||||
quad->setMaterial(mat);
|
||||
}
|
||||
}
|
||||
|
||||
int Map::getNumMapSpawnPoints(string name){
|
||||
if(name != "")
|
||||
generateView().script_file(GameManager::getSingleton()->getPath() + "Models/Maps/" + name + "/" + name + ".lua");
|
||||
|
||||
sol::table spawnPointsTbl = generateView()["metadata"]["spawnPoints"];
|
||||
return spawnPointsTbl.size();
|
||||
}
|
||||
|
||||
//TODO improve for underwater cells
|
||||
vector<int> Map::getSurroundingCells(Vector3 p, int numRings){
|
||||
int numHorCells = int(mapSize.x / CELL_SIZE.x);
|
||||
int numVertCells = int(mapSize.z / CELL_SIZE.z);
|
||||
int horId = int((.5 * mapSize.x + p.x) / CELL_SIZE.x);
|
||||
int vertId = int((.5 * mapSize.z + p.z) / CELL_SIZE.z);
|
||||
|
||||
vector<int> cellIds;
|
||||
|
||||
for(int i = max(vertId - numRings, 0); i <= min(vertId + numRings, numVertCells - 1); i++)
|
||||
for(int j = max(horId - numRings, 0); j <= min(horId + numRings, numHorCells - 1); j++)
|
||||
cellIds.push_back(numHorCells * i + j);
|
||||
|
||||
return cellIds;
|
||||
}
|
||||
|
||||
void Map::blockCells(Unit *unit){
|
||||
vector<int> surroundingCellIds = getSurroundingCells(unit->getPos(), 0);
|
||||
|
||||
for(int scid : surroundingCellIds){
|
||||
if(cells[scid].blockedBy && cells[scid].blockedBy != unit) continue;
|
||||
|
||||
bool within = unit->pointWithinObj(cells[scid].pos);
|
||||
cells[scid].blockedBy = (within ? unit : nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void Map::unblockCells(Unit *unit){
|
||||
vector<int> surroundingCellIds = getSurroundingCells(unit->getPos(), 0);
|
||||
|
||||
for(int scid : surroundingCellIds)
|
||||
if(cells[scid].blockedBy == unit)
|
||||
cells[scid].blockedBy = nullptr;
|
||||
}
|
||||
|
||||
void Map::loadSpawnPoints(){
|
||||
sol::state_view SOL_LUA_VIEW = generateView();
|
||||
int numSpawnPoints = getNumMapSpawnPoints();
|
||||
|
||||
for(int i = 0; i < numSpawnPoints; i++){
|
||||
sol::table posTable = SOL_LUA_VIEW[mapTable]["spawnPoints"][i + 1];
|
||||
spawnPoints.push_back(Vector3(posTable["x"], posTable["y"], posTable["z"]));
|
||||
}
|
||||
}
|
||||
|
||||
void Map::loadPlayerGameObjects(Player *player, sol::table playerTbl){
|
||||
sol::state_view SOL_LUA_VIEW = generateView();
|
||||
|
||||
string resDepInd = "resourceDeposits";
|
||||
sol::optional<sol::table> resDepTblOpt = playerTbl[resDepInd];
|
||||
|
||||
if(resDepTblOpt != sol::nullopt){
|
||||
sol::table resDepTbl = playerTbl[resDepInd];
|
||||
int numNpcObjs = resDepTbl.size();
|
||||
|
||||
for(int j = 0; j < numNpcObjs; j++){
|
||||
sol::table npcObjTable = resDepTbl[j + 1];
|
||||
int id = npcObjTable["id"];
|
||||
|
||||
sol::table posTable = npcObjTable["pos"];
|
||||
Vector3 pos = Vector3(posTable["x"], posTable["y"], posTable["z"]);
|
||||
|
||||
sol::table rotTable = npcObjTable["rot"];
|
||||
Quaternion rot = Quaternion(rotTable["w"], rotTable["x"], rotTable["y"], rotTable["z"]);
|
||||
int initAmmount = resDepTbl[j + 1]["initAmmount"];
|
||||
|
||||
player->addResourceDeposit(GameObjectFactory::createResourceDeposit(player, id, pos, rot, initAmmount));
|
||||
}
|
||||
}
|
||||
|
||||
string unitInd = "units";
|
||||
sol::optional<sol::table> unitsTblOpt = playerTbl[unitInd];
|
||||
|
||||
if(unitsTblOpt != sol::nullopt){
|
||||
sol::table unitsTbl = playerTbl[unitInd];
|
||||
int numUnits = unitsTbl.size();
|
||||
|
||||
for(int j = 0; j < numUnits; j++){
|
||||
sol::table unitTable = unitsTbl[j + 1];
|
||||
|
||||
string posInd = "pos";
|
||||
Vector3 pos = Vector3(unitTable[posInd]["x"], unitTable[posInd]["y"], unitTable[posInd]["z"]);
|
||||
|
||||
string rotInd = "rot";
|
||||
Quaternion rot = Quaternion(unitTable[rotInd]["w"], unitTable[rotInd]["x"], unitTable[rotInd]["y"], unitTable[rotInd]["z"]);
|
||||
|
||||
int id = unitTable["id"];
|
||||
int buildStatus = unitTable["buildStatus"].get_or(0);
|
||||
player->addUnit(GameObjectFactory::createUnit(player, id, pos, rot, buildStatus));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TODO move minimap loading elsewhere
|
||||
void Map::loadPlayersGameObjects(){
|
||||
Game *game = Game::getSingleton();
|
||||
vector<Player*> choosablePlayers = game->getPlayers(false);
|
||||
sol::state_view SOL_LUA_VIEW = generateView();
|
||||
|
||||
for(int i = 0; i < choosablePlayers.size(); i++){
|
||||
sol::table playerTbl = SOL_LUA_VIEW[mapTable]["choosablePlayers"][i + 1];
|
||||
loadPlayerGameObjects(choosablePlayers[i], playerTbl);
|
||||
}
|
||||
|
||||
sol::table civPlayerTbl = SOL_LUA_VIEW[mapTable]["civilianPlayer"];
|
||||
loadPlayerGameObjects(game->getCivilianPlayer(), civPlayerTbl);
|
||||
|
||||
Minimap::getSingleton()->load();
|
||||
}
|
||||
|
||||
void Map::preprareScene(bool empty){
|
||||
Game::getSingleton()->setCivilianPlayer(new Player(0, 0, 0, .5 * Vector3::VEC_IJK));
|
||||
|
||||
Root *root = Root::getSingleton();
|
||||
Node *rootNode = root->getRootNode();
|
||||
string libPath = root->getLibPath();
|
||||
terrainNode = new Node();
|
||||
rootNode->attachChild(terrainNode);
|
||||
|
||||
cellNode = new Node();
|
||||
cellNode->setVisible(false);
|
||||
rootNode->attachChild(cellNode);
|
||||
landCellMat = new Material(libPath + "texture");
|
||||
landCellMat->addBoolUniform("lightingEnabled", false);
|
||||
landCellMat->addBoolUniform("texturingEnabled", false);
|
||||
landCellMat->addVec4Uniform("diffuseColor", Vector4(0, 1, 0, 1));
|
||||
waterCellMat = new Material(libPath + "texture");
|
||||
waterCellMat->addBoolUniform("lightingEnabled", false);
|
||||
waterCellMat->addBoolUniform("texturingEnabled", false);
|
||||
waterCellMat->addVec4Uniform("diffuseColor", Vector4(0, 0, 1, 1));
|
||||
|
||||
Camera *cam = root->getCamera();
|
||||
cam->setFarPlane(600);
|
||||
cam->setPosition(Vector3(1, 1, 1) * configData::CAMERA_DISTANCE);
|
||||
cam->lookAt(Vector3(-1, -1, -1).norm(), Vector3(-1, 1, -1).norm());
|
||||
|
||||
if(empty){
|
||||
Light *light = new Light(Light::Type::AMBIENT);
|
||||
light->setColor(Vector3::VEC_IJK * .9);
|
||||
|
||||
Node *node = new Node();
|
||||
node->addLight(light);
|
||||
Root::getSingleton()->getRootNode()->attachChild(node);
|
||||
lights.push_back(node);
|
||||
}
|
||||
}
|
||||
|
||||
//TODO implement toggleable cell rendering
|
||||
void Map::loadCells(){
|
||||
sol::state_view SOL_LUA_VIEW = generateView();
|
||||
sol::table cellsTable = SOL_LUA_VIEW["cells"];
|
||||
int numCells = cellsTable.size();
|
||||
|
||||
for(int i = 0; i < numCells; i++){
|
||||
sol::table cellTable = cellsTable[i + 1], posTable = cellTable["pos"];
|
||||
int numEdges = cellTable["numEdges"];
|
||||
vector<Edge> edges;
|
||||
|
||||
for(int j = 0; j < numEdges; j++){
|
||||
sol::table edgeTable = cellTable["edges"][j + 1];
|
||||
edges.push_back(Edge(edgeTable["weight"], edgeTable["srcCellId"], edgeTable["destCellId"]));
|
||||
}
|
||||
|
||||
int numUnderWaterCells = cellTable["numUnderWaterCells"];
|
||||
vector<int> underWaterCellIds;
|
||||
|
||||
for(int j = 0; j < numUnderWaterCells; j++)
|
||||
underWaterCellIds.push_back((int)cellTable["underWaterCellId"][j + 1]);
|
||||
|
||||
Vector3 cellPos = Vector3(posTable["x"], posTable["y"], posTable["z"]);
|
||||
Cell::Type cellType = (Cell::Type)cellTable["type"];
|
||||
|
||||
/*
|
||||
Quad *quad = new Quad(Vector3(CELL_SIZE.x, CELL_SIZE.z, 0));
|
||||
quad->setWireframe(true);
|
||||
quad->setMaterial(cellType == Cell::Type::LAND ? landCellMat : waterCellMat);
|
||||
|
||||
Node *node = new Node(cellPos + Vector3::VEC_J * .1);
|
||||
node->attachMesh(quad);
|
||||
*/
|
||||
|
||||
cells.push_back(Cell(cellPos, cellType, edges, underWaterCellIds));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void Map::load(string mapName){
|
||||
this->mapName = mapName;
|
||||
|
||||
Pathfinder::getSingleton()->setImpassibleNodeVal(u32(0 - 1));
|
||||
string path = GameManager::getSingleton()->getPath();
|
||||
AssetManager::getSingleton()->load(path + "Textures/", true);
|
||||
|
||||
sol::state_view SOL_LUA_STATE = generateView();
|
||||
SOL_LUA_STATE.script_file(path + "Models/Maps/" + mapName + "/" + mapName + ".lua");
|
||||
SOL_LUA_STATE.script_file(path + "Models/Maps/" + mapName + "/cells.lua");
|
||||
|
||||
preprareScene(false);
|
||||
loadSpawnPoints();
|
||||
loadSkybox();
|
||||
loadCells();
|
||||
loadTerrainObject(-1);
|
||||
|
||||
sol::optional<sol::table> lightsOpt = SOL_LUA_STATE[mapTable]["lights"];
|
||||
|
||||
if(lightsOpt != sol::nullopt)
|
||||
loadLights();
|
||||
|
||||
sol::table sizeTable = SOL_LUA_STATE[mapTable]["size"];
|
||||
mapSize = Vector3(sizeTable["x"], sizeTable["y"], sizeTable["z"]);
|
||||
sol::table wbTbl = SOL_LUA_STATE[mapTable]["waterbodies"];
|
||||
int numWaterbodies = wbTbl.size();
|
||||
|
||||
for(int i = 0; i < numWaterbodies; i++)
|
||||
loadTerrainObject(i);
|
||||
}
|
||||
|
||||
void Map::create(string mapName, Vector3 mapSize){
|
||||
this->mapName = mapName;
|
||||
this->mapSize = mapSize;
|
||||
|
||||
//addSpawnPoint(Vector3::VEC_ZERO);
|
||||
preprareScene(true);
|
||||
}
|
||||
|
||||
//TODO unload skybox assets
|
||||
void Map::unloadSkybox(){
|
||||
Root::getSingleton()->removeSkybox();
|
||||
}
|
||||
|
||||
void Map::unloadLights(){
|
||||
while(!lights.empty()){
|
||||
Root::getSingleton()->getRootNode()->dettachChild(lights[0]);
|
||||
delete lights[0];
|
||||
lights.erase(lights.begin());
|
||||
}
|
||||
}
|
||||
|
||||
void Map::unloadCells(){
|
||||
while(cellNode->getNumChildren() > 0){
|
||||
Node *node = cellNode->getChild(0);
|
||||
node->getMesh(0)->setMaterial(nullptr);
|
||||
cellNode->dettachChild(node);
|
||||
delete node;
|
||||
}
|
||||
|
||||
delete landCellMat;
|
||||
delete waterCellMat;
|
||||
|
||||
cells.clear();
|
||||
}
|
||||
|
||||
//TODO unload terrain assets
|
||||
void Map::unloadTerrainObjects(){
|
||||
while(terrainNode->getNumChildren() > 0){
|
||||
Node *node = terrainNode->getChild(0);
|
||||
terrainNode->dettachChild(node);
|
||||
delete node;
|
||||
}
|
||||
}
|
||||
|
||||
void Map::unloadPlayerObjects(){
|
||||
for(Player *pl : Game::getSingleton()->getPlayers(true)){
|
||||
while(pl->getNumUnits() > 0){
|
||||
pl->removeUnit(0);
|
||||
}
|
||||
|
||||
while(pl->getNumResourceDeposits() > 0){
|
||||
pl->removeResourceDeposit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Map::destroyScene(){
|
||||
Node *rootNode = Root::getSingleton()->getRootNode();
|
||||
rootNode->dettachChild(terrainNode);
|
||||
rootNode->dettachChild(cellNode);
|
||||
|
||||
delete terrainNode;
|
||||
delete cellNode;
|
||||
}
|
||||
|
||||
void Map::unload(){
|
||||
Minimap::getSingleton()->unload();
|
||||
|
||||
unloadPlayerObjects();
|
||||
unloadCells();
|
||||
unloadTerrainObjects();
|
||||
destroyScene();
|
||||
unloadLights();
|
||||
unloadSkybox();
|
||||
spawnPoints.clear();
|
||||
}
|
||||
|
||||
vector<RayCaster::CollisionResult> Map::raycastTerrain(Vector3 rayPos, Vector3 rayDir, bool bothTerrTypes){
|
||||
vector<RayCaster::CollisionResult> allResults = RayCaster::cast(rayPos, rayDir, terrainNode->getChild(0), 0, configData::DIST_FROM_RAY);
|
||||
|
||||
if(bothTerrTypes){
|
||||
vector<Node*> waterNodes = terrainNode->getChildren();
|
||||
waterNodes.erase(waterNodes.begin());
|
||||
|
||||
vector<RayCaster::CollisionResult> waterResults = RayCaster::cast(rayPos, rayDir, waterNodes);
|
||||
allResults.insert(allResults.end(), waterResults.begin(), waterResults.end());
|
||||
|
||||
RayCaster::sortResults(allResults);
|
||||
}
|
||||
|
||||
return allResults;
|
||||
}
|
||||
|
||||
template<typename T> int Map::bsearch(vector<T> haystack, T needle, float eps){
|
||||
T haystackMidVal;
|
||||
bool sizeHaystackEven = (haystack.size() % 2 == 0);
|
||||
int midValId = haystack.size() / 2;
|
||||
|
||||
if(sizeHaystackEven)
|
||||
haystackMidVal = (haystack[midValId - 1] + haystack[midValId]) / 2;
|
||||
else
|
||||
haystackMidVal = haystack[midValId];
|
||||
|
||||
int beginId, endId;
|
||||
|
||||
if(fabs(haystackMidVal - needle) > eps){
|
||||
if(fabs(haystackMidVal - needle) < eps){
|
||||
beginId = 0;
|
||||
endId = (midValId - 1);
|
||||
}
|
||||
else{
|
||||
endId = haystack.size() - 1;
|
||||
endId = (midValId + 1);
|
||||
}
|
||||
|
||||
return bsearch(vector<T>(haystack.begin() + beginId, haystack.begin() + endId), needle);
|
||||
}
|
||||
else{
|
||||
if(sizeHaystackEven)
|
||||
return midValId - (needle > haystackMidVal ? 0 : 1);
|
||||
else
|
||||
return midValId;
|
||||
}
|
||||
}
|
||||
|
||||
//TODO replace search with binary search
|
||||
//TODO optimize horizontal and vertical id calculcation
|
||||
int Map::getCellId(Vector3 pos, bool checkUnderwaterCells){
|
||||
int numHorCells = int(mapSize.x / CELL_SIZE.x), horId = -1;
|
||||
|
||||
for(int i = 0; i < numHorCells; i++)
|
||||
if(fabs(cells[i].pos.x - pos.x) <= .5 * CELL_SIZE.x){
|
||||
horId = i;
|
||||
break;
|
||||
}
|
||||
|
||||
int numVertCells = int(mapSize.z / CELL_SIZE.z), vertId = -1;
|
||||
|
||||
for(int i = 0; i < numVertCells; i++)
|
||||
if(fabs(cells[i * numHorCells].pos.z - pos.z) <= .5 * CELL_SIZE.z){
|
||||
vertId = i;
|
||||
break;
|
||||
}
|
||||
|
||||
int surfaceCellId = vertId * numHorCells + horId;
|
||||
|
||||
if(checkUnderwaterCells && cells[surfaceCellId].type == Cell::Type::WATER && !cells[surfaceCellId].underWaterCellIds.empty()){
|
||||
int cellId = surfaceCellId;
|
||||
|
||||
for(int i = 0; i <= cells[surfaceCellId].underWaterCellIds.size(); i++){
|
||||
cellId = (i == 0 ? surfaceCellId : cells[surfaceCellId].underWaterCellIds[i - 1]);
|
||||
|
||||
if(fabs(cells[cellId].pos.y - pos.y) < .5 * CELL_SIZE.y)
|
||||
return cellId;
|
||||
}
|
||||
|
||||
return surfaceCellId;
|
||||
}
|
||||
else return surfaceCellId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
#ifndef MAP_H
|
||||
#define MAP_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <rayCaster.h>
|
||||
#include <vector.h>
|
||||
#include <util.h>
|
||||
|
||||
#include <solUtil.h>
|
||||
|
||||
namespace vb01{
|
||||
class Model;
|
||||
class Material;
|
||||
class Node;
|
||||
}
|
||||
|
||||
namespace vb01Gui{
|
||||
class Button;
|
||||
}
|
||||
|
||||
namespace battleship{
|
||||
class Player;
|
||||
class Unit;
|
||||
class ResourceDeposit;
|
||||
struct Cell;
|
||||
|
||||
class Map {
|
||||
public:
|
||||
struct Cell;
|
||||
|
||||
struct Edge{
|
||||
Edge(vb01::s64 w, vb01::s64 src, vb01::s64 dest) : weight(w), srcCellId(src), destCellId(dest){}
|
||||
vb01::s64 weight, srcCellId, destCellId;
|
||||
};
|
||||
|
||||
struct Cell{
|
||||
enum Type{LAND, WATER};
|
||||
|
||||
Type type;
|
||||
vb01::Vector3 pos;
|
||||
std::vector<Edge> edges;
|
||||
Unit *blockedBy = nullptr;
|
||||
std::vector<int> underWaterCellIds;
|
||||
|
||||
Cell(){}
|
||||
Cell(vb01::Vector3 p, Type t, std::vector<Edge> e = std::vector<Edge>{}, std::vector<int> uc = std::vector<int>{}): pos(p), type(t), edges(e), underWaterCellIds(uc){}
|
||||
};
|
||||
|
||||
class Minimap{
|
||||
public:
|
||||
static Minimap* getSingleton();
|
||||
~Minimap();
|
||||
void update();
|
||||
void updateImage();
|
||||
void load();
|
||||
void unload();
|
||||
inline vb01::u8* getOldMinimapImage(){return oldImageData;}
|
||||
private:
|
||||
Minimap();
|
||||
vb01::Node* initIcon(vb01::Vector3, std::string);
|
||||
void updateCamFrame(vb01Gui::Button*);
|
||||
|
||||
vb01::u8 *oldImageData = nullptr;
|
||||
vb01::Node *camFrame = nullptr;
|
||||
std::vector<vb01::Node*> depositIcons;
|
||||
vb01::Node* camIcon = nullptr;
|
||||
};
|
||||
|
||||
static Map* getSingleton();
|
||||
~Map(){}
|
||||
static std::vector<Edge> generateAdjacentNodeEdges(int, int, int, int, int);
|
||||
void update();
|
||||
void load(std::string);
|
||||
void create(std::string, vb01::Vector3);
|
||||
void unload();
|
||||
std::vector<vb01::RayCaster::CollisionResult> raycastTerrain(vb01::Vector3, vb01::Vector3, bool);
|
||||
int getCellId(vb01::Vector3, bool = true);
|
||||
bool isPointWithinTerrainObject(vb01::Vector3, int);
|
||||
void loadPlayersGameObjects();
|
||||
int getNumMapSpawnPoints(std::string = "");
|
||||
std::vector<int> getSurroundingCells(vb01::Vector3, int);
|
||||
void blockCells(Unit*);
|
||||
void unblockCells(Unit*);
|
||||
inline Map::Cell getCell(int i){return cells[i];}
|
||||
inline std::string getMapName(){return mapName;}
|
||||
inline vb01::Node* getNodeParent(){return terrainNode;}
|
||||
inline vb01::Vector3 getCellSize(){return CELL_SIZE;}
|
||||
inline int getNumSpawnPoints(){return spawnPoints.size();}
|
||||
inline vb01::Vector3 getSpawnPoint(int i){return spawnPoints[i];}
|
||||
inline void setMapSize(vb01::Vector3 s){this->mapSize = s;}
|
||||
inline vb01::Vector3 getMapSize(){return mapSize;}
|
||||
inline void addSpawnPoint(vb01::Vector3 sp){spawnPoints.push_back(sp);}
|
||||
inline std::vector<Map::Cell>& getCells(){return cells;}
|
||||
inline vb01::Node* getLight(int i){return lights[i];}
|
||||
inline std::vector<vb01::Node*> getLights(){return lights;}
|
||||
inline float getBaseHeight(){return baseHeight;}
|
||||
inline void setBaseHeight(float bh){this->baseHeight = bh;}
|
||||
private:
|
||||
std::string mapTable = "metadata";
|
||||
vb01::Node *terrainNode = nullptr, *cellNode = nullptr;
|
||||
vb01::Material *landCellMat = nullptr, *waterCellMat = nullptr;
|
||||
std::string mapName;
|
||||
vb01::Vector3 CELL_SIZE = vb01::Vector3(7, 7, 7), mapSize;
|
||||
std::vector<vb01::Vector3> spawnPoints;
|
||||
std::vector<Cell> cells;
|
||||
float baseHeight;
|
||||
std::vector<vb01::Node*> lights;
|
||||
|
||||
Map(){}
|
||||
void preprareScene(bool);
|
||||
void loadSpawnPoints();
|
||||
void loadLights();
|
||||
void loadSkybox();
|
||||
void loadCells();
|
||||
void loadPlayerGameObjects(Player*, sol::table);
|
||||
void loadTerrainObject(int);
|
||||
void unloadTerrainObjects();
|
||||
void unloadCells();
|
||||
void unloadLights();
|
||||
void unloadSkybox();
|
||||
void unloadPlayerObjects();
|
||||
void destroyScene();
|
||||
template<typename T> int bsearch(std::vector<T>, T, float);
|
||||
};
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,107 @@
|
||||
#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(){
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -0,0 +1,226 @@
|
||||
#include "gameObject.h"
|
||||
#include "gameManager.h"
|
||||
#include "destructable.h"
|
||||
#include "defConfigs.h"
|
||||
#include "player.h"
|
||||
#include "game.h"
|
||||
#include "unit.h"
|
||||
|
||||
#include <solUtil.h>
|
||||
|
||||
#include <material.h>
|
||||
#include <box.h>
|
||||
|
||||
#include <SFML/Audio.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace battleship{
|
||||
using namespace std;
|
||||
using namespace vb01;
|
||||
using namespace gameBase;
|
||||
using namespace configData;
|
||||
|
||||
GameObject::GameObject(Type t, int i, Player *pl, vb01::Vector3 vec, vb01::Quaternion quat) : type(t), id(i), player(pl), pos(vec), rot(quat){}
|
||||
|
||||
void GameObject::reinit(){
|
||||
placeAt(pos);
|
||||
orientAt(rot);
|
||||
|
||||
if(hitbox){
|
||||
Box *hbMesh = (Box*)hitbox->getMesh(0);
|
||||
hbMesh->setSize(Vector3(width, height, length));
|
||||
hbMesh->updateVerts(hbMesh->getMeshBase());
|
||||
hitbox->setVisible(Game::getSingleton()->isDebug());
|
||||
}
|
||||
}
|
||||
|
||||
void GameObject::update(){
|
||||
leftVec = model->getGlobalAxis(0);
|
||||
upVec = model->getGlobalAxis(1);
|
||||
dirVec = model->getGlobalAxis(2);
|
||||
screenPos = spaceToScreen(pos);
|
||||
}
|
||||
|
||||
void GameObject::placeAt(Vector3 p) {
|
||||
model->setPosition(p);
|
||||
pos = p;
|
||||
}
|
||||
|
||||
void GameObject::orientAt(Quaternion rotQuat){
|
||||
rot = rotQuat;
|
||||
model->setOrientation(rotQuat);
|
||||
leftVec = model->getGlobalAxis(0);
|
||||
upVec = model->getGlobalAxis(1);
|
||||
dirVec = model->getGlobalAxis(2);
|
||||
}
|
||||
|
||||
//TODO remove neccessity to create a material for an invisible mesh
|
||||
void GameObject::initHitbox(){
|
||||
Material *mat = new Material(Root::getSingleton()->getLibPath() + "texture");
|
||||
mat->addBoolUniform("texturingEnabled", false);
|
||||
mat->addBoolUniform("lightingEnabled", false);
|
||||
mat->addVec4Uniform("diffuseColor", Vector4(1, 1, 1, 1));
|
||||
|
||||
Box *box = new Box(Vector3(width, height, length));
|
||||
box->setWireframe(true);
|
||||
box->setMaterial(mat);
|
||||
|
||||
sol::table gameObjTable = generateView()[GameObject::getGameObjTableName()][id + 1];
|
||||
sol::table offsetPosTable = gameObjTable["hitboxOffset"];
|
||||
|
||||
hitbox = new Node(Vector3(offsetPosTable["x"], offsetPosTable["y"], offsetPosTable["z"]));
|
||||
hitbox->attachMesh(box);
|
||||
hitbox->setVisible(Game::getSingleton()->isDebug());
|
||||
model->attachChild(hitbox);
|
||||
}
|
||||
|
||||
void GameObject::destroyHitbox(){
|
||||
model->dettachChild(hitbox);
|
||||
delete hitbox;
|
||||
hitbox = nullptr;
|
||||
}
|
||||
|
||||
//TODO use a vector for the color nodes
|
||||
void GameObject::useColor(Material *colorMat){
|
||||
if(hitbox) model->dettachChild(hitbox);
|
||||
model->setMaterial(model->getMaterial());
|
||||
if(hitbox) model->attachChild(hitbox);
|
||||
|
||||
sol::table gameObjTable = generateView()[GameObject::getGameObjTableName()][id + 1];
|
||||
sol::table colNodeTbl = gameObjTable["colorNodes"];
|
||||
int numColorNodes = colNodeTbl.size();
|
||||
|
||||
for(int i = 0; i < numColorNodes; i++){
|
||||
string name = colNodeTbl[i + 1];
|
||||
Node *node = model->findDescendant(name, true);
|
||||
|
||||
if(!node) continue;
|
||||
|
||||
vector<Mesh*> meshes = node->getMeshes();
|
||||
|
||||
for(Mesh *mesh : meshes)
|
||||
mesh->setMaterial(colorMat);
|
||||
}
|
||||
}
|
||||
|
||||
void GameObject::initProperties(){
|
||||
sol::table objTable = generateView()[GameObject::getGameObjTableName()][id + 1];
|
||||
sol::optional<float> maxUnevOpt = objTable["maxUnevenness"];
|
||||
|
||||
if(maxUnevOpt != sol::nullopt) maxUnevenness = objTable["maxUnevenness"];
|
||||
|
||||
sol::table sizeTable = objTable["size"];
|
||||
width = sizeTable["x"];
|
||||
height = sizeTable["y"];
|
||||
length = sizeTable["z"];
|
||||
}
|
||||
|
||||
void GameObject::destroyModel(){
|
||||
if(model->getMaterial())
|
||||
delete model->getMaterial();
|
||||
|
||||
Root::getSingleton()->getRootNode()->dettachChild(model);
|
||||
delete model;
|
||||
}
|
||||
|
||||
//TODO improve DEFAULT_TEXTURE handling
|
||||
void GameObject::initModel(bool textured){
|
||||
sol::table gameObjTable = generateView()[GameObject::getGameObjTableName()][id + 1];
|
||||
string basePath = gameObjTable["basePath"], meshPath = gameObjTable["meshPath"];
|
||||
model = new Model(basePath + meshPath);
|
||||
|
||||
Root *root = Root::getSingleton();
|
||||
Material *mat = new Material(root->getLibPath() + "texture");
|
||||
|
||||
if(textured){
|
||||
string albedoPath = gameObjTable["albedoPath"].get_or(configData::DEFAULT_TEXTURE);
|
||||
string f[]{albedoPath == configData::DEFAULT_TEXTURE ? GameManager::getSingleton()->getPath() + albedoPath : basePath + albedoPath};
|
||||
Texture *diffuseTexture = new Texture(f, 1, false);
|
||||
|
||||
mat->addBoolUniform("texturingEnabled", true);
|
||||
mat->addBoolUniform("lightingEnabled", true);
|
||||
mat->addBoolUniform("constLightingEnabled", false);
|
||||
mat->addTexUniform("textures[0]", diffuseTexture, true);
|
||||
}
|
||||
else{
|
||||
mat->addBoolUniform("texturingEnabled", false);
|
||||
mat->addBoolUniform("lightingEnabled", false);
|
||||
mat->addVec4Uniform("diffuseColor", Vector4::VEC_ZERO);
|
||||
model->setWireframe(true);
|
||||
}
|
||||
|
||||
model->setMaterial(mat);
|
||||
sol::optional<sol::table> colNodeOpt = gameObjTable["colorNodes"];
|
||||
|
||||
if(!(model->isWireframe() || colNodeOpt == sol::nullopt))
|
||||
useColor(player->getColorMaterial());
|
||||
|
||||
root->getRootNode()->attachChild(model);
|
||||
}
|
||||
|
||||
//TODO implement death SFX destruction
|
||||
void GameObject::destroySound(){
|
||||
}
|
||||
|
||||
sf::Sound* GameObject::prepareSfx(sf::SoundBuffer *buffer, string sfxPath){
|
||||
sf::Sound *sfx = nullptr;
|
||||
|
||||
if(buffer->loadFromFile(sfxPath.c_str())){
|
||||
sfx = new sf::Sound(*buffer);
|
||||
sfx->setBuffer(*buffer);
|
||||
}
|
||||
|
||||
return sfx;
|
||||
}
|
||||
|
||||
bool GameObject::pointWithinObj(Vector3 point, float deltaLength, float deltaWidth, bool useHeight, float deltaHeight){
|
||||
Vector3 pointDir = point - pos;
|
||||
bool within = true;
|
||||
|
||||
float forwAngle = std::min(dirVec.getAngleBetween(pointDir.norm()), (-dirVec).getAngleBetween(pointDir.norm()));
|
||||
float forwDist = pointDir.getLength() * cos(forwAngle);
|
||||
within &= (forwDist < .5 * (length + deltaLength));
|
||||
|
||||
float leftAngle = std::min(leftVec.getAngleBetween(pointDir.norm()), (-leftVec).getAngleBetween(pointDir.norm()));
|
||||
float leftDist = pointDir.getLength() * cos(leftAngle);
|
||||
within &= (leftDist < .5 * (width + deltaWidth));
|
||||
|
||||
if(useHeight){
|
||||
float upAngle = std::min(upVec.getAngleBetween(pointDir.norm()), (-upVec).getAngleBetween(pointDir.norm()));
|
||||
float upDist = pointDir.getLength() * cos(upAngle);
|
||||
within &= (upDist < .5 * (height + deltaHeight));
|
||||
}
|
||||
|
||||
return within;
|
||||
}
|
||||
|
||||
//TODO improve for other game objs, too
|
||||
void GameObject::changePlayer(Player *newPlayer){
|
||||
vector<Unit*> &oldPlayerUnits = player->getUnits();
|
||||
int oldId = -1;
|
||||
|
||||
for(int i = 0; i < oldPlayerUnits.size(); i++)
|
||||
if(oldPlayerUnits[i] == (Unit*)this){
|
||||
oldId = i;
|
||||
break;
|
||||
}
|
||||
|
||||
oldPlayerUnits.erase(oldPlayerUnits.begin() + oldId);
|
||||
newPlayer->addUnit((Unit*)this);
|
||||
setPlayer(newPlayer);
|
||||
useColor(newPlayer->getColorMaterial());
|
||||
((Unit*)this)->halt();
|
||||
}
|
||||
|
||||
string GameObject::getGameObjTableName(){
|
||||
switch(type){
|
||||
case GameObject::Type::UNIT:
|
||||
return "units";
|
||||
case GameObject::Type::PROJECTILE:
|
||||
return "projectiles";
|
||||
case GameObject::Type::RESOURCE_DEPOSIT:
|
||||
return "resources";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
#ifndef GAME_OBJECT_H
|
||||
#define GAME_OBJECT_H
|
||||
|
||||
#include <vector.h>
|
||||
#include <quaternion.h>
|
||||
#include <model.h>
|
||||
|
||||
namespace sf{
|
||||
class SoundBuffer;
|
||||
class Sound;
|
||||
}
|
||||
|
||||
namespace battleship{
|
||||
class Player;
|
||||
class Unit;
|
||||
class Destructable;
|
||||
|
||||
class GameObject{
|
||||
public:
|
||||
enum class Type{UNIT, PROJECTILE, RESOURCE_DEPOSIT};
|
||||
|
||||
GameObject(Type, int, Player*, vb01::Vector3, vb01::Quaternion);
|
||||
~GameObject(){}
|
||||
virtual void reinit();
|
||||
virtual void update();
|
||||
virtual void select(){}
|
||||
virtual void placeAt(vb01::Vector3);
|
||||
void orientAt(vb01::Quaternion);
|
||||
std::string getGameObjTableName();
|
||||
static sf::Sound* prepareSfx(sf::SoundBuffer*, std::string);
|
||||
bool pointWithinObj(vb01::Vector3, float = 0, float = 0, bool = false, float = 0);
|
||||
void changePlayer(Player *newPlayer);
|
||||
inline float getMaxUnevenness(){return maxUnevenness;}
|
||||
inline vb01::Vector2 getScreenPos(){return screenPos;}
|
||||
inline vb01::Vector3 getCorner(int i){return corners[i];}
|
||||
inline bool isSelectable(){return selectable;}
|
||||
inline bool isDebuggable(){return debugging;}
|
||||
inline vb01::Vector3 getPos() {return pos;}
|
||||
inline vb01::Quaternion getRot(){return rot;}
|
||||
inline float getWidth() {return width;}
|
||||
inline float getHeight() {return height;}
|
||||
inline float getLength() {return length;}
|
||||
inline vb01::Model* getModel() {return model;}
|
||||
inline void setPlayer(Player *pl){player = pl;}
|
||||
inline Player* getPlayer(){return player;}
|
||||
inline void toggleDebugging(bool d){this->debugging=d;}
|
||||
inline vb01::Vector3 getDirVec() {return dirVec;}
|
||||
inline vb01::Vector3 getLeftVec() {return leftVec;}
|
||||
inline vb01::Vector3 getUpVec() {return upVec;}
|
||||
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();
|
||||
virtual void destroyModel();
|
||||
virtual void initModel(bool = true);
|
||||
virtual void initHitbox();
|
||||
virtual void destroyHitbox();
|
||||
virtual void destroySound();
|
||||
virtual void initSound(){}
|
||||
|
||||
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];
|
||||
vb01::Vector2 screenPos;
|
||||
vb01::Quaternion rot;
|
||||
bool selectable = false, debugging = false, remove = false;
|
||||
float width, height, length, maxUnevenness;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,94 @@
|
||||
#include "gameObjectFactory.h"
|
||||
#include "player.h"
|
||||
#include "factory.h"
|
||||
#include "engineer.h"
|
||||
#include "submarine.h"
|
||||
#include "resourceRover.h"
|
||||
#include "projectile.h"
|
||||
#include "resourceDeposit.h"
|
||||
#include "pointDefense.h"
|
||||
#include "extractor.h"
|
||||
#include "freezer.h"
|
||||
#include "researchStruct.h"
|
||||
#include "missile.h"
|
||||
#include "cruiseMissile.h"
|
||||
#include "iceSheet.h"
|
||||
#include "shell.h"
|
||||
#include "torpedo.h"
|
||||
#include "depthCharge.h"
|
||||
#include "defConfigs.h"
|
||||
|
||||
#include <solUtil.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace battleship{
|
||||
using namespace std;
|
||||
using namespace vb01;
|
||||
using namespace gameBase;
|
||||
|
||||
Unit* GameObjectFactory::createUnit(Player *player, int id, Vector3 pos, Quaternion rot, int buildStatus){
|
||||
sol::state_view SOL_LUA_VIEW = generateView();
|
||||
int unitClass = SOL_LUA_VIEW["units"][id + 1]["unitClass"];
|
||||
bool vehicle = SOL_LUA_VIEW["units"][id + 1]["isVehicle"];
|
||||
|
||||
if(vehicle)
|
||||
switch((UnitClass)unitClass){
|
||||
case UnitClass::ROBO_ENGINEER:
|
||||
case UnitClass::CYBORG_ENGINEER:
|
||||
return new Engineer(player, id, pos, rot, Unit::State::STAND_GROUND);
|
||||
case UnitClass::RESOURCE_ROVER:
|
||||
return new ResourceRover(player, id, pos, rot, Unit::State::STAND_GROUND);
|
||||
case UnitClass::SUBMARINE:
|
||||
case UnitClass::MISSILE_SUBMARINE:
|
||||
return new Submarine(player, id, pos, rot, Unit::State::STAND_GROUND);
|
||||
case UnitClass::FREEZER:
|
||||
return new Freezer(player, id, pos, rot, Unit::State::STAND_GROUND);
|
||||
default:
|
||||
return new Vehicle(player, id, pos, rot, Unit::State::STAND_GROUND);
|
||||
}
|
||||
else
|
||||
switch((UnitClass)unitClass){
|
||||
case UnitClass::LAND_FACTORY:
|
||||
case UnitClass::NAVAL_FACTORY:
|
||||
return new Factory(player, id, pos, rot, buildStatus, Unit::State::STAND_GROUND);
|
||||
case UnitClass::POINT_DEFENSE:
|
||||
return new PointDefense(player, id, pos, rot, buildStatus, Unit::State::STAND_GROUND);
|
||||
case UnitClass::EXTRACTOR:
|
||||
return new Extractor(player, id, pos, rot, buildStatus);
|
||||
case UnitClass::LAB:
|
||||
return new ResearchStruct(player, id, pos, rot, buildStatus);
|
||||
case UnitClass::ICE_SHEET:
|
||||
return new IceSheet(player, id, pos, rot, buildStatus);
|
||||
default:
|
||||
return new Structure(player, id, pos, rot, buildStatus, Unit::State::STAND_GROUND);
|
||||
}
|
||||
}
|
||||
|
||||
Projectile* GameObjectFactory::createProjectile(Unit *unit, int id, Vector3 pos, Quaternion rot){
|
||||
sol::state_view SOL_LUA_VIEW = generateView();
|
||||
int projectileClass = SOL_LUA_VIEW["projectiles"][id + 1]["projectileClass"];
|
||||
|
||||
Order::Target target = unit->getOrder(0).targets[0];
|
||||
Vector3 targetPos = (target.unit ? target.unit->getPos() : target.pos);
|
||||
|
||||
switch((ProjectileClass)projectileClass){
|
||||
case ProjectileClass::SHELL:
|
||||
return new Shell(unit, id, pos, rot);
|
||||
case ProjectileClass::CRUISE_MISSILE:
|
||||
return new CruiseMissile(unit, id, targetPos, pos, rot);
|
||||
case ProjectileClass::MISSILE:
|
||||
return new Missile(unit, id, targetPos, pos, rot);
|
||||
case ProjectileClass::TORPEDO:
|
||||
return new Torpedo(unit, id, pos, rot);
|
||||
case ProjectileClass::DEPTH_CHARGE:
|
||||
return new DepthCharge(unit, id, pos, rot);
|
||||
default:
|
||||
return new Projectile(unit, id, pos, rot);
|
||||
}
|
||||
}
|
||||
|
||||
ResourceDeposit* GameObjectFactory::createResourceDeposit(Player *player, int id, Vector3 pos, Quaternion rot, int initAmmount){
|
||||
return new ResourceDeposit(player, id, pos, rot, initAmmount);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
#ifndef GAME_OBJECT_FACTORY_H
|
||||
#define GAME_OBJECT_FACTORY_H
|
||||
|
||||
#include <vector.h>
|
||||
#include <quaternion.h>
|
||||
|
||||
namespace battleship{
|
||||
class Unit;
|
||||
class Projectile;
|
||||
class ResourceDeposit;
|
||||
class Player;
|
||||
|
||||
class GameObjectFactory{
|
||||
public:
|
||||
enum GameObjectType{UNIT, PROJECTILE, RESOURCE_DEPOSIT};
|
||||
static Unit* createUnit(Player*, int, vb01::Vector3, vb01::Quaternion, int = 0);
|
||||
static Projectile* createProjectile(Unit*, int, vb01::Vector3, vb01::Quaternion);
|
||||
static ResourceDeposit* createResourceDeposit(Player*, int, vb01::Vector3, vb01::Quaternion, int = 0);
|
||||
private:
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,4 @@
|
||||
#include "gameObjectFrame.h"
|
||||
|
||||
namespace battleship{
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
#ifndef GAME_OBJECT_FRAME_H
|
||||
#define GAME_OBJECT_FRAME_H
|
||||
|
||||
#include "gameObject.h"
|
||||
|
||||
#include <vector.h>
|
||||
#include <quaternion.h>
|
||||
|
||||
namespace battleship{
|
||||
struct GameObjectFrame : public GameObject{
|
||||
enum Status{
|
||||
PLACEABLE,
|
||||
BLOCKED_BY_FOG_OF_WAR,
|
||||
BLOCKED_BY_UNIT,
|
||||
BLOCKED_BY_MAP_BOUNDS,
|
||||
BLOCKED_BY_DIFF_TERR,
|
||||
BLOCKED_BY_BUMPY_TERR
|
||||
};
|
||||
|
||||
GameObjectFrame(int i, GameObject::Type t, Player *pl, Unit *ou = nullptr, vb01::Vector3 pos = vb01::Vector3::VEC_ZERO, vb01::Quaternion rot = vb01::Quaternion::QUAT_W) :
|
||||
originalUnit(ou),
|
||||
GameObject(t, i, pl, pos, rot)
|
||||
{
|
||||
initModel(false);
|
||||
initProperties();
|
||||
placeAt(pos);
|
||||
orientAt(rot);
|
||||
}
|
||||
~GameObjectFrame(){}
|
||||
void destroy(){destroyModel();}
|
||||
inline Unit* getOriginalUnit(){return originalUnit;}
|
||||
|
||||
Status status;
|
||||
Unit *originalUnit = nullptr;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,145 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include "pathfinder.h"
|
||||
#include "vehicle.h"
|
||||
|
||||
namespace battleship{
|
||||
using namespace std;
|
||||
using namespace vb01;
|
||||
|
||||
static Pathfinder *pathfinder = nullptr;
|
||||
|
||||
Pathfinder* Pathfinder::getSingleton(){
|
||||
if(!pathfinder)
|
||||
pathfinder = new Pathfinder();
|
||||
|
||||
return pathfinder;
|
||||
}
|
||||
|
||||
vector<float> Pathfinder::calcHeuristics(vector<Map::Cell> &cells, int dest){
|
||||
vector<float> heuristics;
|
||||
|
||||
for(Map::Cell &cell : cells)
|
||||
heuristics.push_back(145 * (cells[dest].pos.getDistanceFrom(cell.pos)));
|
||||
|
||||
return heuristics;
|
||||
}
|
||||
|
||||
vector<int> Pathfinder::findPath(vector<Map::Cell> &cells, vector<float> &heuristics, int source, int dest, int vehicleType){
|
||||
if(heuristics.empty() || (heuristics.size() == 1 && heuristics[0] == 0.0))
|
||||
heuristics = calcHeuristics(cells, dest);
|
||||
|
||||
bool useHeur = !heuristics.empty();
|
||||
|
||||
const int size = cells.size();
|
||||
u32 *distances = new u32[size];
|
||||
vector<int> *paths = new vector<int>[size];
|
||||
vector<pair<int, bool>> cellsByCheck;
|
||||
vector<bool> posMinCellChecked;
|
||||
vector<int> possibleMinCells = vector<int>{source};
|
||||
|
||||
for(int i = 0; i < size; i++){
|
||||
cellsByCheck.push_back(pair(i, false));
|
||||
distances[i] = impassibleNodeVal;
|
||||
posMinCellChecked.push_back(false);
|
||||
}
|
||||
|
||||
paths[source].push_back(source);
|
||||
distances[source] = 0;
|
||||
posMinCellChecked[source] = true;
|
||||
|
||||
int lastVertStrich = -1;
|
||||
|
||||
while(!cellsByCheck[dest].second){
|
||||
int posMinCellId = 0, vertStrich = possibleMinCells[posMinCellId];
|
||||
|
||||
for(int i = 0; i < possibleMinCells.size(); i++){
|
||||
float sum1 = distances[possibleMinCells[i]] + (useHeur ? heuristics[possibleMinCells[i]] : 0);
|
||||
float sum2 = distances[possibleMinCells[posMinCellId]] + (useHeur ? heuristics[possibleMinCells[posMinCellId]] : 0);
|
||||
|
||||
if(sum1 < sum2 || (useHeur && sum1 == sum2 && heuristics[i] < heuristics[vertStrich])){
|
||||
posMinCellId = i;
|
||||
vertStrich = possibleMinCells[i];
|
||||
}
|
||||
}
|
||||
|
||||
if(distances[vertStrich] == impassibleNodeVal){
|
||||
vector<int> path = paths[lastVertStrich];
|
||||
|
||||
delete[] paths;
|
||||
delete[] distances;
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
posMinCellChecked[possibleMinCells[posMinCellId]] = false;
|
||||
possibleMinCells.erase(possibleMinCells.begin() + posMinCellId);
|
||||
|
||||
cellsByCheck[vertStrich].second = true;
|
||||
|
||||
int numEdges = cells[vertStrich].edges.size();
|
||||
|
||||
for(int i = 0; i < numEdges; i++){
|
||||
int edgeNode = cells[vertStrich].edges[i].destCellId;
|
||||
|
||||
if(cellsByCheck[edgeNode].second) continue;
|
||||
|
||||
if(!posMinCellChecked[edgeNode]){
|
||||
posMinCellChecked[edgeNode] = true;
|
||||
possibleMinCells.push_back(edgeNode);
|
||||
}
|
||||
|
||||
UnitType ut = (UnitType)vehicleType;
|
||||
Map::Cell::Type ct = cells[edgeNode].type;
|
||||
bool ship = (ut == UnitType::UNDERWATER || ut == UnitType::SEA_LEVEL);
|
||||
int weightMult = 1;
|
||||
|
||||
if((ut == UnitType::LAND && ct == Map::Cell::WATER) || (ship && ct == Map::Cell::LAND))
|
||||
weightMult = 10;
|
||||
/*
|
||||
if(vehicleType != -1){
|
||||
UnitType unitType = vehicle->getType();
|
||||
bool ship = (unitType == UnitType::UNDERWATER || unitType == UnitType::SEA_LEVEL);
|
||||
Unit *blockingUnit = cells[vertStrich].blockedBy;
|
||||
bool diffBlockingUnit = (blockingUnit && blockingUnit != vehicle);
|
||||
bool throughBlockedCell = (source != vertStrich);
|
||||
|
||||
if(
|
||||
(unitType == UnitType::LAND && ((diffBlockingUnit && throughBlockedCell) || cells[vertStrich].type != Map::Cell::LAND)) ||
|
||||
(
|
||||
ship &&
|
||||
(
|
||||
cells[vertStrich].type != Map::Cell::WATER ||
|
||||
(
|
||||
diffBlockingUnit &&
|
||||
throughBlockedCell &&
|
||||
blockingUnit->getUnitClass() == UnitClass::ICE_SHEET &&
|
||||
vehicle->getUnitClass() != UnitClass::ICEBREAKER
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
if(distances[vertStrich] + weightMult * cells[vertStrich].edges[i].weight < distances[edgeNode]){
|
||||
distances[edgeNode] = distances[vertStrich] + weightMult * cells[vertStrich].edges[i].weight;
|
||||
paths[edgeNode] = paths[vertStrich];
|
||||
paths[edgeNode].push_back(edgeNode);
|
||||
}
|
||||
}
|
||||
|
||||
lastVertStrich = vertStrich;
|
||||
}
|
||||
|
||||
vector<int> path = paths[dest];
|
||||
|
||||
delete[] paths;
|
||||
delete[] distances;
|
||||
|
||||
return path;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
#ifndef PATHFINDER_H
|
||||
#define PATHFINDER_H
|
||||
|
||||
#include "map.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <util.h>
|
||||
|
||||
namespace battleship{
|
||||
class Vehicle;
|
||||
|
||||
class Pathfinder{
|
||||
public:
|
||||
static Pathfinder* getSingleton();
|
||||
std::vector<float> calcHeuristics(std::vector<Map::Cell>&, int);
|
||||
std::vector<int> findPath(std::vector<Map::Cell>&, std::vector<float>&, int, int, int = -1);
|
||||
inline vb01::u32 getImpassibleNodeVal(){return impassibleNodeVal;}
|
||||
inline void setImpassibleNodeVal(vb01::u32 val){this->impassibleNodeVal = val;}
|
||||
private:
|
||||
Pathfinder(){}
|
||||
|
||||
vb01::u32 impassibleNodeVal;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,81 @@
|
||||
#include "cruiseMissile.h"
|
||||
#include "destructable.h"
|
||||
#include "player.h"
|
||||
#include "unit.h"
|
||||
#include "map.h"
|
||||
#include "game.h"
|
||||
|
||||
#include <util.h>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
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)
|
||||
{
|
||||
destructable = new Destructable(this);
|
||||
|
||||
Vector3 unitDir = unit->getDirVec();
|
||||
Vector3 leftDir = unit->getLeftVec();
|
||||
Vector3 targDir = (Vector3(targetPoint.x, pos.y, targetPoint.z) - pos).norm();
|
||||
|
||||
bool left = (leftDir.getAngleBetween(targDir) < PI / 2);
|
||||
float angle = unitDir.getAngleBetween(targDir) * (left ? 1 : -1);
|
||||
orientAt(Quaternion(angle, Vector3::VEC_J) * rot);
|
||||
}
|
||||
|
||||
CruiseMissile::~CruiseMissile(){delete destructable;}
|
||||
|
||||
void CruiseMissile::pitch(float rotAngle, Vector3 compVec){
|
||||
float minHeight = 20;
|
||||
float angleToCompVec = Projectile::dirVec.getAngleBetween(compVec);
|
||||
float angle = (angleToCompVec > rotAngle ? rotAngle : angleToCompVec);
|
||||
|
||||
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(Projectile::dirVec.getAngleBetween(targDir) < PI / 2)
|
||||
Projectile::orientAt(Quaternion(angle, Projectile::leftVec) * Projectile::rot);
|
||||
}
|
||||
}
|
||||
|
||||
void CruiseMissile::cruise(){
|
||||
float minDist = 6;
|
||||
float initDist = Vector3(targetPoint.x, initPos.y, targetPoint.z).getDistanceFrom(initPos);
|
||||
|
||||
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(Projectile::dirVec.x, 0, Projectile::dirVec.z).norm());
|
||||
break;
|
||||
case FlightStage::DESCENT:
|
||||
pitch(rotAngle, -Vector3::VEC_J);
|
||||
break;
|
||||
case FlightStage::CRUISE:
|
||||
cruise();
|
||||
break;
|
||||
}
|
||||
|
||||
if(flightStage == FlightStage::DESCENT && !remove){
|
||||
checkSurfaceCollision(false);
|
||||
if(remove) return;
|
||||
checkUnitCollision();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#ifndef CRUISE_MISSILE_H
|
||||
#define CRUISE_MISSILE_H
|
||||
|
||||
#include "projectile.h"
|
||||
|
||||
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};
|
||||
FlightStage flightStage;
|
||||
vb01::Vector3 targetPoint;
|
||||
|
||||
void pitch(float, vb01::Vector3);
|
||||
void cruise();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,17 @@
|
||||
#include "depthCharge.h"
|
||||
|
||||
namespace battleship{
|
||||
using namespace vb01;
|
||||
|
||||
DepthCharge::DepthCharge(Unit *un, int id, Vector3 pos, Quaternion rot) : Projectile(un, id, pos, rot){}
|
||||
|
||||
void DepthCharge::update(){
|
||||
Projectile::update();
|
||||
|
||||
if(!remove){
|
||||
checkSurfaceCollision(true);
|
||||
if(remove) return;
|
||||
checkUnitCollision();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#ifndef DEPTH_CHARGE_H
|
||||
#define DEPTH_CHARGE_H
|
||||
|
||||
#include "projectile.h"
|
||||
|
||||
namespace battleship{
|
||||
class DepthCharge : public Projectile{
|
||||
public:
|
||||
DepthCharge(Unit*, int, vb01::Vector3, vb01::Quaternion);
|
||||
void update();
|
||||
private:
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,32 @@
|
||||
#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)
|
||||
{
|
||||
destructable = new Destructable(this);
|
||||
}
|
||||
|
||||
Missile::~Missile(){delete destructable;}
|
||||
|
||||
void Missile::update(){
|
||||
Vector3 targDir = (targetPos - Projectile::pos).norm();
|
||||
float angle = targDir.getAngleBetween(Projectile::dirVec);
|
||||
float ra = (rotAngle < angle ? rotAngle : angle);
|
||||
orientAt(Quaternion(ra, Projectile::dirVec.cross(targDir)) * Projectile::rot);
|
||||
|
||||
Projectile::update();
|
||||
destructable->update();
|
||||
|
||||
if(!remove){
|
||||
checkSurfaceCollision(false);
|
||||
if(remove) return;
|
||||
checkUnitCollision();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#ifndef MISSILE_H
|
||||
#define MISSILE_H
|
||||
|
||||
#include "projectile.h"
|
||||
|
||||
namespace battleship{
|
||||
class Missile : public Projectile{
|
||||
public:
|
||||
Missile(Unit*, int, vb01::Vector3, vb01::Vector3, vb01::Quaternion);
|
||||
~Missile();
|
||||
void update();
|
||||
private:
|
||||
vb01::Vector3 targetPos;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,131 @@
|
||||
#include <node.h>
|
||||
#include <model.h>
|
||||
#include <material.h>
|
||||
#include <quaternion.h>
|
||||
#include <particleEmitter.h>
|
||||
|
||||
#include <stateManager.h>
|
||||
|
||||
#include "game.h"
|
||||
#include "unit.h"
|
||||
#include "util.h"
|
||||
#include "player.h"
|
||||
#include "environment.h"
|
||||
#include "projectile.h"
|
||||
#include "defConfigs.h"
|
||||
#include "destructable.h"
|
||||
#include "resourceDeposit.h"
|
||||
#include "inGameAppState.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace vb01;
|
||||
|
||||
namespace battleship{
|
||||
using namespace vb01;
|
||||
using namespace configData;
|
||||
using namespace gameBase;
|
||||
|
||||
Projectile::Projectile(Unit *un, int id, Vector3 pos, Quaternion rot) : GameObject(GameObject::Type::PROJECTILE, id, un->getPlayer(), pos, rot), unit(un), initPos(pos){
|
||||
initProperties();
|
||||
initModel();
|
||||
initSound();
|
||||
placeAt(pos);
|
||||
orientAt(rot);
|
||||
}
|
||||
|
||||
Projectile::~Projectile(){
|
||||
destroySound();
|
||||
destroyModel();
|
||||
}
|
||||
|
||||
void Projectile::reinit(){
|
||||
destroySound();
|
||||
destroyModel();
|
||||
|
||||
initProperties();
|
||||
|
||||
initModel();
|
||||
|
||||
GameObject::reinit();
|
||||
}
|
||||
|
||||
void Projectile::initProperties(){
|
||||
GameObject::initProperties();
|
||||
Game *game = Game::getSingleton();
|
||||
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);
|
||||
|
||||
string explKey = "explosion";
|
||||
explosionDamage = projTable[explKey]["damage"]; explosionDamage += game->calcAbilFromTech(Ability::Type::EXPLOSION_DAMAGE, currTechs, (int)GameObject::type, id);
|
||||
explosionRadius = projTable[explKey]["radius"]; explosionRadius += game->calcAbilFromTech(Ability::Type::EXPLOSION_RADIUS, currTechs, (int)GameObject::type, id);
|
||||
speed = projTable["speed"];
|
||||
rotAngle = projTable["rotAngle"].get_or(0.0);
|
||||
}
|
||||
|
||||
void Projectile::update() {
|
||||
GameObject::update();
|
||||
placeAt(pos + speed * dirVec);
|
||||
}
|
||||
|
||||
void Projectile::detonate(Unit *target){
|
||||
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);
|
||||
Environment::explode(fx, (Environment::Detonation)tbl["detonation"], pos, tbl["damage"], tbl["radius"]);
|
||||
|
||||
remove = true;
|
||||
}
|
||||
|
||||
void Projectile::checkUnitCollision(){
|
||||
vector<Player*> players = Game::getSingleton()->getPlayers(true);
|
||||
vector<Unit*> targetUnits;
|
||||
vector<Node*> targetNodes;
|
||||
|
||||
for(Player *pl : players){
|
||||
vector<Unit*> units = pl->getUnits();
|
||||
|
||||
for(Unit *u : units)
|
||||
if(unit && unit != u){
|
||||
targetUnits.push_back(u);
|
||||
targetNodes.push_back(u->getHitbox());
|
||||
}
|
||||
}
|
||||
|
||||
vector<RayCaster::CollisionResult> results = RayCaster::cast(pos, dirVec, targetNodes, rayLength);
|
||||
|
||||
if(!results.empty())
|
||||
for(int i = 0; i < targetNodes.size(); i++)
|
||||
if(targetNodes[i]->getMesh(0) == results[0].mesh)
|
||||
detonate(targetUnits[i]);
|
||||
}
|
||||
|
||||
//TODO fix map boundary checks
|
||||
void Projectile::checkSurfaceCollision(bool useBottomCell){
|
||||
Map *map = Map::getSingleton();
|
||||
vector<Map::Cell> &cells = map->getCells();
|
||||
int cellId = map->getCellId(pos, false);
|
||||
Vector3 mapSize = map->getMapSize();
|
||||
|
||||
if(cellId < 0 || fabs(pos.x) > .5 * mapSize.x || fabs(pos.z) > .5 * mapSize.z){
|
||||
remove = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if(useBottomCell && !cells[cellId].underWaterCellIds.empty()){
|
||||
int numUnderwaterCells = cells[cellId].underWaterCellIds.size();
|
||||
cellId = cells[cellId].underWaterCellIds[numUnderwaterCells - 1];
|
||||
}
|
||||
|
||||
if((pos + dirVec * rayLength).y <= cells[cellId].pos.y + .5 * map->getCellSize().y)
|
||||
detonate();
|
||||
}
|
||||
|
||||
void Projectile::debug(){
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
#ifndef PROJECTILE_H
|
||||
#define PROJECTILE_H
|
||||
|
||||
#include "gameObject.h"
|
||||
#include "fxManager.h"
|
||||
|
||||
#include <SFML/Audio.hpp>
|
||||
|
||||
namespace vb01{
|
||||
class Node;
|
||||
}
|
||||
|
||||
namespace battleship {
|
||||
class Unit;
|
||||
|
||||
enum class ProjectileClass{SHELL, CRUISE_MISSILE, MISSILE, TORPEDO, DEPTH_CHARGE};
|
||||
|
||||
class Projectile : public GameObject{
|
||||
public:
|
||||
Projectile(Unit*, int, vb01::Vector3, vb01::Quaternion);
|
||||
virtual ~Projectile();
|
||||
virtual void update();
|
||||
virtual void debug();
|
||||
inline ProjectileClass getProjectileClass(){return projClass;}
|
||||
private:
|
||||
void initProperties();
|
||||
void detonate(Unit *u = nullptr);
|
||||
protected:
|
||||
virtual void reinit();
|
||||
virtual void checkUnitCollision();
|
||||
virtual void checkSurfaceCollision(bool);
|
||||
|
||||
vb01::Vector3 initPos;
|
||||
ProjectileClass projClass;
|
||||
Unit *unit = nullptr;
|
||||
FxManager::Fx *explosionFx = nullptr;
|
||||
float speed, rayLength, explosionRadius, rotAngle;
|
||||
int directHitDamage, explosionDamage;
|
||||
sf::SoundBuffer *shotSfxBuffer, *explosionSfxBuffer;
|
||||
sf::Sound *shotSfx = nullptr, *explosionSfx = nullptr;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,42 @@
|
||||
#include "shell.h"
|
||||
|
||||
#include <solUtil.h>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace battleship{
|
||||
using namespace std;
|
||||
using namespace vb01;
|
||||
using namespace gameBase;
|
||||
|
||||
Shell::Shell(Unit *un, int id, Vector3 pos, Quaternion rot) :
|
||||
Projectile(un, id, pos, rot),
|
||||
initTime(getTime()),
|
||||
initDir(dirVec) {}
|
||||
|
||||
void Shell::update(){
|
||||
float currTime = float(getTime() - initTime) / 1000;
|
||||
|
||||
if(currTime == 0) return;
|
||||
|
||||
const float G = generateView()["G"];
|
||||
float angle = initDir.getAngleBetween(Vector3(initDir.x, 0, initDir.z).norm());
|
||||
|
||||
dirVec = (
|
||||
pos +
|
||||
speed * currTime * cos(angle) * Vector3(initDir.x, 0, initDir.z).norm() +
|
||||
(currTime * speed * sin(angle) - G * currTime * currTime) * Vector3::VEC_J -
|
||||
pos
|
||||
).norm();
|
||||
upVec = Quaternion(-PI / 2, leftVec) * dirVec;
|
||||
model->lookAt(dirVec, upVec);
|
||||
|
||||
Projectile::update();
|
||||
|
||||
if(!remove){
|
||||
checkSurfaceCollision(false);
|
||||
if(remove) return;
|
||||
checkUnitCollision();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#ifndef SHELL_H
|
||||
#define SHELL_H
|
||||
|
||||
#include "projectile.h"
|
||||
|
||||
#include <util.h>
|
||||
|
||||
namespace battleship{
|
||||
class Shell : public Projectile{
|
||||
public:
|
||||
Shell(Unit*, int, vb01::Vector3, vb01::Quaternion);
|
||||
void update();
|
||||
private:
|
||||
vb01::s64 initTime;
|
||||
vb01::Vector3 initDir;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,17 @@
|
||||
#include "torpedo.h"
|
||||
|
||||
namespace battleship{
|
||||
using namespace vb01;
|
||||
|
||||
Torpedo::Torpedo(Unit *un, int id, Vector3 pos, Quaternion rot) : Projectile(un, id, pos, rot){}
|
||||
|
||||
void Torpedo::update(){
|
||||
Projectile::update();
|
||||
|
||||
if(!remove){
|
||||
checkSurfaceCollision(true);
|
||||
if(remove) return;
|
||||
checkUnitCollision();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#ifndef TORPEDO_H
|
||||
#define TORPEDO_H
|
||||
|
||||
#include "projectile.h"
|
||||
|
||||
namespace battleship{
|
||||
class Torpedo : public Projectile{
|
||||
public:
|
||||
Torpedo(Unit*, int, vb01::Vector3, vb01::Quaternion);
|
||||
void update();
|
||||
private:
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,34 @@
|
||||
#include "resourceDeposit.h"
|
||||
|
||||
namespace battleship{
|
||||
using namespace vb01;
|
||||
|
||||
ResourceDeposit::ResourceDeposit(Player *player, int id, Vector3 pos, Quaternion rot, int ia) :
|
||||
GameObject(GameObject::Type::RESOURCE_DEPOSIT, id, player, pos, rot),
|
||||
initAmmount(ia),
|
||||
ammount(ia)
|
||||
{
|
||||
initProperties();
|
||||
initModel();
|
||||
initHitbox();
|
||||
placeAt(pos);
|
||||
orientAt(rot);
|
||||
}
|
||||
|
||||
ResourceDeposit::~ResourceDeposit(){
|
||||
destroyHitbox();
|
||||
destroyModel();
|
||||
}
|
||||
|
||||
void ResourceDeposit::reinit(){
|
||||
destroyHitbox();
|
||||
destroyModel();
|
||||
|
||||
initProperties();
|
||||
|
||||
initModel();
|
||||
initHitbox();
|
||||
|
||||
GameObject::reinit();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#ifndef RESOURCE_DEPOSIT_H
|
||||
#define RESOURCE_DEPOSIT_H
|
||||
|
||||
#include "gameObject.h"
|
||||
|
||||
namespace battleship{
|
||||
class Extractor;
|
||||
|
||||
class ResourceDeposit : public GameObject{
|
||||
public:
|
||||
ResourceDeposit(Player*, int, vb01::Vector3, vb01::Quaternion, int);
|
||||
~ResourceDeposit();
|
||||
inline int getAmmount(){return ammount;}
|
||||
inline int getInitAmmount(){return initAmmount;}
|
||||
inline void decreaseAmmount(int amnt){ammount -= amnt;}
|
||||
inline Extractor* getExtractor(){return extractor;}
|
||||
inline void setExtractor(Extractor *e){this->extractor = e;}
|
||||
private:
|
||||
int ammount, initAmmount;
|
||||
Extractor *extractor = nullptr;
|
||||
|
||||
void reinit();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,32 @@
|
||||
#ifndef ABILITY_H
|
||||
#define ABILITY_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace battleship{
|
||||
struct Ability{
|
||||
enum class Type{
|
||||
SPEED,
|
||||
HEALTH,
|
||||
LINE_OF_SIGHT,
|
||||
MAX_TURN_ANGLE,
|
||||
DIRECT_HIT_DAMAGE,
|
||||
EXPLOSION_RADIUS,
|
||||
EXPLOSION_DAMAGE,
|
||||
CAPACITY,
|
||||
LOAD_RATE,
|
||||
LOAD_SPEED,
|
||||
DRAW_RATE,
|
||||
DRAW_SPEED,
|
||||
HACK_RANGE,
|
||||
UNIT_UNLOCK
|
||||
};
|
||||
|
||||
Type type;
|
||||
float ammount;
|
||||
int gameObjType;
|
||||
std::vector<int> gameObjIds;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,13 @@
|
||||
#ifndef BUILDABLE_UNIT_H
|
||||
#define BUILDABLE_UNIT_H
|
||||
|
||||
namespace battleship{
|
||||
struct BuildableUnit{
|
||||
int id;
|
||||
bool buildable;
|
||||
|
||||
BuildableUnit(int i, bool build) : id(i), buildable(build){}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,23 @@
|
||||
#include "garrisonable.h"
|
||||
#include "unit.h"
|
||||
|
||||
#include <node.h>
|
||||
|
||||
namespace battleship{
|
||||
using namespace vb01;
|
||||
|
||||
void Garrisonable::update(){
|
||||
}
|
||||
|
||||
void Garrisonable::ejectVehicle(int id){
|
||||
}
|
||||
|
||||
void Garrisonable::prepareGarrisonSlots(){
|
||||
for(int i = 0; i < capacity; i++){
|
||||
Vector2 size = 10 * Vector2::VEC_IJ;
|
||||
Vector2 pos = Vector2(0, 10 * (i));
|
||||
garrisonSlotBackgrounds.push_back(Unit::createBar(pos, size, Vector4(0, 0, 0, 1)));
|
||||
garrisonSlotForegrounds.push_back(Unit::createBar(pos, size, Vector4(0, 1, 0, 1)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
#ifndef GARRISONABLE_H
|
||||
#define GARRISONABLE_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "unit.h"
|
||||
|
||||
namespace vb01{
|
||||
class Node;
|
||||
}
|
||||
|
||||
namespace battleship{
|
||||
class Vehicle;
|
||||
|
||||
class Garrisonable{
|
||||
public:
|
||||
Garrisonable(){}
|
||||
~Garrisonable(){}
|
||||
void update();
|
||||
void ejectVehicle(int);
|
||||
protected:
|
||||
int capacity;
|
||||
std::vector<Vehicle*> garrisonedVehicles;
|
||||
std::vector<vb01::Node*> garrisonSlotForegrounds, garrisonSlotBackgrounds;
|
||||
|
||||
void prepareGarrisonSlots();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,70 @@
|
||||
#include "extractor.h"
|
||||
#include "player.h"
|
||||
#include "game.h"
|
||||
#include "destructable.h"
|
||||
#include "activeGameState.h"
|
||||
#include "resourceDeposit.h"
|
||||
|
||||
#include <stateManager.h>
|
||||
|
||||
namespace battleship{
|
||||
using namespace std;
|
||||
using namespace vb01;
|
||||
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){
|
||||
Vector2 size = Vector2(lenHpBar, 10);
|
||||
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;
|
||||
|
||||
initProperties();
|
||||
|
||||
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);
|
||||
|
||||
destructable->removeBar(ammountForeground);
|
||||
destructable->removeBar(ammountBackground);
|
||||
}
|
||||
|
||||
void Extractor::initProperties(){
|
||||
Game *game = Game::getSingleton();
|
||||
vector<int> currTechs = player->getTechnologies();
|
||||
|
||||
sol::table unitTable = generateView()["units"][id + 1];
|
||||
drawRate = unitTable["drawRate"]; drawRate += game->calcAbilFromTech(Ability::Type::DRAW_RATE, currTechs, (int)GameObject::type, id);
|
||||
drawSpeed = unitTable["drawSpeed"]; drawSpeed += game->calcAbilFromTech(Ability::Type::DRAW_SPEED, currTechs, (int)GameObject::type, id);
|
||||
}
|
||||
|
||||
void Extractor::update(){
|
||||
Structure::update();
|
||||
|
||||
ActiveGameState *activeState = (ActiveGameState*)GameManager::getSingleton()->getStateManager()->getAppStateByType(AppStateType::ACTIVE_STATE);
|
||||
Player *mainPlayer = (activeState ? activeState->getPlayer() : nullptr);
|
||||
|
||||
vector<Player*> selectingPlayers = getSelectingPlayers();
|
||||
bool mainPlayerSelecting = (activeState && find(selectingPlayers.begin(), selectingPlayers.end(), mainPlayer) != selectingPlayers.end());
|
||||
int ammount = 0, initAmmount = 0;
|
||||
|
||||
if(deposit){
|
||||
ammount = deposit->getAmmount();
|
||||
initAmmount = deposit->getInitAmmount();
|
||||
}
|
||||
|
||||
destructable->displayStats(ammountForeground, ammountBackground, ammount, initAmmount, mainPlayer == player && mainPlayerSelecting, Vector2(0, -10));
|
||||
}
|
||||
|
||||
void Extractor::draw(){
|
||||
deposit->decreaseAmmount(drawSpeed);
|
||||
lastDrawTime = getTime();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
#ifndef EXTRACTOR_H
|
||||
#define EXTRACTOR_H
|
||||
|
||||
#include "structure.h"
|
||||
|
||||
#include <util.h>
|
||||
|
||||
namespace battleship{
|
||||
class ResourceDeposit;
|
||||
|
||||
class Extractor : public Structure{
|
||||
public:
|
||||
Extractor(Player*, int, vb01::Vector3, vb01::Quaternion, int, ResourceDeposit *rd = nullptr, Unit::State = Unit::State::STAND_GROUND);
|
||||
~Extractor();
|
||||
void update();
|
||||
void draw();
|
||||
bool canDraw(){return vb01::getTime() - lastDrawTime > drawRate;}
|
||||
inline ResourceDeposit* getDeposit(){return deposit;}
|
||||
private:
|
||||
void initProperties();
|
||||
|
||||
int drawSpeed, drawRate;
|
||||
vb01::s64 lastDrawTime = 0;
|
||||
vb01::Node *ammountBackground = nullptr, *ammountForeground = nullptr;
|
||||
ResourceDeposit *deposit = nullptr;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,82 @@
|
||||
#include "factory.h"
|
||||
#include "player.h"
|
||||
#include "game.h"
|
||||
#include "destructable.h"
|
||||
#include "gameObjectFactory.h"
|
||||
#include "activeGameState.h"
|
||||
|
||||
#include <stateManager.h>
|
||||
#include <solUtil.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace battleship{
|
||||
using namespace vb01;
|
||||
using namespace std;
|
||||
using namespace gameBase;
|
||||
|
||||
Factory::Factory(Player *player, int id, Vector3 pos, Quaternion rot, int buildStatus, Unit::State state) : Structure(player, id, pos, rot, buildStatus, state), rallyPoint(pos + 30 * dirVec){}
|
||||
|
||||
void Factory::update(){
|
||||
Structure::update();
|
||||
|
||||
if(!isComplete()) return;
|
||||
|
||||
if(!unitQueue.empty()) train();
|
||||
}
|
||||
|
||||
//TODO replace repetetive string literals
|
||||
void Factory::initProperties(){
|
||||
Structure::initProperties();
|
||||
}
|
||||
|
||||
int Factory::getNumQueueUnitsById(int unitId){
|
||||
int numUnits = 0;
|
||||
|
||||
for(int qu : unitQueue)
|
||||
if(qu == unitId)
|
||||
numUnits++;
|
||||
|
||||
return numUnits;
|
||||
}
|
||||
|
||||
void Factory::appendToQueue(int buId){
|
||||
if(buId < buildableUnits.size() && buildableUnits[buId].buildable)
|
||||
unitQueue.push_back(buildableUnits[buId].id);
|
||||
}
|
||||
|
||||
void Factory::train(){
|
||||
bool training = !unitQueue.empty();
|
||||
buildStatusForeground->setVisible(training);
|
||||
buildStatusBackground->setVisible(training);
|
||||
|
||||
if(training){
|
||||
ActiveGameState *activeState = (ActiveGameState*)GameManager::getSingleton()->getStateManager()->getAppStateByType(AppStateType::ACTIVE_STATE);
|
||||
Player *mainPlayer = (activeState ? activeState->getPlayer() : nullptr);
|
||||
|
||||
vector<Player*> selectingPlayers = getSelectingPlayers();
|
||||
bool mainPlayerSelecting = (activeState && find(selectingPlayers.begin(), selectingPlayers.end(), mainPlayer) != selectingPlayers.end());
|
||||
|
||||
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;
|
||||
|
||||
if(player->getResource(ResourceType::REFINEDS) >= costRate && getTime() - lastTrainTime > trainRate){
|
||||
trainingStatus++;
|
||||
player->updateResource(ResourceType::REFINEDS, -costRate, true);
|
||||
lastTrainTime = getTime();
|
||||
}
|
||||
|
||||
if(trainingStatus >= 100){
|
||||
Unit *unit = GameObjectFactory::createUnit(player, unitQueue[0], pos, rot);
|
||||
player->addUnit(unit);
|
||||
unit->receiveOrder(Order(Order::TYPE::MOVE, vector<Order::Target>{Order::Target(nullptr, rallyPoint)}, Vector3::VEC_ZERO), false);
|
||||
|
||||
unitQueue.erase(unitQueue.begin());
|
||||
trainingStatus = 0;
|
||||
|
||||
player->incVehiclesBuilt();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
#ifndef FACTORY_H
|
||||
#define FACTORY_H
|
||||
|
||||
#include "structure.h"
|
||||
|
||||
#include <vector>
|
||||
#include <util.h>
|
||||
|
||||
namespace vb01{
|
||||
class Node;
|
||||
}
|
||||
|
||||
namespace battleship{
|
||||
class Player;
|
||||
|
||||
class Factory : public Structure{
|
||||
public:
|
||||
Factory(Player*, int, vb01::Vector3, vb01::Quaternion, int = 0, Unit::State = Unit::State::STAND_GROUND);
|
||||
~Factory(){}
|
||||
void update();
|
||||
int getNumQueueUnitsById(int);
|
||||
void appendToQueue(int);
|
||||
inline void setRallyPoint(vb01::Vector3 rp){this->rallyPoint = rp;}
|
||||
inline vb01::Vector3 getRallyPoint(){return rallyPoint;}
|
||||
inline std::vector<int> getQueue(){return unitQueue;}
|
||||
private:
|
||||
std::vector<int> unitQueue;
|
||||
int maxLenQueue, trainingStatus = 0;
|
||||
vb01::s64 lastTrainTime = 0;
|
||||
vb01::Vector3 rallyPoint;
|
||||
|
||||
void initProperties();
|
||||
void train();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,27 @@
|
||||
#include "iceSheet.h"
|
||||
#include "player.h"
|
||||
#include "game.h"
|
||||
|
||||
namespace battleship{
|
||||
using namespace vb01;
|
||||
using namespace std;
|
||||
|
||||
IceSheet::IceSheet(Player *player, int id, Vector3 pos, Quaternion rot, int bldSt) : Structure(player, id, pos, rot, bldSt, Unit::State::STAND_GROUND){}
|
||||
|
||||
void IceSheet::update(){
|
||||
Structure::update();
|
||||
|
||||
if(buildStatus < 100)
|
||||
model->getChild(0)->setScale(.01 * buildStatus * Vector3::VEC_IJK);
|
||||
|
||||
for(Player *pl : Game::getSingleton()->getPlayers(true)){
|
||||
vector<Unit*> icebreakers = pl->getUnitsByClass(UnitClass::ICEBREAKER);
|
||||
|
||||
for(Unit *icebreaker : icebreakers)
|
||||
if(icebreaker->pointWithinObj(pos)){
|
||||
player->removeUnit(this);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#ifndef ICE_SHEET_H
|
||||
#define ICE_SHEET_H
|
||||
|
||||
#include "structure.h"
|
||||
|
||||
namespace battleship{
|
||||
class IceSheet : public Structure{
|
||||
public:
|
||||
IceSheet(Player*, int, vb01::Vector3, vb01::Quaternion, int);
|
||||
void update();
|
||||
private:
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,17 @@
|
||||
#include "pointDefense.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace battleship{
|
||||
using namespace vb01;
|
||||
using namespace std;
|
||||
using namespace gameBase;
|
||||
|
||||
PointDefense::PointDefense(Player *player, int id, Vector3 pos, Quaternion rot, int buildStatus, Unit::State state) : Structure(player, id, pos, rot, buildStatus, state){}
|
||||
|
||||
void PointDefense::attack(Order order){
|
||||
if(!isComplete()) return;
|
||||
|
||||
Unit::attack(order);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#ifndef POINT_DEFENSE_H
|
||||
#define POINT_DEFENSE_H
|
||||
|
||||
#include "structure.h"
|
||||
|
||||
namespace battleship{
|
||||
class PointDefense : public Structure{
|
||||
public:
|
||||
PointDefense(Player*, int, vb01::Vector3, vb01::Quaternion, int, Unit::State);
|
||||
private:
|
||||
void attack(Order);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,68 @@
|
||||
#include "researchStruct.h"
|
||||
#include "activeGameState.h"
|
||||
#include "destructable.h"
|
||||
#include "player.h"
|
||||
#include "game.h"
|
||||
|
||||
#include <stateManager.h>
|
||||
|
||||
namespace battleship{
|
||||
using namespace std;
|
||||
using namespace vb01;
|
||||
using namespace gameBase;
|
||||
|
||||
ResearchStruct::ResearchStruct(Player *player, int id, Vector3 pos, Quaternion rot, int buildStatus, Unit::State state) : Structure(player, id, pos, rot, buildStatus, state){
|
||||
sol::table unitTable = generateView()["units"][id + 1];
|
||||
generationRate = unitTable["generationRate"];
|
||||
generationSpeed = unitTable["generationSpeed"];
|
||||
researchCost = unitTable["researchCost"];
|
||||
|
||||
Vector2 size = Vector2(lenHpBar, 10);
|
||||
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(){
|
||||
destructable->removeBar(researchStatusBackground);
|
||||
destructable->removeBar(researchStatusForeground);
|
||||
}
|
||||
|
||||
void ResearchStruct::update(){
|
||||
Structure::update();
|
||||
|
||||
if(!isComplete()) return;
|
||||
|
||||
ActiveGameState *activeState = (ActiveGameState*)GameManager::getSingleton()->getStateManager()->getAppStateByType(AppStateType::ACTIVE_STATE);
|
||||
Player *mainPlayer = (activeState ? activeState->getPlayer() : nullptr);
|
||||
|
||||
vector<Player*> selectingPlayers = Unit::getSelectingPlayers();
|
||||
bool mainPlayerSelecting = (activeState && find(selectingPlayers.begin(), selectingPlayers.end(), mainPlayer) != selectingPlayers.end());
|
||||
|
||||
if(researchQueue.empty()){
|
||||
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();
|
||||
}
|
||||
|
||||
researchStatusBackground->setVisible(false);
|
||||
researchStatusForeground->setVisible(false);
|
||||
}
|
||||
else if(!researchQueue.empty()){
|
||||
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);
|
||||
|
||||
if(techCost > playerResearch && canUpdateResearch()){
|
||||
researchStatus += int(100 * ((float)playerResearch / techCost));
|
||||
lastUpdateTime = getTime();
|
||||
}
|
||||
else if(researchStatus >= 100 || techCost <= playerResearch){
|
||||
player->addTechnology(researchQueue[0]);
|
||||
researchQueue.erase(researchQueue.begin());
|
||||
researchStatus = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
#ifndef RESEARCH_STRUCT_H
|
||||
#define RESEARCH_STRUCT_H
|
||||
|
||||
#include "structure.h"
|
||||
|
||||
namespace vb01{
|
||||
class Node;
|
||||
}
|
||||
|
||||
namespace battleship{
|
||||
class ResearchStruct : public Structure{
|
||||
public:
|
||||
ResearchStruct(Player*, int, vb01::Vector3, vb01::Quaternion, int = 0, Unit::State = Unit::State::STAND_GROUND);
|
||||
~ResearchStruct();
|
||||
void update();
|
||||
inline void appendToQueue(int tid){researchQueue.push_back(tid);}
|
||||
inline std::vector<int> getQueue(){return researchQueue;}
|
||||
private:
|
||||
vb01::s64 lastUpdateTime = 0;
|
||||
int researchCost, generationRate, generationSpeed, researchStatus = 0;
|
||||
std::vector<int> researchQueue;
|
||||
vb01::Node *researchStatusForeground = nullptr, *researchStatusBackground = nullptr;
|
||||
|
||||
bool canUpdateResearch(){return vb01::getTime() - lastUpdateTime > generationRate;}
|
||||
void generateResearch();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,41 @@
|
||||
#include "structure.h"
|
||||
#include "activeGameState.h"
|
||||
#include "destructable.h"
|
||||
|
||||
#include <stateManager.h>
|
||||
|
||||
#include <node.h>
|
||||
|
||||
using namespace gameBase;
|
||||
using namespace vb01;
|
||||
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 = 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(){
|
||||
destructable->removeBar(buildStatusForeground);
|
||||
destructable->removeBar(buildStatusBackground);
|
||||
}
|
||||
|
||||
void Structure::update(){
|
||||
Unit::update();
|
||||
|
||||
ActiveGameState *activeState = (ActiveGameState*)GameManager::getSingleton()->getStateManager()->getAppStateByType(AppStateType::ACTIVE_STATE);
|
||||
Player *mainPlayer = (activeState ? activeState->getPlayer() : nullptr);
|
||||
|
||||
vector<Player*> selectingPlayers = getSelectingPlayers();
|
||||
bool mainPlayerSelecting = (activeState && find(selectingPlayers.begin(), selectingPlayers.end(), mainPlayer) != selectingPlayers.end());
|
||||
|
||||
if(!isComplete())
|
||||
destructable->displayStats(buildStatusForeground, buildStatusBackground, buildStatus, 100, mainPlayer == player && mainPlayerSelecting, Vector2(0, -10));
|
||||
else{
|
||||
buildStatusBackground->setVisible(false);
|
||||
buildStatusForeground->setVisible(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#ifndef STRUCTURE_H
|
||||
#define STRUCTURE_H
|
||||
|
||||
#include "unit.h"
|
||||
|
||||
namespace vb01{
|
||||
class Node;
|
||||
}
|
||||
|
||||
namespace battleship{
|
||||
class Structure : public Unit{
|
||||
public:
|
||||
Structure(Player*, int, vb01::Vector3, vb01::Quaternion, int = 0, Unit::State = Unit::State::STAND_GROUND);
|
||||
~Structure();
|
||||
virtual void update();
|
||||
inline bool isComplete(){return buildStatus == 100;}
|
||||
inline int getBuildStatus(){return buildStatus;}
|
||||
inline void incrementBuildStatus(){buildStatus++;}
|
||||
private:
|
||||
protected:
|
||||
vb01::Node *buildStatusBackground = nullptr, *buildStatusForeground = nullptr;
|
||||
int buildStatus = 0;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef TECHNOLOGY_H
|
||||
#define TECHNOLOGY_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace battleship{
|
||||
struct Technology{
|
||||
int cost;
|
||||
std::string name;
|
||||
std::string icon;
|
||||
std::string description;
|
||||
std::vector<int> parents;
|
||||
std::vector<int> abilities;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,582 @@
|
||||
#include <box.h>
|
||||
#include <quad.h>
|
||||
#include <model.h>
|
||||
#include <light.h>
|
||||
#include <texture.h>
|
||||
#include <material.h>
|
||||
#include <particleEmitter.h>
|
||||
|
||||
#include <stateManager.h>
|
||||
#include <solUtil.h>
|
||||
|
||||
#include <glm.hpp>
|
||||
#include <ext.hpp>
|
||||
|
||||
#include "unit.h"
|
||||
#include "weapon.h"
|
||||
#include "util.h"
|
||||
#include "game.h"
|
||||
#include "map.h"
|
||||
#include "vehicle.h"
|
||||
#include "destructable.h"
|
||||
#include "gameObjectFactory.h"
|
||||
#include "activeGameState.h"
|
||||
#include "gameManager.h"
|
||||
#include "projectile.h"
|
||||
#include "defConfigs.h"
|
||||
#include "pathfinder.h"
|
||||
#include "ability.h"
|
||||
|
||||
using namespace glm;
|
||||
using namespace vb01;
|
||||
using namespace gameBase;
|
||||
using namespace std;
|
||||
|
||||
namespace battleship{
|
||||
//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;
|
||||
|
||||
destructable = new Destructable(this);
|
||||
|
||||
Unit::initProperties();
|
||||
initModel();
|
||||
initHitbox();
|
||||
initSound();
|
||||
initWeapons();
|
||||
placeAt(pos);
|
||||
orientAt(rot);
|
||||
|
||||
Vector2 size = Vector2(lenHpBar, 10);
|
||||
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);
|
||||
destructable->removeBar(hpBackgroundNode);
|
||||
destructable->removeBar(hpForegroundNode);
|
||||
destroyWeapons();
|
||||
destroySound();
|
||||
destroyHitbox();
|
||||
destroyModel();
|
||||
}
|
||||
|
||||
void Unit::initProperties(){
|
||||
GameObject::initProperties();
|
||||
|
||||
sol::state_view SOL_LUA_VIEW = generateView();
|
||||
string objType = GameObject::getGameObjTableName();
|
||||
sol::table unitTable = SOL_LUA_VIEW[objType][id + 1];
|
||||
|
||||
Game *game = Game::getSingleton();
|
||||
vector<int> currTechs = player->getTechnologies();
|
||||
|
||||
string name = unitTable["name"];
|
||||
alignToSurface = unitTable["alignToSurface"].get_or(false);
|
||||
vehicle = unitTable["isVehicle"];
|
||||
|
||||
lineOfSight = unitTable["lineOfSight"]; lineOfSight += game->calcAbilFromTech(Ability::Type::LINE_OF_SIGHT, currTechs, (int)GameObject::type, id);
|
||||
unitClass = (UnitClass)unitTable["unitClass"];
|
||||
type = (UnitType)unitTable["unitType"];
|
||||
|
||||
guiScreen = "";
|
||||
string gsk = "guiScreen";
|
||||
sol::optional<string> nameOpt = unitTable[gsk];
|
||||
|
||||
if(nameOpt != sol::nullopt) guiScreen = unitTable[gsk];
|
||||
|
||||
string tblName = "garrisonCapacity";
|
||||
sol::optional<sol::table> gc = unitTable[tblName];
|
||||
|
||||
if(gc != sol::nullopt){
|
||||
string varName = "numGarrisonSlots";
|
||||
SOL_LUA_VIEW.script(varName + " = #" + objType + "[" + to_string(id + 1) + "]." + tblName);
|
||||
int numGarrisonSlots = SOL_LUA_VIEW[varName];
|
||||
|
||||
for(int i = 0; i < numGarrisonSlots; i++){
|
||||
Vector2 size = 10 * Vector2::VEC_IJ;
|
||||
Vector2 pos = Vector2(1.5 * size.x * i, 20);
|
||||
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 = "buildableUnits";
|
||||
sol::optional<sol::table> bu = unitTable[tblName];
|
||||
|
||||
if(bu != sol::nullopt){
|
||||
SOL_LUA_VIEW.script("numBuildableUnits = #units[" + to_string(id + 1) + "]." + tblName);
|
||||
int numBuildableUnits = SOL_LUA_VIEW["numBuildableUnits"];
|
||||
|
||||
for(int i = 0; i < numBuildableUnits; i++){
|
||||
sol::table buTable = unitTable[tblName][i + 1];
|
||||
buildableUnits.push_back(BuildableUnit(buTable["id"], game->isUnitUnlocked(currTechs, id) | (bool)buTable["buildable"]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Unit::initWeapons(){
|
||||
sol::state_view SOL_STATE_VIEW = generateView();
|
||||
string objType = GameObject::getGameObjTableName();
|
||||
sol::table unitTable = SOL_STATE_VIEW[objType][id + 1];
|
||||
|
||||
string tblName = "weapons";
|
||||
sol::optional<sol::table> weaponsTblOpt = unitTable[tblName];
|
||||
|
||||
if(weaponsTblOpt != sol::nullopt){
|
||||
string varName = "numWeapons";
|
||||
SOL_STATE_VIEW.script(varName + " = #" + objType + "[" + to_string(id + 1) + "]." + tblName);
|
||||
int numWeapons = SOL_STATE_VIEW[varName];
|
||||
|
||||
for(int i = 0; i < numWeapons; i++){
|
||||
int wt = 0;
|
||||
sol::optional<int> wtOpt = unitTable[tblName][i + 1]["type"];
|
||||
|
||||
if(wtOpt != sol::nullopt) wt = unitTable[tblName][i + 1]["type"];
|
||||
|
||||
weapons.push_back(new Weapon(this, unitTable, i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Unit::destroyWeapons(){
|
||||
for(Weapon *weapon : weapons)
|
||||
delete weapon;
|
||||
|
||||
weapons.clear();
|
||||
}
|
||||
|
||||
void Unit::initLosLight(){
|
||||
Light *light = new Light(Light::Type::POINT);
|
||||
light->setAttenuation(Light::Attenuation::NONE);
|
||||
light->setRadius(lineOfSight);
|
||||
light->setColor(Vector3::VEC_IJK * .3);
|
||||
light->setAdditiveLighting(false);
|
||||
light->setUseAngle(false);
|
||||
|
||||
losLightNode = new Node(Vector3::VEC_J * 5);
|
||||
//losLightNode->addLight(light);
|
||||
model->attachChild(losLightNode);
|
||||
}
|
||||
|
||||
void Unit::destroyLosLight(){
|
||||
model->dettachChild(losLightNode);
|
||||
delete losLightNode;
|
||||
losLightNode = nullptr;
|
||||
}
|
||||
|
||||
int Unit::getNumFreeGarrisonSlots(){
|
||||
int numFreeSlots = 0;
|
||||
|
||||
for(GarrisonSlot &slot : garrisonSlots)
|
||||
if(!slot.vehicle) numFreeSlots++;
|
||||
|
||||
return numFreeSlots;
|
||||
}
|
||||
|
||||
void Unit::destroySound(){
|
||||
selectionSfx->stop();
|
||||
delete selectionSfx;
|
||||
delete selectionSfxBuffer;
|
||||
}
|
||||
|
||||
//TODO factor out initSound()
|
||||
void Unit::initSound(){
|
||||
GameObject::initSound();
|
||||
selectionSfxBuffer = new sf::SoundBuffer();
|
||||
string sfxPath = generateView()[getGameObjTableName()][id + 1]["selectionSfx"];
|
||||
selectionSfx = GameObject::prepareSfx(selectionSfxBuffer, sfxPath);
|
||||
}
|
||||
|
||||
void Unit::reinit(){
|
||||
if(losLightNode)
|
||||
destroyLosLight();
|
||||
|
||||
destroyWeapons();
|
||||
destroyHitbox();
|
||||
destroyModel();
|
||||
destroySound();
|
||||
|
||||
Unit::initProperties();
|
||||
|
||||
initModel();
|
||||
initHitbox();
|
||||
initSound();
|
||||
initWeapons();
|
||||
|
||||
GameObject::reinit();
|
||||
}
|
||||
|
||||
bool Unit::canGarrison(Vehicle *vehicle){
|
||||
for(int i = 0; i < garrisonSlots.size(); i++)
|
||||
if(!garrisonSlots[i].vehicle && garrisonSlots[i].category >= vehicle->getGarrisonCategory())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Unit::launch(Order order){
|
||||
getWeaponsByOrder(Order::TYPE::LAUNCH)[0]->fire(order);
|
||||
removeOrder(0);
|
||||
}
|
||||
|
||||
float Unit::calculateRotation(Vector3 dir, float angle, float maxTurnAngle){
|
||||
float rotSpeed = (maxTurnAngle > angle ? angle : maxTurnAngle);
|
||||
|
||||
if(isTargetToTheRight(dir, leftVec))
|
||||
rotSpeed *= -1;
|
||||
|
||||
return rotSpeed;
|
||||
}
|
||||
|
||||
void Unit::renderOrderLine(bool mainPlayerSelecting){
|
||||
if (!orders.empty() && orders[0].lineId != -1 && mainPlayerSelecting){
|
||||
bool display = canDisplayOrderLine();
|
||||
LineRenderer *lineRenderer = LineRenderer::getSingleton();
|
||||
lineRenderer->toggleVisibility(orders[0].lineId, display);
|
||||
|
||||
if(display){
|
||||
lineRenderer->changeLineField(orders[0].lineId, pos, LineRenderer::START);
|
||||
Vector3 targPos = (orders[0].targets[0].unit ? orders[0].targets[0].unit->getPos() : orders[0].targets[0].pos);
|
||||
lineRenderer->changeLineField(orders[0].lineId, targPos, LineRenderer::END);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TODO clean up method code
|
||||
void Unit::autoAttackTargets(){
|
||||
if(!orders.empty()) return;
|
||||
|
||||
vector<Player*> players = Game::getSingleton()->getPlayers();
|
||||
vector<GameObject*> targets;
|
||||
|
||||
for(Player *pl : players)
|
||||
if(!(pl == player || pl->getTeam() == player->getTeam())){
|
||||
vector<GameObject*> targs = pl->getDestructables();
|
||||
targets.insert(targets.end(), targs.begin(), targs.end());
|
||||
}
|
||||
|
||||
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(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);
|
||||
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();
|
||||
destructable->displayStats(hpForegroundNode, hpBackgroundNode, destructable->getHealth(), destructable->getMaxHealth(), mainPlayerSelecting);
|
||||
|
||||
for(GarrisonSlot &slot : garrisonSlots)
|
||||
destructable->displayStats(slot.foreground, slot.background, (int)((bool)slot.vehicle), (int)true, renderSelectables, slot.offset);
|
||||
|
||||
for(Weapon *weapon : weapons)
|
||||
weapon->update();
|
||||
}
|
||||
|
||||
//TODO remove order argument from action methods
|
||||
void Unit::executeOrders() {
|
||||
if(orders.empty() || condition != Condition::ABLE) return;
|
||||
|
||||
if(!currOrderStarted) startCurrentOrder();
|
||||
|
||||
if(!orders[0].targets.empty() && orders[0].targets[0].unit){
|
||||
vector<Unit*> units;
|
||||
|
||||
for(Player *pl : Game::getSingleton()->getPlayers(true)){
|
||||
vector<Unit*> us = pl->getUnits();
|
||||
units.insert(units.end(), us.begin(), us.end());
|
||||
}
|
||||
|
||||
if(find(units.begin(), units.end(), orders[0].targets[0].unit) == units.end()){
|
||||
removeOrder(0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch (orders[0].type) {
|
||||
case Order::TYPE::ATTACK:
|
||||
attack(orders[0]);
|
||||
break;
|
||||
case Order::TYPE::BUILD:
|
||||
build(orders[0]);
|
||||
break;
|
||||
case Order::TYPE::MOVE:
|
||||
move(orders[0]);
|
||||
break;
|
||||
case Order::TYPE::GARRISON:
|
||||
garrison(orders[0]);
|
||||
break;
|
||||
case Order::TYPE::EJECT:
|
||||
eject(orders[0]);
|
||||
break;
|
||||
case Order::TYPE::PATROL:
|
||||
patrol(orders[0]);
|
||||
break;
|
||||
case Order::TYPE::LAUNCH:
|
||||
launch(orders[0]);
|
||||
break;
|
||||
break;
|
||||
case Order::TYPE::LOAD:
|
||||
case Order::TYPE::SUPPLY:
|
||||
case Order::TYPE::UNLOAD:
|
||||
handleResources(orders[0]);
|
||||
break;
|
||||
case Order::TYPE::HACK:
|
||||
hack(orders[0]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Unit::eject(Order order){
|
||||
Map *map = Map::getSingleton();
|
||||
int currCellId = map->getCellId(pos);
|
||||
vector<Map::Cell> &cells = map->getCells();
|
||||
int adjWaterCellId = -1, adjLandCellId = -1;
|
||||
|
||||
for(Map::Edge edge : cells[currCellId].edges){
|
||||
if(adjLandCellId == -1 && cells[edge.destCellId].type == Map::Cell::LAND)
|
||||
adjLandCellId = edge.destCellId;
|
||||
if(adjWaterCellId == -1 && cells[edge.destCellId].type == Map::Cell::WATER)
|
||||
adjWaterCellId = edge.destCellId;
|
||||
}
|
||||
|
||||
for(GarrisonSlot &slot : garrisonSlots)
|
||||
if(slot.vehicle){
|
||||
bool exitToLandCell = (slot.vehicle->getType() == UnitType::LAND && adjLandCellId != -1);
|
||||
bool exitToWaterCell = ((slot.vehicle->getType() == UnitType::SEA_LEVEL || slot.vehicle->getType() == UnitType::UNDERWATER) && adjWaterCellId != -1);
|
||||
|
||||
if(exitToLandCell || exitToWaterCell)
|
||||
slot.vehicle->exitGarrisonable(cells[exitToLandCell ? adjLandCellId : adjWaterCellId].pos);
|
||||
}
|
||||
|
||||
removeOrder(0);
|
||||
}
|
||||
|
||||
void Unit::attack(Order order){
|
||||
vector<GameObject*> targets;
|
||||
|
||||
for(Player *pl : Game::getSingleton()->getPlayers()){
|
||||
vector<GameObject*> targs = pl->getDestructables();
|
||||
targets.insert(targets.end(), targs.begin(), targs.end());
|
||||
}
|
||||
|
||||
vector<Weapon*> attackWeapons = getWeaponsByOrder(Order::TYPE::ATTACK);
|
||||
|
||||
for(Order::Target &target : orders[0].targets)
|
||||
if(target.unit){
|
||||
if(find(targets.begin(), targets.end(), target.unit) != targets.end()){
|
||||
bool canAttack = false;
|
||||
|
||||
for(Weapon *aw : attackWeapons){
|
||||
int tc;
|
||||
|
||||
switch(target.unit->getType()){
|
||||
case GameObject::Type::UNIT:
|
||||
tc = (int)((Unit*)target.unit)->getType();
|
||||
break;
|
||||
case GameObject::Type::PROJECTILE:
|
||||
tc = (int)((Projectile*)target.unit)->getProjectileClass();
|
||||
break;
|
||||
}
|
||||
|
||||
if(aw->canAttackTarget((int)target.unit->getType(), tc)) canAttack = true;
|
||||
}
|
||||
|
||||
if(!canAttack){
|
||||
removeOrder(0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else{
|
||||
removeOrder(0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 targPos = (order.targets[0].unit ? order.targets[0].unit->getPos() : order.targets[0].pos);
|
||||
|
||||
for(Weapon *weapon : attackWeapons)
|
||||
weapon->trackTarget(targPos);
|
||||
}
|
||||
|
||||
bool Unit::validateOrder(Order order){
|
||||
switch (order.type) {
|
||||
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::ROBO_ENGINEER || unitClass == UnitClass::CYBORG_ENGINEER || unitClass == UnitClass::FREEZER);
|
||||
case Order::TYPE::PATROL:
|
||||
case Order::TYPE::MOVE:
|
||||
return vehicle;
|
||||
case Order::TYPE::GARRISON:
|
||||
return validateGarrisonOrder(order);
|
||||
case Order::TYPE::EJECT:
|
||||
return !garrisonSlots.empty();
|
||||
case Order::TYPE::LAUNCH:
|
||||
return validateLaunchOrder();
|
||||
case Order::TYPE::SUPPLY:
|
||||
case Order::TYPE::LOAD:
|
||||
case Order::TYPE::UNLOAD:
|
||||
return unitClass == UnitClass::RESOURCE_ROVER;
|
||||
case Order::TYPE::HACK:
|
||||
return !getWeaponsByOrder(Order::TYPE::HACK).empty();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
vector<Weapon*> Unit::getWeaponsByOrder(Order::TYPE type){
|
||||
vector<Weapon*> weaps;
|
||||
|
||||
for(Weapon *w : weapons)
|
||||
if(w->getOrderType() == type)
|
||||
weaps.push_back(w);
|
||||
|
||||
return weaps;
|
||||
}
|
||||
|
||||
vector<Weapon*> Unit::getWeaponsByType(int type){
|
||||
vector<Weapon*> weaps;
|
||||
|
||||
for(Weapon *w : weapons)
|
||||
if(w->getType() == (Weapon::Type)type)
|
||||
weaps.push_back(w);
|
||||
|
||||
return weaps;
|
||||
}
|
||||
|
||||
void Unit::receiveOrder(Order order, bool add) {
|
||||
if(!validateOrder(order)) return;
|
||||
|
||||
if(!add){
|
||||
while (!orders.empty())
|
||||
removeOrder(0);
|
||||
|
||||
orderLineDispTime = getTime();
|
||||
}
|
||||
|
||||
orders.push_back(order);
|
||||
|
||||
if(order.type == Order::TYPE::BUILD && order.targets[0].unit)
|
||||
player->addUnit((Unit*)order.targets[0].unit);
|
||||
|
||||
executeOrders();
|
||||
}
|
||||
|
||||
void Unit::halt() {
|
||||
while (orders.size() > 0)
|
||||
removeOrder(orders.size() - 1);
|
||||
}
|
||||
|
||||
void Unit::updateGarrison(Vehicle *garrVeh, bool entering){
|
||||
for(GarrisonSlot &slot : garrisonSlots){
|
||||
if(entering && !slot.vehicle){
|
||||
slot.vehicle = garrVeh;
|
||||
break;
|
||||
}
|
||||
else if(!entering && slot.vehicle == garrVeh){
|
||||
slot.vehicle = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TODO select only the closest cells based on unit size
|
||||
void Unit::placeAt(Vector3 p){
|
||||
Map *map = Map::getSingleton();
|
||||
|
||||
if(alignToSurface){
|
||||
vector<RayCaster::CollisionResult> res = map->raycastTerrain(Vector3(p.x, 100, p.z), -Vector3::VEC_J, true);
|
||||
|
||||
if(res.empty() || res[0].mesh->getNode() != map->getNodeParent()->getChild(0))
|
||||
model->lookAt(Vector3(dirVec.x, 0, dirVec.z).norm(), Vector3::VEC_J);
|
||||
else if(res[0].mesh->getNode() == map->getNodeParent()->getChild(0)){
|
||||
float angle = upVec.getAngleBetween(res[0].norm);
|
||||
|
||||
//if(angle > 0)
|
||||
model->lookAt(leftVec.cross(res[0].norm), res[0].norm);
|
||||
}
|
||||
}
|
||||
|
||||
ActiveGameState *activeState = (ActiveGameState*)GameManager::getSingleton()->getStateManager()->getAppStateByType(AppStateType::ACTIVE_STATE);
|
||||
|
||||
//check twice in case the unit is warped over a long distance
|
||||
if(activeState) map->blockCells(this);
|
||||
GameObject::placeAt(p);
|
||||
|
||||
if(activeState){
|
||||
map->blockCells(this);
|
||||
|
||||
//if(activeState->getPlayer()) Map::Minimap::getSingleton()->updateImage();
|
||||
}
|
||||
}
|
||||
|
||||
vector<Player*> Unit::getSelectingPlayers(){
|
||||
vector<Player*> players = Game::getSingleton()->getPlayers(), selectingPlayers;
|
||||
|
||||
for(Player *pl : players){
|
||||
int numSelectedUnits = pl->getNumSelectedUnits();
|
||||
|
||||
for(int i = 0; i < numSelectedUnits; i++)
|
||||
if(pl->getSelectedUnit(i) == this){
|
||||
selectingPlayers.push_back(pl);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return selectingPlayers;
|
||||
}
|
||||
|
||||
void Unit::removeOrder(int id) {
|
||||
if(orders[id].lineId != -1)
|
||||
LineRenderer::getSingleton()->removeLine(orders[id].lineId);
|
||||
|
||||
orders.erase(orders.begin() + id);
|
||||
currOrderStarted = false;
|
||||
}
|
||||
|
||||
void Unit::select() {
|
||||
ActiveGameState *activeState = (ActiveGameState*)GameManager::getSingleton()->getStateManager()->getAppStateByType(AppStateType::ACTIVE_STATE);
|
||||
Player *mainPlayer = (activeState ? activeState->getPlayer() : nullptr);
|
||||
|
||||
vector<Player*> selectingPlayers = getSelectingPlayers();
|
||||
bool mainPlayerSelecting = (activeState && find(selectingPlayers.begin(), selectingPlayers.end(), mainPlayer) != selectingPlayers.end());
|
||||
|
||||
if(mainPlayer == player && mainPlayerSelecting && selectionSfx)
|
||||
selectionSfx->play();
|
||||
|
||||
orderLineDispTime = getTime();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
#ifndef UNIT_H
|
||||
#define UNIT_H
|
||||
|
||||
#include <vector>
|
||||
#include <util.h>
|
||||
#include <quaternion.h>
|
||||
#include <lineRenderer.h>
|
||||
|
||||
#include <solUtil.h>
|
||||
|
||||
#include "gameObject.h"
|
||||
#include "buildableUnit.h"
|
||||
#include "fxManager.h"
|
||||
|
||||
namespace sf{
|
||||
class SoundBuffer;
|
||||
class Sound;
|
||||
}
|
||||
|
||||
namespace vb01{
|
||||
class Mesh;
|
||||
class Quad;
|
||||
class Node;
|
||||
class Light;
|
||||
class Camera;
|
||||
}
|
||||
|
||||
namespace battleship{
|
||||
class Player;
|
||||
class Weapon;
|
||||
class GameObject;
|
||||
class Vehicle;
|
||||
class Projectile;
|
||||
|
||||
struct Order {
|
||||
enum class TYPE {ATTACK, BUILD, MOVE, GARRISON, EJECT, PATROL, LAUNCH, SUPPLY, LOAD, UNLOAD, HACK};
|
||||
struct Target{
|
||||
GameObject *unit = nullptr;
|
||||
vb01::Vector3 pos;
|
||||
|
||||
Target(){}
|
||||
Target(GameObject *u, vb01::Vector3 p = vb01::Vector3::VEC_ZERO) : unit(u), pos(p){}
|
||||
};
|
||||
|
||||
TYPE type;
|
||||
int lineId = -1;
|
||||
bool playerAssigned = true;
|
||||
vb01::Vector3 direction;
|
||||
std::vector<Target> targets;
|
||||
|
||||
Order(){}
|
||||
Order(TYPE t, std::vector<Target> targ, vb01::Vector3 dir = vb01::Vector3::VEC_ZERO, int lid = -1, bool pa = true) :
|
||||
type(t),
|
||||
playerAssigned(pa),
|
||||
lineId(lid),
|
||||
targets(targ),
|
||||
direction(dir){}
|
||||
};
|
||||
|
||||
enum class MoveDir {LEFT, UP, FORW};
|
||||
enum class Corner {FRONT_LEFT, FRONT_RIGHT, REAR_LEFT, REAR_RIGHT};
|
||||
enum class UnitType {UNDERWATER, SEA_LEVEL, HOVER, LAND, AIR, NONE = -1};
|
||||
enum class UnitClass {
|
||||
MECH,
|
||||
TANK,
|
||||
ARTILLERY,
|
||||
ROBO_ENGINEER,
|
||||
CYBORG_ENGINEER,
|
||||
TRANSPORT,
|
||||
RESOURCE_ROVER,
|
||||
CRUISER,
|
||||
ANTI_SUB_CRUISER,
|
||||
CARRIER,
|
||||
SUBMARINE,
|
||||
MISSILE_SUBMARINE,
|
||||
ICEBREAKER,
|
||||
FREEZER,
|
||||
EMP_BOAT,
|
||||
LAND_FACTORY,
|
||||
NAVAL_FACTORY,
|
||||
TRADE_CENTER,
|
||||
LAB,
|
||||
POINT_DEFENSE,
|
||||
EXTRACTOR,
|
||||
REFINERY,
|
||||
ICE_SHEET
|
||||
};
|
||||
|
||||
class Unit : public GameObject{
|
||||
public:
|
||||
struct GarrisonSlot{
|
||||
Vehicle *vehicle = nullptr;
|
||||
int category;
|
||||
vb01::Node *background, *foreground;
|
||||
vb01::Vector2 offset;
|
||||
|
||||
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 State {CHASE, STAND_GROUND, HOLD_FIRE};
|
||||
enum class Condition{ABLE, FROZEN, EM_JAMMED};
|
||||
|
||||
Unit(Player*, int, vb01::Vector3, vb01::Quaternion, State = State::STAND_GROUND);
|
||||
virtual ~Unit();
|
||||
virtual void update();
|
||||
virtual void halt();
|
||||
void updateGarrison(Vehicle*, bool);
|
||||
virtual void select();
|
||||
void setOrder(Order);
|
||||
std::vector<Projectile*> getProjectiles();
|
||||
virtual void receiveOrder(Order, bool);
|
||||
bool canGarrison(Vehicle*);
|
||||
void initLosLight();
|
||||
void destroyLosLight();
|
||||
int getNumFreeGarrisonSlots();
|
||||
inline void setState(State s){state = s;}
|
||||
inline State getState(){return state;}
|
||||
inline int getNumGarrisonSlots(){return garrisonSlots.size();}
|
||||
inline bool isGarrisonEmpty(){return getNumFreeGarrisonSlots() == getNumGarrisonSlots();}
|
||||
inline const std::vector<GarrisonSlot>& getGarrisonSlots(){return garrisonSlots;}
|
||||
inline float getLineOfSight() {return lineOfSight;}
|
||||
inline UnitType getType() {return type;}
|
||||
inline UnitClass getUnitClass() {return unitClass;}
|
||||
inline int getPlayerId() {return playerId;}
|
||||
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];}
|
||||
inline int getNumOrders(){return orders.size();}
|
||||
inline std::string getGuiScreen(){return guiScreen;}
|
||||
inline std::vector<BuildableUnit> getBuildableUnits(){return buildableUnits;}
|
||||
inline int getNumBuildableUnits(){return buildableUnits.size();}
|
||||
inline BuildableUnit getBuildableUnit(int i){return buildableUnits[i];}
|
||||
inline vb01::Node* getLosLightNode(){return losLightNode;}
|
||||
inline Condition getCondition(){return condition;}
|
||||
inline void setCondition(Condition cond){
|
||||
this->condition = cond;
|
||||
|
||||
if(cond == Condition::EM_JAMMED) lastJamTime = vb01::getTime();
|
||||
}
|
||||
private:
|
||||
void renderOrderLine(bool);
|
||||
void initWeapons();
|
||||
void destroyWeapons();
|
||||
bool validateOrder(Order);
|
||||
inline bool canDisplayOrderLine(){return vb01::getTime() - orderLineDispTime < orderVecDispLength;}
|
||||
|
||||
const int orderVecDispLength = 2000;
|
||||
sf::SoundBuffer *selectionSfxBuffer;
|
||||
sf::Sound *selectionSfx = nullptr;
|
||||
vb01::Node *losLightNode = nullptr;
|
||||
bool vehicle, currOrderStarted = false, alignToSurface = false;
|
||||
Condition condition = Condition::ABLE;
|
||||
protected:
|
||||
UnitType type;
|
||||
UnitClass unitClass;
|
||||
std::vector<Order> orders;
|
||||
std::string guiScreen = "";
|
||||
int playerId, restartTime, lenHpBar = 200;
|
||||
vb01::s64 orderLineDispTime = 0, lastFireTime = 0, lastJamTime = 0;
|
||||
float lineOfSight;
|
||||
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();
|
||||
void removeOrder(int);
|
||||
virtual void startCurrentOrder(){currOrderStarted = true;}
|
||||
virtual bool validateLaunchOrder(){return !getWeaponsByOrder(Order::TYPE::LAUNCH).empty();}
|
||||
virtual bool validateGarrisonOrder(Order){return false;}
|
||||
virtual void autoAttackTargets();
|
||||
virtual void reinit();
|
||||
virtual void initProperties();
|
||||
virtual void destroySound();
|
||||
virtual void initSound();
|
||||
virtual void executeOrders();
|
||||
virtual void eject(Order);
|
||||
virtual void attack(Order);
|
||||
virtual void garrison(Order){}
|
||||
virtual void build(Order){}
|
||||
virtual void move(Order){}
|
||||
virtual void patrol(Order){}
|
||||
virtual void launch(Order);
|
||||
virtual void handleResources(Order){}
|
||||
virtual void hack(Order){}
|
||||
virtual void freeze(Order){}
|
||||
float calculateRotation(vb01::Vector3, float, float);
|
||||
std::vector<Weapon*> getWeaponsByOrder(Order::TYPE);
|
||||
std::vector<Weapon*> getWeaponsByType(int);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,81 @@
|
||||
#include "engineer.h"
|
||||
#include "activeGameState.h"
|
||||
#include "destructable.h"
|
||||
#include "structure.h"
|
||||
#include "player.h"
|
||||
#include "game.h"
|
||||
#include "map.h"
|
||||
|
||||
#include <solUtil.h>
|
||||
#include <stateManager.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace battleship{
|
||||
using namespace std;
|
||||
using namespace vb01;
|
||||
using namespace gameBase;
|
||||
|
||||
Engineer::Engineer(Player *player, int id, Vector3 pos, Quaternion rot, Unit::State state) : Vehicle(player, id, pos, rot, state){
|
||||
Game *game = Game::getSingleton();
|
||||
vector<int> currTechs = player->getTechnologies();
|
||||
hackRange = generateView()["units"][id + 1]["hackRange"]; hackRange += game->calcAbilFromTech(Ability::Type::HACK_RANGE, currTechs, (int)GameObject::type, id);
|
||||
|
||||
Vector2 size = Vector2(lenHpBar, 10);
|
||||
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(){
|
||||
destructable->removeBar(hackStatusBackground);
|
||||
destructable->removeBar(hackStatusForeground);
|
||||
}
|
||||
|
||||
void Engineer::update(){
|
||||
Vehicle::update();
|
||||
|
||||
ActiveGameState *activeState = (ActiveGameState*)GameManager::getSingleton()->getStateManager()->getAppStateByType(AppStateType::ACTIVE_STATE);
|
||||
Player *mainPlayer = (activeState ? activeState->getPlayer() : nullptr);
|
||||
|
||||
vector<Player*> selectingPlayers = Unit::getSelectingPlayers();
|
||||
bool mainPlayerSelecting = (activeState && find(selectingPlayers.begin(), selectingPlayers.end(), mainPlayer) != selectingPlayers.end());
|
||||
|
||||
if(hackStatus < 100)
|
||||
destructable->displayStats(hackStatusForeground, hackStatusBackground, hackStatus, 100, mainPlayer == player && mainPlayerSelecting, Vector2(0, -10));
|
||||
else{
|
||||
hackStatusBackground->setVisible(false);
|
||||
hackStatusForeground->setVisible(false);
|
||||
}
|
||||
|
||||
if(orders.empty() || orders[0].type != Order::TYPE::HACK)
|
||||
hackStatus = 0;
|
||||
}
|
||||
|
||||
//TODO change unit colors after faction change
|
||||
void Engineer::hack(Order order){
|
||||
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);
|
||||
|
||||
if(withinRange && canHack){
|
||||
hackStatus++;
|
||||
pursuingTarget = false;
|
||||
}
|
||||
else if(!withinRange){
|
||||
hackStatus = 0;
|
||||
|
||||
if(!pursuingTarget){
|
||||
preparePathpoints(order, targUnit->getPos());
|
||||
pursuingTarget = true;
|
||||
}
|
||||
else
|
||||
navigateToTarget(.9 * hackRange);
|
||||
}
|
||||
|
||||
if(hackStatus >= 100){
|
||||
order.targets[0].unit->changePlayer(player);
|
||||
removeOrder(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
#ifndef ENGINEER_H
|
||||
#define ENGINEER_H
|
||||
|
||||
#include <util.h>
|
||||
|
||||
#include "vehicle.h"
|
||||
|
||||
namespace vb01{
|
||||
class Node;
|
||||
}
|
||||
|
||||
namespace battleship{
|
||||
class Structure;
|
||||
|
||||
class Engineer : public Vehicle{
|
||||
public:
|
||||
Engineer(Player*, int, vb01::Vector3, vb01::Quaternion, Unit::State);
|
||||
~Engineer();
|
||||
void update();
|
||||
private:
|
||||
int hackStatus = 0;
|
||||
float hackRange;
|
||||
vb01::s64 lastHackTime = 0;
|
||||
vb01::Node *hackStatusBackground = nullptr, *hackStatusForeground = nullptr;
|
||||
|
||||
void hack(Order);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,39 @@
|
||||
#include "freezer.h"
|
||||
#include "weapon.h"
|
||||
#include "structure.h"
|
||||
#include "destructable.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace battleship{
|
||||
using namespace vb01;
|
||||
using namespace std;
|
||||
|
||||
//TODO rename the class to a more generic name
|
||||
Freezer::Freezer(Player *player, int id, Vector3 pos, Quaternion rot, Unit::State state) : Vehicle(player, id, pos, rot, state){}
|
||||
|
||||
void Freezer::attack(Order order){
|
||||
Vehicle::attack(order);
|
||||
|
||||
Destructable *target = order.targets[0].unit->getDestructable();
|
||||
|
||||
if(target && target->getFreezeStatus() >= 100)
|
||||
removeOrder(0);
|
||||
}
|
||||
|
||||
void Freezer::build(Order order){
|
||||
vector<Weapon*> weapons = getWeaponsByType((int)Weapon::Type::FREEZER);
|
||||
|
||||
if(weapons.empty()) return;
|
||||
|
||||
Unit *targ = (Unit*)order.targets[0].unit;
|
||||
|
||||
for(Weapon *w : weapons)
|
||||
w->trackTarget(targ->getPos());
|
||||
|
||||
Vehicle::build(order);
|
||||
|
||||
if(targ->getUnitClass() == UnitClass::ICE_SHEET && ((Structure*)targ)->isComplete())
|
||||
removeOrder(0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
#ifndef FREEZER_H
|
||||
#define FREEZER_H
|
||||
|
||||
#include "vehicle.h"
|
||||
|
||||
namespace battleship{
|
||||
class Freezer : public Vehicle{
|
||||
public:
|
||||
Freezer(Player*, int, vb01::Vector3, vb01::Quaternion, Unit::State);
|
||||
private:
|
||||
void attack(Order);
|
||||
void build(Order);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,203 @@
|
||||
#include "resourceRover.h"
|
||||
#include "resourceDeposit.h"
|
||||
#include "destructable.h"
|
||||
#include "map.h"
|
||||
#include "game.h"
|
||||
#include "player.h"
|
||||
#include "extractor.h"
|
||||
#include "structure.h"
|
||||
#include "activeGameState.h"
|
||||
|
||||
#include <stateManager.h>
|
||||
|
||||
namespace battleship{
|
||||
using namespace std;
|
||||
using namespace vb01;
|
||||
using namespace gameBase;
|
||||
|
||||
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 = 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(){
|
||||
destructable->removeBar(loadForeground);
|
||||
destructable->removeBar(loadBackground);
|
||||
}
|
||||
|
||||
void ResourceRover::initProperties(){
|
||||
Game *game = Game::getSingleton();
|
||||
vector<int> currTechs = player->getTechnologies();
|
||||
|
||||
sol::table unitTable = generateView()["units"][id + 1];
|
||||
capacity = unitTable["capacity"]; capacity += game->calcAbilFromTech(Ability::Type::CAPACITY, currTechs, (int)GameObject::type, id);
|
||||
loadSpeed = unitTable["loadSpeed"]; loadSpeed += game->calcAbilFromTech(Ability::Type::LOAD_SPEED, currTechs, (int)GameObject::type, id);
|
||||
loadRate = unitTable["loadRate"]; loadRate += game->calcAbilFromTech(Ability::Type::LOAD_RATE, currTechs, (int)GameObject::type, id);
|
||||
}
|
||||
|
||||
//TODO implement a check of whether a vehicle is next to a building's outline
|
||||
void ResourceRover::loadResources(Structure *targStruct, bool loadResource){
|
||||
float w = targStruct->getWidth(), l = targStruct->getLength();
|
||||
bool closeEnough = (pos.getDistanceFrom(targStruct->getPos()) <= sqrt(l * l + w * w));
|
||||
if(!closeEnough) return;
|
||||
|
||||
ResourceType resType;
|
||||
|
||||
switch(targStruct->getUnitClass()){
|
||||
case UnitClass::TRADE_CENTER:
|
||||
resType = ResourceType::WEALTH;
|
||||
break;
|
||||
case UnitClass::REFINERY:
|
||||
resType = ResourceType::REFINEDS;
|
||||
break;
|
||||
case UnitClass::LAB:
|
||||
resType = ResourceType::RESEARCH;
|
||||
break;
|
||||
}
|
||||
|
||||
if(player == targStruct->getPlayer()){
|
||||
if(!loadResource && canUnload((int)resType)){
|
||||
player->updateResource(resType, loadSpeed, true);
|
||||
cargo[(int)resType] -= loadSpeed;
|
||||
lastLoadTime = getTime();
|
||||
}
|
||||
else if(loadResource && canLoad() && player->getResource(resType) > 0){
|
||||
player->updateResource(resType, -loadSpeed, true);
|
||||
cargo[(int)resType] += loadSpeed;
|
||||
lastLoadTime = getTime();
|
||||
}
|
||||
}
|
||||
else{
|
||||
vector<TradeOffer*> offers = player->getTradeOffers(targStruct->getPlayer());
|
||||
if(offers.empty()) return;
|
||||
|
||||
TradeOffer *offer = offers[0];
|
||||
|
||||
if(!loadResource && offer->tradeResources[(int)resType][1] > offer->deliveredResources[(int)resType][1] && canUnload((int)resType)){
|
||||
targStruct->getPlayer()->updateResource(resType, loadSpeed, true);
|
||||
offer->deliveredResources[(int)resType][1]++;
|
||||
cargo[(int)resType] -= loadSpeed;
|
||||
lastLoadTime = getTime();
|
||||
}
|
||||
else if(
|
||||
loadResource &&
|
||||
offer->tradeResources[(int)resType][0] > offer->deliveredResources[(int)resType][0] &&
|
||||
targStruct->getPlayer()->getResource(resType) > 0 &&
|
||||
canLoad()
|
||||
)
|
||||
{
|
||||
targStruct->getPlayer()->updateResource(resType, -loadSpeed, true);
|
||||
offer->deliveredResources[(int)resType][0]++;
|
||||
cargo[(int)resType] += loadSpeed;
|
||||
lastLoadTime = getTime();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TODO equate rover load and extractor draw rates
|
||||
void ResourceRover::collectRefineds(Order order){
|
||||
vector<Unit*> units = player->getUnits();
|
||||
vector<Structure*> extractors, refineries;
|
||||
|
||||
for(Unit *unit : units){
|
||||
if(unit->getUnitClass() == UnitClass::EXTRACTOR && ((Extractor*)unit)->getDeposit()->getAmmount() > 0)
|
||||
extractors.push_back((Structure*)unit);
|
||||
else if(unit->getUnitClass() == UnitClass::REFINERY)
|
||||
refineries.push_back((Structure*)unit);
|
||||
}
|
||||
|
||||
nearestExtractor = (Extractor*)getClosestUnit(extractors);
|
||||
nearestRefinery = getClosestUnit(refineries);
|
||||
|
||||
auto closeEnough = [](GameObject *obj, Vector3 pos){
|
||||
Vector3 neVec = pos - obj->getPos();
|
||||
float angle = obj->getDirVec().getAngleBetween(neVec.norm());
|
||||
|
||||
if(angle > PI / 2) angle = PI - angle;
|
||||
|
||||
return cos(angle) * neVec.getLength() < .5 * obj->getLength();
|
||||
};
|
||||
|
||||
if(nearestExtractor && closeEnough(nearestExtractor, pos)){
|
||||
ResourceDeposit *deposit = nearestExtractor->getDeposit();
|
||||
|
||||
if(canLoad() && deposit->getAmmount() > 0){
|
||||
if(nearestExtractor->canDraw()){
|
||||
nearestExtractor->draw();
|
||||
cargo[(int)ResourceType::REFINEDS] += loadSpeed;
|
||||
lastLoadTime = getTime();
|
||||
}
|
||||
}
|
||||
else if(calcTotalLoad() == capacity && nearestRefinery){
|
||||
order.targets[0].unit = nearestRefinery;
|
||||
preparePathpoints(order, nearestRefinery->getPos());
|
||||
}
|
||||
}
|
||||
else if(!nearestExtractor){
|
||||
if(nearestRefinery && cargo[(int)ResourceType::REFINEDS] > 0){
|
||||
order.targets[0].unit = nearestRefinery;
|
||||
preparePathpoints(order, nearestRefinery->getPos());
|
||||
}
|
||||
else removeOrder(0);
|
||||
}
|
||||
|
||||
if(nearestRefinery && closeEnough(nearestRefinery, pos)){
|
||||
if(canUnload((int)ResourceType::REFINEDS)){
|
||||
cargo[(int)ResourceType::REFINEDS] -= loadSpeed;
|
||||
player->updateResource(ResourceType::REFINEDS, loadSpeed, true);
|
||||
lastLoadTime = getTime();
|
||||
}
|
||||
else if(cargo[(int)ResourceType::REFINEDS] == 0 && nearestExtractor){
|
||||
order.targets[0].unit = nearestExtractor;
|
||||
preparePathpoints(order, nearestExtractor->getPos());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ResourceRover::handleResources(Order order){
|
||||
if(!pathPoints.empty()) navigate(.01);
|
||||
else if(order.type == Order::TYPE::SUPPLY)
|
||||
collectRefineds(order);
|
||||
else
|
||||
loadResources((Structure*)order.targets[0].unit, order.type == Order::TYPE::LOAD);
|
||||
}
|
||||
|
||||
void ResourceRover::update(){
|
||||
Vehicle::update();
|
||||
|
||||
vector<Unit*> units = player->getUnits();
|
||||
nearestExtractor = (find(units.begin(), units.end(), nearestExtractor) != units.end() ? nearestExtractor : nullptr);
|
||||
nearestRefinery = (find(units.begin(), units.end(), nearestRefinery) != units.end() ? nearestRefinery : nullptr);
|
||||
|
||||
ActiveGameState *activeState = (ActiveGameState*)GameManager::getSingleton()->getStateManager()->getAppStateByType(AppStateType::ACTIVE_STATE);
|
||||
Player *mainPlayer = (activeState ? activeState->getPlayer() : nullptr);
|
||||
|
||||
vector<Player*> selectingPlayers = getSelectingPlayers();
|
||||
bool mainPlayerSelecting = (activeState && find(selectingPlayers.begin(), selectingPlayers.end(), mainPlayer) != selectingPlayers.end());
|
||||
|
||||
destructable->displayStats(loadForeground, loadBackground, calcTotalLoad(), capacity, mainPlayer == player && mainPlayerSelecting, Vector2(0, -10));
|
||||
}
|
||||
|
||||
Unit* ResourceRover::getClosestUnit(vector<Structure*> structs){
|
||||
if(structs.empty()) return nullptr;
|
||||
|
||||
int minDistId = -1;
|
||||
|
||||
for(int i = 0; i < structs.size(); i++)
|
||||
if(structs[i]->isComplete()){
|
||||
minDistId = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if(minDistId == -1) return nullptr;
|
||||
|
||||
for(int i = 0; i < structs.size(); i++)
|
||||
if(structs[i]->isComplete() && structs[minDistId]->getPos().getDistanceFrom(pos) > structs[i]->getPos().getDistanceFrom(pos))
|
||||
minDistId = i;
|
||||
|
||||
return structs[minDistId];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
#ifndef RESOURCE_ROVER_H
|
||||
#define RESOURCE_ROVER_H
|
||||
|
||||
#include "vehicle.h"
|
||||
|
||||
#include <util.h>
|
||||
|
||||
namespace battleship{
|
||||
class Structure;
|
||||
class Extractor;
|
||||
|
||||
class ResourceRover : public Vehicle{
|
||||
public:
|
||||
ResourceRover(Player*, int, vb01::Vector3, vb01::Quaternion, Unit::State = Unit::State::STAND_GROUND);
|
||||
~ResourceRover();
|
||||
void update();
|
||||
inline int getLoad(int id){return cargo[id];}
|
||||
inline int calcTotalLoad(){return cargo[0] + cargo[1] + cargo[2];}
|
||||
inline int getCapacity(){return capacity;}
|
||||
inline bool canLoad(){return vb01::getTime() - lastLoadTime > loadRate && calcTotalLoad() < capacity;}
|
||||
inline bool canUnload(int id){return vb01::getTime() - lastLoadTime > loadRate && cargo[id] > 0;}
|
||||
private:
|
||||
void initProperties();
|
||||
void collectRefineds(Order);
|
||||
void loadResources(Structure*, bool);
|
||||
void handleResources(Order);
|
||||
Unit* getClosestUnit(std::vector<Structure*>);
|
||||
|
||||
vb01::s64 lastLoadTime = 0;
|
||||
int cargo[3]{0, 0, 0}, capacity, loadRate, loadSpeed;
|
||||
Extractor *nearestExtractor = nullptr;
|
||||
Unit *nearestRefinery = nullptr;
|
||||
vb01::Node *loadBackground = nullptr, *loadForeground = nullptr;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,27 @@
|
||||
#include "submarine.h"
|
||||
#include "map.h"
|
||||
|
||||
#include <quad.h>
|
||||
|
||||
namespace battleship{
|
||||
using namespace vb01;
|
||||
using namespace std;
|
||||
|
||||
Submarine::Submarine(Player *player, int id, Vector3 pos, Quaternion rot, Unit::State state) : Vehicle(player, id, pos, rot, state){}
|
||||
|
||||
bool Submarine::validateLaunchOrder(){
|
||||
if(!Unit::validateLaunchOrder()) return false;
|
||||
|
||||
vector<Node*> terrainNodes = Map::getSingleton()->getNodeParent()->getChildren();
|
||||
|
||||
for(int i = 1; i < terrainNodes.size(); i++){
|
||||
Vector3 wbPos = terrainNodes[i]->getPosition();
|
||||
Vector3 size = ((Quad*)terrainNodes[i]->getMesh(0))->getSize();
|
||||
|
||||
if(fabs(wbPos.x - pos.x) < .5 * size.x && fabs(wbPos.z - pos.z) < .5 * size.y && pos.y - wbPos.y > -.1)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#ifndef SUBMARINE_H
|
||||
#define SUBMARINE_H
|
||||
|
||||
#include "vehicle.h"
|
||||
|
||||
namespace battleship{
|
||||
class Submarine : public Vehicle{
|
||||
public:
|
||||
Submarine(Player*, int, vb01::Vector3, vb01::Quaternion, Unit::State);
|
||||
private:
|
||||
bool validateLaunchOrder();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,526 @@
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
|
||||
#include <solUtil.h>
|
||||
|
||||
#include <util.h>
|
||||
#include <box.h>
|
||||
#include <quad.h>
|
||||
#include <model.h>
|
||||
#include <quaternion.h>
|
||||
|
||||
#include "pathfinder.h"
|
||||
#include "destructable.h"
|
||||
#include "defConfigs.h"
|
||||
#include "structure.h"
|
||||
#include "vehicle.h"
|
||||
#include "weapon.h"
|
||||
#include "player.h"
|
||||
#include "game.h"
|
||||
#include "map.h"
|
||||
|
||||
using namespace gameBase;
|
||||
using namespace vb01;
|
||||
using namespace std;
|
||||
|
||||
namespace battleship{
|
||||
Vehicle::Vehicle(Player *player, int id, Vector3 pos, Quaternion rot, Unit::State state) : Unit(player, id, pos, rot, state){
|
||||
initProperties();
|
||||
}
|
||||
|
||||
Vehicle::~Vehicle(){
|
||||
removeAllPathpoints();
|
||||
}
|
||||
|
||||
void Vehicle::update(){
|
||||
Unit::update();
|
||||
|
||||
if(garrisonable) model->setVisible(false);
|
||||
}
|
||||
|
||||
void Vehicle::halt(){
|
||||
Unit::halt();
|
||||
removeAllPathpoints();
|
||||
|
||||
patrolPointId = 0;
|
||||
pursuingTarget = false;
|
||||
}
|
||||
|
||||
void Vehicle::startCurrentOrder(){
|
||||
Unit::startCurrentOrder();
|
||||
|
||||
switch(orders[0].type){
|
||||
case Order::TYPE::LAUNCH:
|
||||
case Order::TYPE::EJECT:
|
||||
return;
|
||||
}
|
||||
|
||||
removeAllPathpoints();
|
||||
|
||||
Vector3 targPos = (orders[0].targets[0].unit ? orders[0].targets[0].unit->getPos() : orders[0].targets[0].pos);
|
||||
preparePathpoints(orders[0], targPos);
|
||||
}
|
||||
|
||||
bool Vehicle::validateGarrisonOrder(Order order){
|
||||
Unit *targUnit = (Unit*)order.targets[0].unit;
|
||||
|
||||
for(GarrisonSlot slot : targUnit->getGarrisonSlots())
|
||||
if(!slot.vehicle && slot.category >= garrisonCategory)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Vehicle::turn(float angle) {
|
||||
Quaternion newRot = Quaternion(angle, upVec) * model->getOrientation();
|
||||
model->setOrientation(newRot);
|
||||
rot = newRot;
|
||||
}
|
||||
|
||||
void Vehicle::advance(float speed, MoveDir moveDir) {
|
||||
Vector3 dir;
|
||||
|
||||
switch(moveDir){
|
||||
case MoveDir::FORW:
|
||||
dir = dirVec;
|
||||
break;
|
||||
case MoveDir::LEFT:
|
||||
dir = leftVec;
|
||||
break;
|
||||
case MoveDir::UP:
|
||||
dir = upVec;
|
||||
break;
|
||||
}
|
||||
|
||||
placeAt(pos + dir * speed);
|
||||
}
|
||||
|
||||
void Vehicle::initProperties(){
|
||||
Game *game = Game::getSingleton();
|
||||
vector<int> currTechs = player->getTechnologies();
|
||||
|
||||
sol::table unitTable = generateView()[GameObject::getGameObjTableName()][id + 1];
|
||||
maxTurnAngle = unitTable["maxTurnAngle"]; maxTurnAngle += game->calcAbilFromTech(Ability::Type::MAX_TURN_ANGLE, currTechs, (int)GameObject::type, id);
|
||||
speed = unitTable["speed"]; speed += game->calcAbilFromTech(Ability::Type::SPEED, currTechs, (int)GameObject::type, id);
|
||||
anglePrecision = unitTable["anglePrecision"];
|
||||
garrisonCategory = unitTable["garrisonCategory"];
|
||||
}
|
||||
|
||||
void Vehicle::reinit(){
|
||||
Unit::reinit();
|
||||
initProperties();
|
||||
}
|
||||
|
||||
void Vehicle::arrivedAtPathpoint(bool byPlane, float vertDist){
|
||||
bool orderHasDir = (orders[0].direction != Vector3::VEC_ZERO);
|
||||
float angleToOrderDir = dirVec.getAngleBetween(orders[0].direction);
|
||||
bool destDirWithin = (!orderHasDir || (orderHasDir && angleToOrderDir <= anglePrecision));
|
||||
|
||||
if(pathPoints.size() == 1 && !destDirWithin)
|
||||
turn(calculateRotation(orders[0].direction, angleToOrderDir, maxTurnAngle));
|
||||
|
||||
if(byPlane && (
|
||||
(pathPoints.size() > 1 || (pathPoints.size() == 1 && destDirWithin)) &&
|
||||
(type != UnitType::UNDERWATER || (type == UnitType::UNDERWATER && vertDist < 0.5 * height))
|
||||
)
|
||||
){
|
||||
removePathpoint();
|
||||
}
|
||||
else if(!byPlane && (pathPoints.size() > 1 || (pathPoints.size() == 1 && destDirWithin)))
|
||||
removePathpoint();
|
||||
}
|
||||
|
||||
void Vehicle::moveByTerrainQuads(Vector3 hypVec, float destOffset){
|
||||
Map *map = Map::getSingleton();
|
||||
Quad *terrQuad = (Quad*)map->getNodeParent()->getChild(0)->getMesh(0);
|
||||
int numVertDiv = configData::NUM_SUBDIVS, numHorDiv = configData::NUM_SUBDIVS;
|
||||
Vector3 mapSize = map->getMapSize();
|
||||
Vector2 sqIdsVec = terrQuad->getSubquadIds(numVertDiv, numHorDiv, pos, mapSize);
|
||||
Vector2 sqIdsEndVec = terrQuad->getSubquadIds(numVertDiv, numHorDiv, pathPoints[0], mapSize);
|
||||
|
||||
int sqIds[]{sqIdsVec.x, sqIdsVec.y};
|
||||
vector<Vector3> points = vector<Vector3>{pos};
|
||||
|
||||
// y = ax + b
|
||||
float a = hypVec.z / hypVec.x;
|
||||
float b = pos.z - a * pos.x;
|
||||
|
||||
while(!(sqIds[0] == (int)sqIdsEndVec.x && sqIds[1] == (int)sqIdsEndVec.y)){
|
||||
Vector3 c1 = terrQuad->getSubquadCorner(sqIds[0], sqIds[1], numVertDiv, numHorDiv, true, false); //top left
|
||||
Vector3 c2 = terrQuad->getSubquadCorner(sqIds[0], sqIds[1], numVertDiv, numHorDiv, true, true); //top right
|
||||
Vector3 c3 = terrQuad->getSubquadCorner(sqIds[0], sqIds[1], numVertDiv, numHorDiv, false, false); //bottom left
|
||||
Vector3 c4 = terrQuad->getSubquadCorner(sqIds[0], sqIds[1], numVertDiv, numHorDiv, false, true); //bottom right
|
||||
|
||||
float minX = c1.x, maxX = c2.x, minY = c1.z, maxY = c3.z;
|
||||
bool bottom = (hypVec.z > 0), left = (hypVec.x < 0);
|
||||
float intersecX = (left ? c1.x : c2.x);
|
||||
float intersecY = (bottom ? c3.z : c1.z);
|
||||
|
||||
float xSolY = a * intersecX + b;
|
||||
float ySolX = (hypVec.x != 0 ? (intersecY - b) / a : points[points.size() - 1].x);
|
||||
|
||||
float diff, vertDiff, x, y, z;
|
||||
|
||||
if(minY <= xSolY && xSolY <= maxY){
|
||||
diff = (xSolY - c1.z) / (c3.z - c1.z);
|
||||
vertDiff = (left ? c3.y - c1.y : c4.y - c2.y);
|
||||
|
||||
x = (left ? c1.x : c2.x);
|
||||
y = (left ? c1.y : c2.y) + vertDiff * diff;
|
||||
z = xSolY;
|
||||
|
||||
sqIds[0] += (left ? -1 : 1);
|
||||
}
|
||||
else if(hypVec.x == 0 || (minX <= ySolX && ySolX <= maxX)){
|
||||
diff = (ySolX - c1.x) / (c2.x - c1.x);
|
||||
vertDiff = (bottom ? c4.y - c3.y : c2.y - c1.y);
|
||||
|
||||
x = ySolX;
|
||||
y = (bottom ? c3.y : c1.y) + vertDiff * diff;
|
||||
z = (bottom ? c3.z : c1.z);
|
||||
|
||||
sqIds[1] += (bottom ? 1 : -1);
|
||||
}
|
||||
|
||||
points.push_back(Vector3(x, y, z));
|
||||
}
|
||||
|
||||
points.push_back(pathPoints[0]);
|
||||
|
||||
float movementAmmount = speed, totalDist = 0, eps = .01;
|
||||
Vector3 endPos = pos;
|
||||
|
||||
for(int i = 0; i < points.size() - 1; i++){
|
||||
Vector3 diffVec = (points[i + 1] - points[i]).norm();
|
||||
float dist = points[i].getDistanceFrom(points[i + 1]);
|
||||
float diff = dist;
|
||||
|
||||
if(fabs(totalDist + dist - movementAmmount) > eps)
|
||||
diff = movementAmmount - totalDist;
|
||||
|
||||
endPos += diffVec * diff;
|
||||
totalDist += diff;
|
||||
}
|
||||
|
||||
placeAt(endPos);
|
||||
|
||||
if(fabs(pathPoints[0].x - pos.x) <= destOffset && fabs(pathPoints[0].z - pos.z) <= destOffset)
|
||||
arrivedAtPathpoint(false);
|
||||
}
|
||||
|
||||
void Vehicle::moveByPlane(Vector3 hypVec, float destOffset){
|
||||
Vector3 linDest = Vector3(pathPoints[0].x, pos.y, pathPoints[0].z);
|
||||
|
||||
if(pos.getDistanceFrom(linDest) > destOffset){
|
||||
float dist = pos.getDistanceFrom(linDest);
|
||||
float movementAmmount = (speed > dist ? dist : speed);
|
||||
advance(movementAmmount);
|
||||
}
|
||||
|
||||
float vertDist = fabs(pos.y - pathPoints[0].y);
|
||||
|
||||
if(vertDist > .1){
|
||||
float dist = pos.y - pathPoints[0].y;
|
||||
float movementAmmount = (speed > fabs(dist) ? dist : speed);
|
||||
|
||||
if(dist > 0) movementAmmount *= -1;
|
||||
|
||||
advance(movementAmmount, MoveDir::UP);
|
||||
}
|
||||
|
||||
if(pos.getDistanceFrom(linDest) <= destOffset)
|
||||
arrivedAtPathpoint(true, vertDist);
|
||||
}
|
||||
|
||||
void Vehicle::navigate(float destOffset){
|
||||
if(pathPoints.empty()) return;
|
||||
|
||||
Vector3 hypVec = (pathPoints[0] - pos);
|
||||
Vector3 baseDir = getVecToPlane(pos, hypVec, upVec);
|
||||
if(baseDir == Vector3::VEC_ZERO) baseDir = dirVec;
|
||||
|
||||
float angle = baseDir.getAngleBetween(dirVec);
|
||||
|
||||
if(angle > anglePrecision && pos.getDistanceFrom(pathPoints[0]) > destOffset)
|
||||
turn(calculateRotation(baseDir, angle, maxTurnAngle));
|
||||
else if(type == UnitType::LAND)
|
||||
moveByTerrainQuads(hypVec, destOffset);
|
||||
else
|
||||
moveByPlane(hypVec, destOffset);
|
||||
}
|
||||
|
||||
void Vehicle::move(Order order) {
|
||||
navigate(0.5 * Map::getSingleton()->getCellSize().x);
|
||||
|
||||
if(pathPoints.empty())
|
||||
removeOrder(0);
|
||||
}
|
||||
|
||||
void Vehicle::exitGarrisonable(Vector3 exitPos){
|
||||
placeAt(exitPos);
|
||||
garrisonable->updateGarrison(this, false);
|
||||
garrisonable = nullptr;
|
||||
}
|
||||
|
||||
void Vehicle::enterGarrisonable(){
|
||||
Unit *targUnit = (Unit*)orders[0].targets[0].unit;
|
||||
targUnit->updateGarrison(this, true);
|
||||
|
||||
removeAllPathpoints();
|
||||
removeOrder(0);
|
||||
|
||||
garrisonable = targUnit;
|
||||
pursuingTarget = false;
|
||||
}
|
||||
|
||||
void Vehicle::navigateToTarget(float minDist){
|
||||
if(!pursuingTarget){
|
||||
Vector3 targPos = (orders[0].targets[0].unit ? orders[0].targets[0].unit->getPos() : orders[0].targets[0].pos);
|
||||
preparePathpoints(orders[0], targPos);
|
||||
pursuingTarget = true;
|
||||
|
||||
if(orders[0].type == Order::TYPE::GARRISON) addPathpoint(targPos);
|
||||
}
|
||||
|
||||
navigate(minDist);
|
||||
}
|
||||
|
||||
void Vehicle::garrison(Order order){
|
||||
Unit *targUnit = (Unit*)order.targets[0].unit;
|
||||
float distToGarrisonable = pos.getDistanceFrom(targUnit->getPos()), garrisonDist = Map::getSingleton()->getCellSize().x;
|
||||
|
||||
if(distToGarrisonable > garrisonDist)
|
||||
navigateToTarget(garrisonDist);
|
||||
else
|
||||
enterGarrisonable();
|
||||
}
|
||||
|
||||
void Vehicle::patrol(Order order){
|
||||
if(pathPoints.empty()){
|
||||
patrolPointId = getNextPatrolPointId(order.targets.size());
|
||||
preparePathpoints(order, order.targets[patrolPointId].pos);
|
||||
}
|
||||
|
||||
navigate(.5 * Map::getSingleton()->getCellSize().x);
|
||||
}
|
||||
|
||||
void Vehicle::addPathpoint(Vector3 pointPos){
|
||||
pathPoints.push_back(pointPos);
|
||||
|
||||
Box *b = new Box(Vector3::VEC_IJK);
|
||||
b->setMaterial(player->getColorMaterial());
|
||||
|
||||
Node *n = new Node(pointPos);
|
||||
n->attachMesh(b);
|
||||
n->setVisible(Game::getSingleton()->isDebug());
|
||||
Root::getSingleton()->getRootNode()->attachChild(n);
|
||||
debugPathPoints.push_back(n);
|
||||
}
|
||||
|
||||
//TODO allow ships to attack land targets and vice versa
|
||||
//TODO recursively search for vacant dest cell neibourghss
|
||||
bool Vehicle::canReachTarget(Vector3 destPos, int &source, int &dest){
|
||||
Map *map = Map::getSingleton();
|
||||
vector<Map::Cell> &cells = map->getCells();
|
||||
|
||||
source = map->getCellId(pos);
|
||||
bool ship = (type == UnitType::UNDERWATER || type == UnitType::SEA_LEVEL);
|
||||
bool waterVehCanMove = (ship && cells[source].type == Map::Cell::WATER);
|
||||
bool landVehCanMove = (type == UnitType::LAND && cells[source].type == Map::Cell::LAND);
|
||||
|
||||
if(type != UnitType::HOVER && !(waterVehCanMove || landVehCanMove)) return false;
|
||||
|
||||
dest = map->getCellId(destPos);
|
||||
|
||||
if(type != UnitType::UNDERWATER && type == UnitType::SEA_LEVEL && fabs(destPos.y - cells[dest].pos.y) > .1) return false;
|
||||
|
||||
if(cells[dest].blockedBy){
|
||||
vector<int> surrCellIds = map->getSurroundingCells(cells[dest].pos, 1);
|
||||
|
||||
for(int scid : surrCellIds){
|
||||
if(!cells[scid].blockedBy)
|
||||
switch(type){
|
||||
case UnitType::HOVER:
|
||||
dest = scid;
|
||||
return true;
|
||||
case UnitType::LAND:
|
||||
if(cells[scid].type == Map::Cell::LAND){
|
||||
dest = scid;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case UnitType::SEA_LEVEL:
|
||||
case UnitType::UNDERWATER:
|
||||
if(cells[scid].type == Map::Cell::WATER){
|
||||
dest = scid;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
else return true;
|
||||
}
|
||||
|
||||
bool Vehicle::truncatePath(Order &order, vector<int> &path, Vector3 destPos, bool appendDestPos){
|
||||
bool pathTruncated = false;
|
||||
bool ship = (type == UnitType::UNDERWATER || type == UnitType::SEA_LEVEL);
|
||||
vector<Map::Cell> &cells = Map::getSingleton()->getCells();
|
||||
|
||||
for(int i = 1; i < path.size(); i++){
|
||||
if((ship && cells[path[i]].type != Map::Cell::WATER) || (order.type != Order::TYPE::GARRISON && type == UnitType::LAND && cells[path[i]].type != Map::Cell::LAND)){
|
||||
path = vector<int>(path.begin(), path.begin() + i);
|
||||
order.targets[0].unit = nullptr;
|
||||
order.targets[0].pos = cells[path[i - 1]].pos;
|
||||
pathTruncated = true;
|
||||
break;
|
||||
}
|
||||
else if(order.type == Order::TYPE::GARRISON && type == UnitType::LAND && cells[path[i]].type != Map::Cell::LAND && path.size() - 1 != i)
|
||||
return false;
|
||||
}
|
||||
|
||||
for(int p : path) addPathpoint(cells[p].pos);
|
||||
|
||||
if(order.targets[0].unit && !pathTruncated){
|
||||
GameObject *targObj = order.targets[0].unit;
|
||||
|
||||
for(int i = path.size() - 1; i >= 0; i--){
|
||||
Vector3 targPos = targObj->getPos();
|
||||
Vector3 pointDir = cells[path[i]].pos - targPos;
|
||||
pointDir = Vector3(pointDir.x, 0, pointDir.z);
|
||||
|
||||
float dirAngle = targObj->getDirVec().getAngleBetween(pointDir.norm());
|
||||
if(dirAngle > PI / 2) dirAngle = PI - dirAngle;
|
||||
|
||||
float pointDist = pointDir.getLength();
|
||||
|
||||
float length = targObj->getLength();
|
||||
float lengthComp = pointDist * cos(dirAngle);
|
||||
bool withinLength = (.5 * length >= lengthComp);
|
||||
|
||||
float width = targObj->getWidth();
|
||||
float widthComp = pointDist * sin(dirAngle);
|
||||
bool withinWidth = (.5 * width >= widthComp);
|
||||
|
||||
if(!(withinLength && withinWidth)){
|
||||
float a1 = atan((.5 * width) / (.5 * length));
|
||||
float a2 = atan((.5 * length) / (.5 * width));
|
||||
|
||||
float leftAngle = targObj->getLeftVec().getAngleBetween(pointDir.norm());
|
||||
if(leftAngle > PI / 2) leftAngle = PI - leftAngle;
|
||||
|
||||
float dist;
|
||||
|
||||
if(dirAngle <= a1) dist = (.5 * length) / cos(dirAngle);
|
||||
else if(leftAngle <= a2) dist = (.5 * width) / cos(leftAngle);
|
||||
|
||||
addPathpoint(targPos + pointDir.norm() * dist);
|
||||
pathTruncated = true;
|
||||
|
||||
break;
|
||||
}
|
||||
else removePathpoint(pathPoints.size() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
if(appendDestPos && !pathTruncated)
|
||||
addPathpoint(destPos);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Vehicle::preparePathpoints(Order &order, Vector3 destPos, bool appendDestPos){
|
||||
removeAllPathpoints();
|
||||
|
||||
vector<Map::Cell> &cells = Map::getSingleton()->getCells();
|
||||
int source, dest;
|
||||
|
||||
if(!canReachTarget(destPos, source, dest)) return;
|
||||
|
||||
vector<float> heurs;
|
||||
Pathfinder *pf = Pathfinder::getSingleton();
|
||||
vector<int> path = pf->findPath(cells, heurs, source, dest, (int)type);
|
||||
|
||||
if(path.empty() || !truncatePath(order, path, destPos, appendDestPos)) return;
|
||||
|
||||
path.erase(path.begin());
|
||||
}
|
||||
|
||||
void Vehicle::removePathpoint(int i){
|
||||
Node *rootNode = Root::getSingleton()->getRootNode();
|
||||
Node *debugPathPointNode = debugPathPoints[i];
|
||||
rootNode->dettachChild(debugPathPointNode);
|
||||
|
||||
Mesh *mesh = debugPathPointNode->getMesh(0);
|
||||
mesh->setMaterial(nullptr);
|
||||
debugPathPoints.erase(debugPathPoints.begin() + i);
|
||||
delete debugPathPointNode;
|
||||
|
||||
pathPoints.erase(pathPoints.begin() + i);
|
||||
|
||||
if(pathPoints.empty()) pursuingTarget = false;
|
||||
}
|
||||
|
||||
void Vehicle::removeAllPathpoints(){
|
||||
while(!pathPoints.empty())
|
||||
removePathpoint();
|
||||
}
|
||||
|
||||
void Vehicle::attack(Order order){
|
||||
int prevNumOrders = orders.size();
|
||||
Unit::attack(order);
|
||||
int currNumOrders = orders.size();
|
||||
|
||||
if(prevNumOrders != currNumOrders) return;
|
||||
|
||||
Order::Target target = order.targets[0];
|
||||
Vector3 targVec = (target.unit ? target.unit->getPos() : target.pos) - pos;
|
||||
float distToTarg = targVec.getLength();
|
||||
|
||||
vector<Weapon*> attackWeapons = getWeaponsByOrder(Order::TYPE::ATTACK);
|
||||
Weapon *weapon = attackWeapons[0];
|
||||
|
||||
for(Weapon *w : attackWeapons)
|
||||
if(w->getMaxRange() > weapon->getMaxRange())
|
||||
weapon = w;
|
||||
|
||||
float minDist = weapon->getMaxRange();
|
||||
|
||||
if(order.playerAssigned || (!order.playerAssigned && state == Unit::State::CHASE)){
|
||||
if(distToTarg > minDist)
|
||||
navigateToTarget(.5 * Map::getSingleton()->getCellSize().x);
|
||||
else
|
||||
pursuingTarget = false;
|
||||
}
|
||||
else if(!order.playerAssigned && state == Unit::State::STAND_GROUND && distToTarg > minDist){
|
||||
removeOrder(0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void Vehicle::build(Order order){
|
||||
if(pathPoints.empty()){
|
||||
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->isComplete() && player->getResource(ResourceType::REFINEDS) >= costRate && getTime() - lastBuildTime > buildRate){
|
||||
structure->incrementBuildStatus();
|
||||
player->updateResource(ResourceType::REFINEDS, -costRate, true);
|
||||
lastBuildTime = getTime();
|
||||
}
|
||||
else if(structure->isComplete()){
|
||||
removeOrder(0);
|
||||
player->incStructuresBuilt();
|
||||
}
|
||||
}
|
||||
else navigate(0.5 * Map::getSingleton()->getCellSize().x);
|
||||
}
|
||||
|
||||
void Vehicle::select(){
|
||||
if(!garrisonable)
|
||||
Unit::select();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
#ifndef VEHICLE_H
|
||||
#define VEHICLE_H
|
||||
|
||||
#include "unit.h"
|
||||
|
||||
namespace vb01{
|
||||
class Material;
|
||||
}
|
||||
|
||||
namespace battleship{
|
||||
class Vehicle : public Unit{
|
||||
public:
|
||||
Vehicle(Player*, int, vb01::Vector3, vb01::Quaternion, Unit::State);
|
||||
~Vehicle();
|
||||
virtual void update();
|
||||
void move(Order);
|
||||
void exitGarrisonable(vb01::Vector3);
|
||||
inline Unit* getGarrisonable(){return garrisonable;}
|
||||
inline int getGarrisonCategory(){return garrisonCategory;}
|
||||
private:
|
||||
Unit *garrisonable = nullptr;
|
||||
int patrolPointId = 0, garrisonCategory;
|
||||
float speed, maxTurnAngle, anglePrecision;
|
||||
std::vector<vb01::Node*> debugPathPoints;
|
||||
vb01::s64 lastBuildTime = 0;
|
||||
|
||||
inline int getNextPatrolPointId(int numPoints) {return patrolPointId == numPoints - 1 ? 0 : patrolPointId + 1;}
|
||||
bool canReachTarget(vb01::Vector3, int&, int&);
|
||||
bool truncatePath(Order&, std::vector<int>&, vb01::Vector3, bool);
|
||||
void startCurrentOrder();
|
||||
bool validateGarrisonOrder(Order);
|
||||
void enterGarrisonable();
|
||||
void halt();
|
||||
void turn(float);
|
||||
void advance(float, MoveDir = MoveDir::FORW);
|
||||
void addPathpoint(vb01::Vector3);
|
||||
void removePathpoint(int = 0);
|
||||
void removeAllPathpoints();
|
||||
void select();
|
||||
void reinit();
|
||||
protected:
|
||||
std::vector<vb01::Vector3> pathPoints;
|
||||
bool pursuingTarget = false;
|
||||
|
||||
void arrivedAtPathpoint(bool, float = 0);
|
||||
void moveByTerrainQuads(vb01::Vector3, float);
|
||||
void moveByPlane(vb01::Vector3, float);
|
||||
void navigate(float = 0.);
|
||||
void navigateToTarget(float);
|
||||
void preparePathpoints(Order&, vb01::Vector3, bool = false);
|
||||
virtual void attack(Order);
|
||||
virtual void build(Order);
|
||||
void garrison(Order);
|
||||
void patrol(Order);
|
||||
virtual void initProperties();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,367 @@
|
||||
#include <node.h>
|
||||
#include <box.h>
|
||||
#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 "structure.h"
|
||||
#include "gameObjectFactory.h"
|
||||
#include "projectile.h"
|
||||
|
||||
namespace battleship{
|
||||
using namespace std;
|
||||
using namespace vb01;
|
||||
using namespace gameBase;
|
||||
|
||||
Weapon::Weapon(Unit *u, sol::table unitTable, int wid) :
|
||||
unit(u),
|
||||
id(wid),
|
||||
rateOfFire(unitTable["weapons"][wid + 1]["rateOfFire"]),
|
||||
damage(unitTable["weapons"][wid + 1]["damage"].get_or(0))
|
||||
{
|
||||
sol::table weaponTable = unitTable["weapons"][wid + 1];
|
||||
maxRange = weaponTable["maxRange"];
|
||||
maxFireAngle = weaponTable["maxFireAngle"].get_or(.1);
|
||||
orderType = (Order::TYPE)weaponTable["orderType"];
|
||||
|
||||
sol::optional<float> typeOpt = unitTable["weapons"][wid + 1]["type"];
|
||||
|
||||
if(typeOpt != sol::nullopt)
|
||||
type = (Type)unitTable["weapons"][wid + 1]["type"];
|
||||
|
||||
sol::optional<sol::table> fireDirOpt = weaponTable["fireDir"];
|
||||
|
||||
if(fireDirOpt != sol::nullopt){
|
||||
sol::table fireDirTbl = weaponTable["fireDir"];
|
||||
fireDir = Vector3((float)fireDirTbl["x"], (float)fireDirTbl["y"], (float)fireDirTbl["z"]);
|
||||
}
|
||||
|
||||
initTargetData(targetUnits, weaponTable, "targetUnits", vector<int>{(int)UnitType::UNDERWATER, (int)UnitType::SEA_LEVEL, (int)UnitType::HOVER, (int)UnitType::LAND});
|
||||
initTargetData(targetProjectiles, weaponTable, "targetProjeciles", vector<int>{(int)ProjectileClass::SHELL, (int)ProjectileClass::CRUISE_MISSILE, (int)ProjectileClass::MISSILE, (int)ProjectileClass::TORPEDO, (int)ProjectileClass::DEPTH_CHARGE});
|
||||
|
||||
initProjectileData(weaponTable);
|
||||
initNodes(weaponTable);
|
||||
|
||||
sol::optional<sol::table> fireFxOpt = weaponTable["fireFx"];
|
||||
|
||||
if(fireFxOpt != sol::nullopt){
|
||||
FxManager *fxManager = FxManager::getSingleton();
|
||||
fireFx = fxManager->initFx(weaponTable["fireFx"], unit->getModel(), true);
|
||||
|
||||
if(fireFx) fxManager->addFx(fireFx);
|
||||
}
|
||||
}
|
||||
|
||||
void Weapon::initTargetData(vector<int> &targetVec, sol::table weaponTable, string tblKey, vector<int> allValues){
|
||||
sol::optional<sol::table> unitTblOpt = weaponTable[tblKey];
|
||||
|
||||
if(unitTblOpt != sol::nullopt){
|
||||
sol::table tbl = weaponTable[tblKey];
|
||||
int tblSize = tbl.size();
|
||||
|
||||
for(int i = 0; i < tblSize; i++)
|
||||
targetVec.push_back((int)tbl[i + 1]);
|
||||
}
|
||||
else targetVec = allValues;
|
||||
}
|
||||
|
||||
void Weapon::initNodes(sol::table weaponTable){
|
||||
sol::optional<sol::table> nodesTblOpt = weaponTable["nodes"];
|
||||
|
||||
if(nodesTblOpt == sol::nullopt) return;
|
||||
|
||||
sol::table tbl = weaponTable["nodes"];
|
||||
int numNodes = tbl.size();
|
||||
|
||||
for(int i = 0; i < numNodes; i++){
|
||||
sol::table nodeTbl = weaponTable["nodes"][i + 1];
|
||||
float rotSpeed = nodeTbl["rotationSpeed"];
|
||||
bool vertical = nodeTbl["vertical"];
|
||||
|
||||
sol::optional<sol::table> angleConstrOpt = nodeTbl["angleConstraints"];
|
||||
float minAngle, maxAngle;
|
||||
|
||||
if(angleConstrOpt != sol::nullopt){
|
||||
sol::table acTbl = nodeTbl["angleConstraints"];
|
||||
minAngle = acTbl["min"];
|
||||
maxAngle = acTbl["max"];
|
||||
}
|
||||
else{
|
||||
minAngle = 0;
|
||||
maxAngle = (vertical ? PI / 2 : 0);
|
||||
}
|
||||
|
||||
string name = nodeTbl["name"];
|
||||
Node *node = unit->getModel()->findDescendant(name, true);
|
||||
|
||||
components.push_back(Component(node, rotSpeed, minAngle, maxAngle, vertical));
|
||||
}
|
||||
|
||||
//using the last node to determine a weapon's init direction
|
||||
Node *node = components[components.size() - 1].node;
|
||||
Vector3 p0 = unit->getModel()->globalToLocalPosition(node->localToGlobalPosition(Vector3::VEC_ZERO));
|
||||
Vector3 p1 = unit->getModel()->globalToLocalPosition(node->localToGlobalPosition(Vector3::VEC_K));
|
||||
initUnitSpaceDir = (p1 - p0).norm();
|
||||
}
|
||||
|
||||
void Weapon::initProjectileData(sol::table weaponTable){
|
||||
string projTableKey = "projectile";
|
||||
sol::optional<sol::table> proj = weaponTable[projTableKey];
|
||||
|
||||
if(proj == sol::nullopt) return;
|
||||
|
||||
projId = weaponTable[projTableKey]["id"];
|
||||
sol::table projTable = generateView()["projectiles"];
|
||||
ProjectileClass pc = (ProjectileClass)projTable[projId + 1]["projectileClass"];
|
||||
|
||||
if(pc == ProjectileClass::CRUISE_MISSILE){
|
||||
minRange = 0;
|
||||
float rotAngle = projTable[projId + 1]["rotAngle"];
|
||||
float speed = projTable[projId + 1]["speed"];
|
||||
float base = PI / 2, alpha = 0;
|
||||
|
||||
while(base - alpha > .001){
|
||||
minRange += speed * sin(alpha);
|
||||
alpha += (base - alpha > rotAngle ? rotAngle : base - alpha);
|
||||
}
|
||||
|
||||
minRange *= 2;
|
||||
}
|
||||
|
||||
projPar = unit->getModel();
|
||||
sol::optional<string> parNameOpt = weaponTable[projTableKey]["parent"];
|
||||
|
||||
if(parNameOpt != sol::nullopt){
|
||||
string parName = weaponTable[projTableKey]["parent"];
|
||||
projPar = unit->getModel()->findDescendant(parName, true);
|
||||
}
|
||||
|
||||
sol::table posTable = weaponTable[projTableKey]["pos"];
|
||||
projPos = Vector3(posTable["x"], posTable["y"], posTable["z"]);
|
||||
sol::table rotTable = weaponTable[projTableKey]["rot"];
|
||||
projRot = Quaternion(rotTable["w"], rotTable["x"], rotTable["y"], rotTable["z"]);
|
||||
}
|
||||
|
||||
Weapon::~Weapon(){
|
||||
FxManager *fm = FxManager::getSingleton();
|
||||
|
||||
if(fireFx) fm->removeFx(fireFx);
|
||||
}
|
||||
|
||||
//TODO replace unit pos with absolute weapon pos for withinAngle
|
||||
void Weapon::update(){
|
||||
if(unit->getCondition() != Unit::Condition::ABLE) return;
|
||||
|
||||
int numOrders = unit->getNumOrders();
|
||||
int ordTp = (numOrders > 0 ? (int)unit->getOrder(0).type : -1);
|
||||
GameObject *targDestruct = (ordTp != -1 ? unit->getOrder(0).targets[0].unit : nullptr);
|
||||
|
||||
bool isWeaponPos = (!components.empty() && components[0].node);
|
||||
Vector3 refPos = (isWeaponPos ? components[0].node->localToGlobalPosition(Vector3::VEC_ZERO) : unit->getPos());
|
||||
|
||||
if(ordTp == (int)orderType){
|
||||
Vector3 dirVec;
|
||||
|
||||
if(!isWeaponPos)
|
||||
dirVec = (fireDir.x * unit->getLeftVec() + fireDir.y * unit->getUpVec() + fireDir.z * unit->getDirVec()).norm();
|
||||
else
|
||||
dirVec = components[components.size() - 1].node->getGlobalAxis(2);
|
||||
|
||||
bool aimedAtTarget = false;
|
||||
|
||||
if(targDestruct && targDestruct->getHitbox()){
|
||||
vector<RayCaster::CollisionResult> res = RayCaster::cast(refPos, dirVec, targDestruct->getHitbox());
|
||||
|
||||
if(res.empty()) return;
|
||||
|
||||
float targDist = refPos.getDistanceFrom(res[0].pos);
|
||||
aimedAtTarget = (minRange <= targDist && targDist <= maxRange);
|
||||
}
|
||||
else{
|
||||
Vector3 targPos = (targDestruct ? targDestruct->getPos() : unit->getOrder(0).targets[0].pos);
|
||||
float targDist = refPos.getDistanceFrom(targPos);
|
||||
bool withinRange = (minRange <= targDist && targDist <= maxRange);
|
||||
bool withinAngle = (dirVec.getAngleBetween((targPos - refPos).norm()) <= maxFireAngle);
|
||||
aimedAtTarget = withinRange && withinAngle;
|
||||
}
|
||||
|
||||
if(aimedAtTarget) fire(unit->getOrder(0));
|
||||
}
|
||||
else{
|
||||
Vector3 dir = (
|
||||
initUnitSpaceDir.x * unit->getLeftVec() +
|
||||
initUnitSpaceDir.y * unit->getUpVec() +
|
||||
initUnitSpaceDir.z * unit->getDirVec()
|
||||
).norm();
|
||||
trackTarget(refPos + dir);
|
||||
}
|
||||
}
|
||||
|
||||
void Weapon::useFx(FxManager::Fx *fx, Vector3 targPos, bool fire){
|
||||
if(fx && !fire) FxManager::getSingleton()->addFx(fx);
|
||||
else if(!fx) return;
|
||||
|
||||
fx->toggleComponents(true);
|
||||
|
||||
Vector3 plCol = unit->getPlayer()->getColor();
|
||||
|
||||
for(int i = 0; i < fx->components.size(); i++){
|
||||
FxManager::Fx::Component &comp = fx->components[i];
|
||||
|
||||
if(!comp.vfx) continue;
|
||||
|
||||
if(fire && ((Node*)comp.comp)->getName() == "laser"){
|
||||
Vector3 initPos = unit->getPos(), laserDir = targPos - initPos;
|
||||
float targDist = laserDir.getLength();
|
||||
float angle = unit->getDirVec().getAngleBetween(laserDir);
|
||||
Vector3 crossProd = unit->getDirVec().cross(laserDir);
|
||||
|
||||
Node *compNode = (Node*)comp.comp;
|
||||
compNode->setOrientation(Quaternion(angle, crossProd) * compNode->getOrientation());
|
||||
|
||||
Box *box = (Box*)compNode->getMesh(0);
|
||||
Vector3 size = box->getSize();
|
||||
box->setSize(Vector3(size.x, size.y, targDist));
|
||||
box->updateVerts(box->getMeshBase());
|
||||
box->getMaterial()->setVec4Uniform("diffuseColor", Vector4(plCol.x, plCol.y, plCol.z, 1));
|
||||
|
||||
compNode->setPosition(comp.pos + .5 * targDist * Vector3::VEC_K);
|
||||
}
|
||||
else if(!fire)
|
||||
((Node*)comp.comp)->setPosition(targPos);
|
||||
}
|
||||
}
|
||||
|
||||
void Weapon::updateTarget(GameObject *target){
|
||||
Destructable *destr = target->getDestructable();
|
||||
|
||||
switch(type){
|
||||
case Type::FREEZER:
|
||||
if(target->getType() == GameObject::Type::UNIT && ((Unit*)target)->getUnitClass() == UnitClass::ICE_SHEET)
|
||||
((Structure*)target)->incrementBuildStatus();
|
||||
else
|
||||
destr->setFreezeStatus(destr->getFreezeStatus() + 1);
|
||||
|
||||
break;
|
||||
default:
|
||||
destr->takeDamage(damage);
|
||||
break;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
GameObject *target = order.targets[0].unit;
|
||||
Vector3 targPos = (target ? target->getPos() : order.targets[0].pos);
|
||||
|
||||
if(fireFx) useFx(fireFx, targPos, true);
|
||||
|
||||
if(projId == -1){
|
||||
sol::table weaponTbl = generateView()["units"][unit->getId() + 1]["weapons"][id + 1];
|
||||
FxManager *fxManager = FxManager::getSingleton();
|
||||
string fxKey = "unitHitFx";
|
||||
|
||||
if(target) updateTarget(target);
|
||||
else{
|
||||
Map *map = Map::getSingleton();
|
||||
Map::Cell::Type cellType = map->getCells()[map->getCellId(targPos)].type;
|
||||
fxKey = (cellType == Map::Cell::Type::LAND ? "landHitFx" : "waterHitFx");
|
||||
}
|
||||
|
||||
sol::optional<sol::table> hitFxOpt = weaponTbl[fxKey];
|
||||
|
||||
if(hitFxOpt != sol::nullopt){
|
||||
sol::table fxTbl = weaponTbl[fxKey];
|
||||
int numFx = fxTbl.size();
|
||||
|
||||
if(numFx > 0) useFx(fxManager->initFx(weaponTbl[fxKey], unit->getModel(), false), targPos, false);
|
||||
}
|
||||
}
|
||||
else{
|
||||
Quaternion r = projPar->localToGlobalOrientation(projRot);
|
||||
Vector3 p = projPar->localToGlobalPosition(projPos);
|
||||
unit->getPlayer()->addProjectile(GameObjectFactory::createProjectile(unit, projId, p, r));
|
||||
}
|
||||
|
||||
lastFireTime = getTime();
|
||||
}
|
||||
|
||||
//TODO improve to allow for vertical alignment
|
||||
void Weapon::trackTarget(Vector3 targPos){
|
||||
for(Component &component : components){
|
||||
bool isWeaponPos = components[0].node;
|
||||
Vector3 weaponPos = (isWeaponPos ? components[0].node->localToGlobalPosition(Vector3::VEC_ZERO) : unit->getPos());
|
||||
|
||||
Vector3 unitUp = unit->getUpVec();
|
||||
Vector3 targDir = (targPos - weaponPos).norm();
|
||||
Vector3 nodeDir = component.node->getGlobalAxis(2);
|
||||
|
||||
Vector3 rotAxis;
|
||||
float rotAngle;
|
||||
|
||||
if(component.vertical){
|
||||
float angle1 = unitUp.getAngleBetween(targDir);
|
||||
float angle2 = unitUp.getAngleBetween(nodeDir);
|
||||
float angleDiff = angle1 - angle2;
|
||||
rotAngle = (component.rotSpeed < fabs(angleDiff) ? component.rotSpeed : fabs(angleDiff)) * (angleDiff > 0 ? 1 : -1);
|
||||
|
||||
if(PI / 2 - (angle2 + rotAngle) > component.maxAngle)
|
||||
rotAngle = PI / 2 - component.maxAngle - angle2;
|
||||
else if(PI / 2 - (angle2 + rotAngle) < component.minAngle)
|
||||
rotAngle = PI / 2 - component.minAngle - angle2;
|
||||
|
||||
rotAngle = (fabs(rotAngle) > .001 ? rotAngle : 0);
|
||||
rotAxis = Vector3::VEC_I;
|
||||
}
|
||||
else{
|
||||
rotAxis = Vector3::VEC_J;
|
||||
Vector3 targDirProj = getVecToPlane(weaponPos, targDir, unitUp);
|
||||
Vector3 nodeLeft = component.node->getGlobalAxis(0);
|
||||
float angle = nodeDir.getAngleBetween(targDirProj);
|
||||
bool negate = (nodeLeft.getAngleBetween(targDirProj) > PI / 2);
|
||||
rotAngle = (negate ? -1 : 1) * (component.rotSpeed < angle ? component.rotSpeed : angle);
|
||||
|
||||
if(!(component.minAngle == 0 && component.maxAngle == 0)){
|
||||
Vector3 refDir = (
|
||||
initUnitSpaceDir.x * unit->getLeftVec() +
|
||||
initUnitSpaceDir.y * unit->getUpVec() +
|
||||
initUnitSpaceDir.z * unit->getDirVec()
|
||||
).norm();
|
||||
float angle2 = refDir.getAngleBetween(nodeDir);
|
||||
|
||||
bool dirOnLeft = (nodeLeft.getAngleBetween(refDir) > PI / 2);
|
||||
|
||||
if(!dirOnLeft && -angle2 + rotAngle < component.minAngle)
|
||||
rotAngle = component.minAngle + angle2;
|
||||
else if(dirOnLeft && angle2 + rotAngle > component.maxAngle)
|
||||
rotAngle = component.maxAngle - angle2;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Quaternion rot = Quaternion(rotAngle, rotAxis) * component.node->getOrientation();
|
||||
component.node->setOrientation(rot);
|
||||
}
|
||||
}
|
||||
|
||||
bool Weapon::canAttackTarget(int objType, int typeOrClass){
|
||||
switch((GameObject::Type)objType){
|
||||
case GameObject::Type::UNIT:
|
||||
return (find(targetUnits.begin(), targetUnits.end(), typeOrClass) != targetUnits.end());
|
||||
case GameObject::Type::PROJECTILE:
|
||||
return (find(targetProjectiles.begin(), targetProjectiles.end(), typeOrClass) != targetProjectiles.end());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
#ifndef WEAPON_H
|
||||
#define WEAPON_H
|
||||
|
||||
#include "unit.h"
|
||||
|
||||
#include <vector>
|
||||
#include <util.h>
|
||||
#include <quaternion.h>
|
||||
|
||||
#include <solUtil.h>
|
||||
|
||||
namespace vb01{
|
||||
class Node;
|
||||
}
|
||||
|
||||
namespace battleship{
|
||||
class FxManager;
|
||||
class GameObject;
|
||||
|
||||
class Weapon{
|
||||
public:
|
||||
enum class Type{DAMAGE = 0, FREEZER = 1};
|
||||
|
||||
struct Component{
|
||||
vb01::Node *node = nullptr;
|
||||
vb01::Vector3 initUnitSpaceDir;
|
||||
float rotSpeed, minAngle, maxAngle;
|
||||
bool vertical;
|
||||
|
||||
Component(vb01::Node *n, float rs, float min, float max, bool v) :
|
||||
node(n),
|
||||
rotSpeed(rs),
|
||||
minAngle(min),
|
||||
maxAngle(max),
|
||||
vertical(v) {}
|
||||
};
|
||||
|
||||
Weapon(Unit*, sol::table, int);
|
||||
~Weapon();
|
||||
virtual void update();
|
||||
virtual void fire(Order);
|
||||
void trackTarget(vb01::Vector3);
|
||||
bool canAttackTarget(int, int);
|
||||
inline int getProjectileId(){return projId;}
|
||||
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;}
|
||||
inline Type getType(){return type;}
|
||||
inline Order::TYPE getOrderType(){return orderType;}
|
||||
private:
|
||||
Unit *unit = nullptr;
|
||||
Order::TYPE orderType;
|
||||
int id, projId = -1, damage = 0;
|
||||
std::vector<int> targetUnits, targetProjectiles;
|
||||
float minRange = 0, maxRange, maxFireAngle;
|
||||
vb01::s64 lastFireTime = 0;
|
||||
FxManager::Fx *fireFx = nullptr;
|
||||
vb01::Quaternion projRot;
|
||||
vb01::Vector3 projPos, initUnitSpaceDir, fireDir = vb01::Vector3::VEC_K;
|
||||
vb01::Node *projPar = nullptr;
|
||||
static std::string LASER_FLAG;
|
||||
Type type = Type::DAMAGE;
|
||||
|
||||
void initTargetData(std::vector<int>&, sol::table, std::string, std::vector<int>);
|
||||
void initProjectileData(sol::table);
|
||||
void initNodes(sol::table);
|
||||
void useFx(FxManager::Fx*, vb01::Vector3, bool);
|
||||
inline bool canFire(){return vb01::getTime() - lastFireTime > rateOfFire;}
|
||||
protected:
|
||||
int rateOfFire;
|
||||
std::vector<Component> components;
|
||||
|
||||
virtual void updateTarget(GameObject*);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user