#include #include #include #include #include #include #include #include #include #include #include #include #include #include "activeGameState.h" #include "inGameAppState.h" #include "defConfigs.h" #include "structure.h" #include "util.h" #include "tooltip.h" #include "unitFrameController.h" #include "cameraController.h" using namespace vb01; using namespace vb01Gui; using namespace std; namespace battleship{ using namespace configData; using namespace gameBase; ActiveGameState::ActiveGameState(GuiAppState *guiState, int playerId) : AbstractAppState( AppStateType::ACTIVE_STATE, configData::calcSumBinds(AppStateType::ACTIVE_STATE, true), configData::calcSumBinds(AppStateType::ACTIVE_STATE, false), GameManager::getSingleton()->getPath() + "Scripts/options.lua"){ this->guiState = guiState; this->playerId = playerId; mainPlayer = Map::getSingleton()->getPlayer(playerId); initDragbox(); initDepthText(); } ActiveGameState::~ActiveGameState() { } 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)); dragbox = new Quad(Vector3::VEC_ZERO, false); dragbox->setMaterial(mat); dragboxNode = new Node(); dragboxNode->attachMesh(dragbox); root->getGuiNode()->attachChild(dragboxNode); } void ActiveGameState::initDepthText(){ Root *root = Root::getSingleton(); Text *t = new Text(GameManager::getSingleton()->getPath() + "Fonts/batang.ttf", L"depth: "); Material *tm = new Material(root->getLibPath() + "text"); tm->addBoolUniform("texturingEnabled", false); tm->addVec4Uniform("diffuseColor", Vector4(1, 1, 1, 1)); t->setMaterial(tm); textNode = new Node(Vector3(0, 100, 0)); textNode->addText(t); depth = 1; } void ActiveGameState::onAttached() { AbstractAppState::onAttached(); Root::getSingleton()->getGuiNode()->attachChild(textNode); } void ActiveGameState::onDettached() { AbstractAppState::onDettached(); Root::getSingleton()->getGuiNode()->attachChild(textNode); } void ActiveGameState::update() { textNode->getText(0)->setText(L"Depth: " + to_wstring(depth)); if (isSelectionBox) updateSelectionBox(); dragboxNode->setVisible(isSelectionBox); renderUnits(); CameraController *camCtr = CameraController::getSingleton(); if(!camCtr->isLookingAround()) camCtr->updateCameraPosition(); UnitFrameController *ufCtr = UnitFrameController::getSingleton(); if(ufCtr->isPlacingFrames()) ufCtr->update(); } void ActiveGameState::deselectUnits(){ mainPlayer->deselectUnits(); UnitFrameController *ufCtr = UnitFrameController::getSingleton(); ufCtr->removeUnitFrames(); ufCtr->setPlacingFrames(false); } //TODO fix fog of war for hostile units void ActiveGameState::renderUnits() { vector units; for (Player *p : Map::getSingleton()->getPlayers()) for (Unit *u : p->getUnits()) units.push_back(u); for (Unit *u : units) { if (u->getPlayer() == mainPlayer){ Vector3 selectionBoxOrigin = dragboxNode->getPosition(); Vector3 selectionBoxEnd = selectionBoxOrigin + dragbox->getSize(); Vector2 pos = u->getScreenPos(); if(isSelectionBox && pos.x >= selectionBoxOrigin.x && pos.x <= selectionBoxEnd.x && pos.y >= selectionBoxOrigin.y && pos.y <= selectionBoxEnd.y){ if(!u->isSelected()){ if(!shiftPressed) deselectUnits(); mainPlayer->selectUnit(u); u->toggleSelection(true); } } u->getNode()->setVisible(true); } else{ Vector3 rendUnPos = u->getPos(); rendUnPos.y = 0; for (int i = 0; i < units.size() && units[i] != u && units[i]->getPlayer() == mainPlayer; i++) { Vector3 compUnPos = units[i]->getPos(); compUnPos.y = 0; float dist = compUnPos.getDistanceFrom(rendUnPos); u->getNode()->setVisible(dist <= units[i]->getLineOfSight() || isInLineOfSight(compUnPos, units[i]->getLineOfSight(), u)); } } } } bool ActiveGameState::isInLineOfSight(Vector3 center, float radius, Unit *u) { bool inside = false; for (int i = 0; i < 4 && !inside; i++) if (center.getDistanceFrom(u->getCorner(i)) <= radius){ inside = true; break; } return inside; } void ActiveGameState::updateSelectionBox() { Vector2 mousePos = getCursorPos(), selectionBoxOrigin, selectionBoxEnd; if (mousePos.x >= clickPoint.x && mousePos.y >= clickPoint.y) { selectionBoxOrigin = Vector2(clickPoint.x, clickPoint.y); selectionBoxEnd = Vector2(mousePos.x, mousePos.y); } else if (mousePos.x < clickPoint.x && mousePos.y > clickPoint.y) { selectionBoxOrigin = Vector2(mousePos.x, clickPoint.y); selectionBoxEnd = Vector2(clickPoint.x, mousePos.y); } else if (mousePos.x >= clickPoint.x && mousePos.y < clickPoint.y) { selectionBoxOrigin = Vector2(clickPoint.x, mousePos.y); selectionBoxEnd = Vector2(mousePos.x, clickPoint.y); } else { selectionBoxOrigin = Vector2(mousePos.x, mousePos.y); selectionBoxEnd = Vector2(clickPoint.x, clickPoint.y); } Vector3 size = Vector3(selectionBoxEnd.x - selectionBoxOrigin.x, selectionBoxEnd.y - selectionBoxOrigin.y, 0); dragbox->setSize(size); dragboxNode->setPosition(Vector3(selectionBoxOrigin.x, selectionBoxOrigin.y, 0)); } void ActiveGameState::issueOrder(Order::TYPE type, bool addOrder) { Vector3 color; switch(type){ case Order::TYPE::MOVE: color = Vector3::VEC_J; break; case Order::TYPE::ATTACK: case Order::TYPE::LAUNCH: color = Vector3::VEC_I; break; case Order::TYPE::PATROL: color = Vector3::VEC_K; break; case Order::TYPE::BUILD: color = Vector3(1, 1, 0); break; } Order o; o.type = type; o.targets = targets; targets.push_back(Order::Target()); if(o.type == Order::TYPE::PATROL) for(int i = targets.size() - 2; i >= 0; i--) targets[i + 1] = targets[i]; LineRenderer *lineRenderer = LineRenderer::getSingleton(); for (int i = 0; i < mainPlayer->getNumSelectedUnits(); ++i) { Unit *u = mainPlayer->getSelectedUnit(i); lineRenderer->addLine(u->getPos(), o.targets[i].pos, color); vector lines = lineRenderer->getLines(); o.line = lines[lines.size() - 1]; if (type != Order::TYPE::LAUNCH) { if(type == Order::TYPE::PATROL){ Vector3 p = u->getPos(); targets[0] = Order::Target(nullptr, p); } if (addOrder) u->addOrder(o); else u->setOrder(o); } } targets.clear(); } void ActiveGameState::addTarget() { Camera *cam = Root::getSingleton()->getCamera(); Vector3 camPos = cam->getPosition(); Vector3 endPos = screenToSpace(getCursorPos()); vector results; Vector3 rayDir = (endPos - camPos).norm(); Ray::retrieveCollisions(camPos, rayDir, Map::getSingleton()->getNodeParent(), results); std::map unitData; Ray::sortResults(results); if(!results.empty()){ vector ancestors = results[0].mesh->getNode()->getAncestors(); Node *node = ancestors[ancestors.size() - 2]; std::map::iterator it = unitData.find(node); Unit *unit = nullptr; UnitFrameController *ufCtr = UnitFrameController::getSingleton(); if(ufCtr->isPlacingFrames()){ unit = new Structure(mainPlayer, ufCtr->getUnitFrame(0).id, results[0].pos, ufCtr->getUnitFrame(0).model->getOrientation()); mainPlayer->addUnit(unit); } Map *map = Map::getSingleton(); for(Unit *u : mainPlayer->getSelectedUnits()) if(u->getType() == UnitType::UNDERWATER){ for(int i = 1; i < map->getNumTerrainObjects(); i++){ if(map->isPointWithinTerrainObject(u->getPos(), i) && map->isPointWithinTerrainObject(results[0].pos, i)){ vector res; Vector3 pos = u->getPos(); Ray::retrieveCollisions(Vector3(pos.x, map->getTerrainObject(0).size.y, pos.z), Vector3(0, -1, 0), map->getTerrainObject(0).node->getChild(0), res); Ray::sortResults(res); results[0].pos.y = res[0].pos.y + depth * (map->getTerrainObject(i).pos.y - res[0].pos.y); break; } } } targets.push_back(Order::Target((it != unitData.end() ? unitData[node] : unit), results[0].pos)); } } void ActiveGameState::onAction(int bind, bool isPressed) { GameManager *gm = GameManager::getSingleton(); InGameAppState *inGameState = (InGameAppState*) gm->getStateManager()->getAppStateByType((int)AppStateType::IN_GAME_STATE); UnitFrameController *ufCtr = UnitFrameController::getSingleton(); switch((Bind)bind){ case Bind::DRAG_BOX: isSelectionBox = isPressed; if (isPressed) { clickPoint = getCursorPos(); if (mainPlayer->getNumSelectedUnits() > 0){ addTarget(); if(!(targets.empty() || selectingPatrolPoints)){ Order::TYPE type = Order::TYPE::MOVE; if(controlPressed || (targets[0].unit && targets[0].unit->getPlayer()->getSide() != mainPlayer->getSide())) type = Order::TYPE::ATTACK; else if(ufCtr->isPlacingFrames()){ type = Order::TYPE::BUILD; ufCtr->setPlacingFrames(false); ufCtr->removeUnitFrames(); } issueOrder(type, shiftPressed); } } } break; case Bind::DESELECT: if(ufCtr->isPlacingFrames()) ufCtr->setRotatingFrames(isPressed); if (!isPressed) deselectUnits(); break; case Bind::TOGGLE_SUB: 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().norm() * .5f)); zooms++; } break; case Bind::LOOK_AROUND: if(!ufCtr->isPlacingFrames()) CameraController::getSingleton()->setLookingAround(isPressed); break; case Bind::HALT: for (Unit *u : mainPlayer->getSelectedUnits()) u->halt(); break; //TODO reimplement submarine diving mechanic case Bind::LEFT_CONTROL: controlPressed = isPressed; if(isPressed) depth -= 0.05; break; case Bind::LEFT_SHIFT: shiftPressed = isPressed; if(isPressed) depth += 0.05; break; case Bind::SELECT_PATROL_POINTS: selectingPatrolPoints = isPressed; if(!selectingPatrolPoints) issueOrder(Order::TYPE::PATROL, shiftPressed); break; case Bind::LAUNCH:{ if(isPressed){ Node *node = Map::getSingleton()->getNodeParent()->getChild(1); node->setVisible(!node->isVisible()); } selectingGuidedMissileTarget = 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::SELECT_STRUCTURE: { if(isPressed){ bool engineersSelected = false; for(Unit *u : mainPlayer->getSelectedUnits()) if(u->getUnitClass() == UnitClass::ENGINEER){ engineersSelected = true; break; } if(!engineersSelected) break; //TODO fix the magic value int id = 3; LuaManager *lm = LuaManager::getSingleton(); string modelPath = lm->getStringFromTable("basePath", vector{Index(id + 1)}) + lm->getStringFromTable("meshPath", vector{Index(id + 1)}); ufCtr->addUnitFrame(UnitFrameController::UnitFrame(modelPath, id, (int)UnitType::LAND)); ufCtr->setPlacingFrames(true); } break; } case Bind::DESELECT_STRUCTURE: ufCtr->removeUnitFrames(); ufCtr->setPlacingFrames(false); break; } } void ActiveGameState::onAnalog(int bind, float strength) { CameraController *camCtr = CameraController::getSingleton(); UnitFrameController *ufCtr = UnitFrameController::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); } break; case Bind::LOOK_LEFT: case Bind::LOOK_RIGHT: if(camCtr->isLookingAround()) CameraController::getSingleton()->orientCamera(Vector3(0, 1, 0), strength); else if(ufCtr->isPlacingFrames() && ufCtr->isRotatingFrames()) ufCtr->rotateUnitFrames(100 * strength); break; } } }