From 78e09c757dbe5f8500d9e60d6ba7b7a9938987a7 Mon Sep 17 00:00:00 2001 From: krzys-h Date: Fri, 26 Jun 2015 22:07:55 +0200 Subject: [PATCH] Basic support for teams and code battle missions --- src/object/auto/autofactory.cpp | 1 + src/object/brain.cpp | 33 ++++++++++++------------- src/object/level/parserparam.cpp | 22 +++++++++++++++++ src/object/level/parserparam.h | 4 +++ src/object/mission_type.h | 26 ++++++++++++++++++++ src/object/object.cpp | 26 +++++++++++++++++--- src/object/object.h | 4 +++ src/object/object_manager.cpp | 13 ++++++++++ src/object/object_manager.h | 3 +++ src/object/robotmain.cpp | 42 +++++++++++++++++++++++++------- src/object/robotmain.h | 11 +++++++-- src/object/task/taskbuild.cpp | 1 + src/ui/mainshort.cpp | 3 ++- 13 files changed, 157 insertions(+), 32 deletions(-) create mode 100644 src/object/mission_type.h diff --git a/src/object/auto/autofactory.cpp b/src/object/auto/autofactory.cpp index a09e25e9..6846b0ef 100644 --- a/src/object/auto/autofactory.cpp +++ b/src/object/auto/autofactory.cpp @@ -642,6 +642,7 @@ bool CAutoFactory::CreateVehicle() vehicle->UpdateMapping(); vehicle->SetLock(true); // not usable vehicle->SetRange(30.0f); + vehicle->SetTeam(m_object->GetTeam()); CPhysics* physics = vehicle->GetPhysics(); if ( physics != nullptr ) diff --git a/src/object/brain.cpp b/src/object/brain.cpp index 0731ce46..521893cf 100644 --- a/src/object/brain.cpp +++ b/src/object/brain.cpp @@ -547,8 +547,9 @@ bool CBrain::EventProcess(const Event &event) axeY = event.motionInput.y; axeZ = event.motionInput.z; - if ( !m_main->GetTrainerPilot() && - m_object->GetTrainer() ) // drive vehicle? + if ( (!m_main->GetTrainerPilot() && + m_object->GetTrainer()) || + !m_main->CanPlayerInteract() ) // drive vehicle? { axeX = 0.0f; axeY = 0.0f; @@ -1423,7 +1424,7 @@ bool CBrain::CreateInterface(bool bSelect) type == OBJECT_WORM || type == OBJECT_CONTROLLER) // vehicle? { - if (!(m_main->GetRetroMode())) + if (m_main->GetMissionType() != MISSION_RETRO) { ddim.x = dim.x*5.1f; ddim.y = dim.y*1.5f; @@ -2299,17 +2300,15 @@ void CBrain::UpdateInterface() type = m_object->GetType(); - bEnable = ( m_secondaryTask == 0 && m_currentProgram == nullptr ); + bEnable = ( m_primaryTask == 0 && m_currentProgram == nullptr ) && m_main->CanPlayerInteract(); - bEnable = ( m_primaryTask == 0 && m_currentProgram == nullptr ); - - EnableInterface(pw, EVENT_OBJECT_PROGEDIT, (m_primaryTask == 0 && !m_bTraceRecord) && m_selScript < m_program.size()); + EnableInterface(pw, EVENT_OBJECT_PROGEDIT, (m_primaryTask == 0 && !m_bTraceRecord) && m_selScript < m_program.size() && m_main->CanPlayerInteract()); EnableInterface(pw, EVENT_OBJECT_PROGLIST, bEnable && !m_bTraceRecord); - EnableInterface(pw, EVENT_OBJECT_PROGADD, m_currentProgram == nullptr); - EnableInterface(pw, EVENT_OBJECT_PROGREMOVE, m_currentProgram == nullptr && m_selScript < m_program.size() && !m_program[m_selScript]->readOnly); - EnableInterface(pw, EVENT_OBJECT_PROGCLONE, m_currentProgram == nullptr && m_selScript < m_program.size() && m_program[m_selScript]->runnable); - EnableInterface(pw, EVENT_OBJECT_PROGMOVEUP, m_currentProgram == nullptr && m_program.size() >= 2 && m_selScript > 0); - EnableInterface(pw, EVENT_OBJECT_PROGMOVEDOWN,m_currentProgram == nullptr && m_program.size() >= 2 && m_selScript < m_program.size()-1); + EnableInterface(pw, EVENT_OBJECT_PROGADD, m_currentProgram == nullptr && m_main->CanPlayerInteract()); + EnableInterface(pw, EVENT_OBJECT_PROGREMOVE, m_currentProgram == nullptr && m_selScript < m_program.size() && !m_program[m_selScript]->readOnly && m_main->CanPlayerInteract()); + EnableInterface(pw, EVENT_OBJECT_PROGCLONE, m_currentProgram == nullptr && m_selScript < m_program.size() && m_program[m_selScript]->runnable && m_main->CanPlayerInteract()); + EnableInterface(pw, EVENT_OBJECT_PROGMOVEUP, m_currentProgram == nullptr && m_program.size() >= 2 && m_selScript > 0 && m_main->CanPlayerInteract()); + EnableInterface(pw, EVENT_OBJECT_PROGMOVEDOWN,m_currentProgram == nullptr && m_program.size() >= 2 && m_selScript < m_program.size()-1 && m_main->CanPlayerInteract()); EnableInterface(pw, EVENT_OBJECT_LEFT, bEnable); EnableInterface(pw, EVENT_OBJECT_RIGHT, bEnable); EnableInterface(pw, EVENT_OBJECT_UP, bEnable); @@ -2379,8 +2378,8 @@ void CBrain::UpdateInterface() { if ( (m_secondaryTask == 0 || !m_secondaryTask->IsBusy()) && m_currentProgram == nullptr ) { - EnableInterface(pw, EVENT_OBJECT_BEGSHIELD, (m_secondaryTask == 0)); - EnableInterface(pw, EVENT_OBJECT_ENDSHIELD, (m_secondaryTask != 0)); + EnableInterface(pw, EVENT_OBJECT_BEGSHIELD, (m_secondaryTask == 0) && m_main->CanPlayerInteract()); + EnableInterface(pw, EVENT_OBJECT_ENDSHIELD, (m_secondaryTask != 0) && m_main->CanPlayerInteract()); DefaultEnter (pw, EVENT_OBJECT_BEGSHIELD, (m_secondaryTask == 0)); DefaultEnter (pw, EVENT_OBJECT_ENDSHIELD, (m_secondaryTask != 0)); } @@ -2404,8 +2403,8 @@ void CBrain::UpdateInterface() { if ( m_object->GetFret() != 0 ) bFly = false; // if holder -> not fly } - EnableInterface(pw, EVENT_OBJECT_GASUP, bFly); - EnableInterface(pw, EVENT_OBJECT_GASDOWN, bFly); + EnableInterface(pw, EVENT_OBJECT_GASUP, bFly && m_main->CanPlayerInteract()); + EnableInterface(pw, EVENT_OBJECT_GASDOWN, bFly && m_main->CanPlayerInteract()); if ( m_object->GetTrainer() ) // Training? { DeadInterface(pw, EVENT_OBJECT_GASUP, false); @@ -2471,7 +2470,7 @@ void CBrain::UpdateInterface() } if ( !bEnable && m_currentProgram == nullptr ) bRun = false; if ( m_bTraceRecord ) bRun = false; - EnableInterface(pw, EVENT_OBJECT_PROGRUN, bRun); + EnableInterface(pw, EVENT_OBJECT_PROGRUN, bRun && m_main->CanPlayerInteract()); pb = static_cast< Ui::CButton* >(pw->SearchControl(EVENT_OBJECT_PROGRUN)); if ( pb != 0 ) diff --git a/src/object/level/parserparam.cpp b/src/object/level/parserparam.cpp index a8872062..f77d7295 100644 --- a/src/object/level/parserparam.cpp +++ b/src/object/level/parserparam.cpp @@ -958,6 +958,28 @@ Gfx::CameraType CLevelParserParam::AsCameraType(Gfx::CameraType def) return AsCameraType(); } +MissionType CLevelParserParam::ToMissionType(std::string value) +{ + if (value == "NORMAL" ) return MISSION_NORMAL; + if (value == "RETRO" ) return MISSION_RETRO; + if (value == "CODE_BATTLE") return MISSION_CODE_BATTLE; + return static_cast(Cast(value, "MissionType")); +} + +MissionType CLevelParserParam::AsMissionType() +{ + if (m_empty) + throw CLevelParserExceptionMissingParam(this); + return ToMissionType(m_value); +} + +MissionType CLevelParserParam::AsMissionType(MissionType def) +{ + if (m_empty) + return def; + return AsMissionType(); +} + void CLevelParserParam::ParseArray() { diff --git a/src/object/level/parserparam.h b/src/object/level/parserparam.h index cd47f3c7..49897275 100644 --- a/src/object/level/parserparam.h +++ b/src/object/level/parserparam.h @@ -34,6 +34,7 @@ #include "object/drive_type.h" #include "object/object_type.h" #include "object/tool_type.h" +#include "object/mission_type.h" #include #include @@ -84,6 +85,7 @@ public: int AsResearchFlag(); Gfx::PyroType AsPyroType(); Gfx::CameraType AsCameraType(); + MissionType AsMissionType(); const CLevelParserParamVec& AsArray(); //@} @@ -105,6 +107,7 @@ public: int AsResearchFlag(int def); Gfx::PyroType AsPyroType(Gfx::PyroType def); Gfx::CameraType AsCameraType(Gfx::CameraType def); + MissionType AsMissionType(MissionType def); //@} //! Set line this param is part of @@ -133,6 +136,7 @@ private: int ToResearchFlag(std::string value); Gfx::PyroType ToPyroType(std::string value); Gfx::CameraType ToCameraType(std::string value); + MissionType ToMissionType(std::string value); const std::string FromObjectType(ObjectType value); const std::string FromCameraType(Gfx::CameraType value); diff --git a/src/object/mission_type.h b/src/object/mission_type.h new file mode 100644 index 00000000..8ad71fce --- /dev/null +++ b/src/object/mission_type.h @@ -0,0 +1,26 @@ +/* + * This file is part of the Colobot: Gold Edition source code + * Copyright (C) 2001-2015, Daniel Roux, EPSITEC SA & TerranovaTeam + * http://epsiteс.ch; http://colobot.info; http://github.com/colobot + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://gnu.org/licenses + */ + +#pragma once + +enum MissionType { + MISSION_NORMAL = 0, + MISSION_RETRO, + MISSION_CODE_BATTLE +}; \ No newline at end of file diff --git a/src/object/object.cpp b/src/object/object.cpp index 70f7ebf9..8cbfebd8 100644 --- a/src/object/object.cpp +++ b/src/object/object.cpp @@ -251,6 +251,7 @@ CObject::CObject(int id) m_magnifyDamage = 1.0f; m_proxyDistance = 60.0f; m_param = 0.0f; + m_team = 0; memset(&m_character, 0, sizeof(m_character)); m_character.wheelFront = 1.0f; @@ -953,6 +954,9 @@ bool CObject::Write(CLevelParserLine* line) if ( GetMagnifyDamage() != 1.0f ) line->AddParam("magnifyDamage", CLevelParserParamUPtr{new CLevelParserParam(GetMagnifyDamage())}); + if ( GetTeam() != 0 ) + line->AddParam("team", CLevelParserParamUPtr{new CLevelParserParam(GetTeam())}); + if ( GetGunGoalV() != 0.0f ) line->AddParam("aimV", CLevelParserParamUPtr{new CLevelParserParam(GetGunGoalV())}); @@ -1048,6 +1052,7 @@ bool CObject::Read(CLevelParserLine* line) SetProxyDistance(line->GetParam("proxyDistance")->AsFloat(15.0f)*g_unit); SetRange(line->GetParam("range")->AsFloat(30.0f)); SetMagnifyDamage(line->GetParam("magnifyDamage")->AsFloat(1.0f)); + SetTeam(line->GetParam("team")->AsInt(0)); SetGunGoalV(line->GetParam("aimV")->AsFloat(0.0f)); SetGunGoalH(line->GetParam("aimH")->AsFloat(0.0f)); SetParam(line->GetParam("param")->AsFloat(0.0f)); @@ -2815,6 +2820,18 @@ bool CObject::GetClip() } +// Controls object team + +void CObject::SetTeam(int team) +{ + m_team = team; +} + +int CObject::GetTeam() +{ + return m_team; +} + // Pushes an object. @@ -3379,7 +3396,7 @@ void CObject::CreateSelectParticle() } } - if ( m_bSelect || IsProgram() || m_main->GetRetroMode() ) + if ( m_bSelect || IsProgram() || m_main->GetMissionType() == MISSION_RETRO ) { // Creates particles lens for the headlights. if ( m_type == OBJECT_MOBILEfa || @@ -3433,7 +3450,7 @@ void CObject::UpdateSelectParticle() float angle; int i; - if ( !m_bSelect && !IsProgram() && !m_main->GetRetroMode() ) return; + if ( !m_bSelect && !IsProgram() && m_main->GetMissionType() != MISSION_RETRO ) return; dim[0].x = 1.0f; dim[1].x = 1.0f; @@ -3557,7 +3574,7 @@ void CObject::UpdateSelectParticle() zoom[3] = 1.0f; if ( ( IsProgram() || // current program? - m_main->GetRetroMode() ) && // Retro mode? + m_main->GetMissionType() == MISSION_RETRO ) && // Retro mode? Math::Mod(m_aTime, 0.7f) < 0.3f ) { zoom[0] = 0.0f; // blinks @@ -3663,6 +3680,9 @@ int CObject::GetDefRank() bool CObject::GetTooltipName(std::string& name) { GetResource(RES_OBJECT, m_type, name); + if(GetTeam() != 0) { + name += " [team "+boost::lexical_cast(GetTeam())+"]"; //TODO: better way to display this + } return !name.empty(); } diff --git a/src/object/object.h b/src/object/object.h index 008103f4..4928431c 100644 --- a/src/object/object.h +++ b/src/object/object.h @@ -278,6 +278,9 @@ public: void SetClip(bool bClip); bool GetClip(); + void SetTeam(int team); + int GetTeam(); + bool JostleObject(float force); void StartDetectEffect(CObject *target, bool bFound); @@ -468,6 +471,7 @@ protected: float m_magnifyDamage; float m_proxyDistance; float m_param; + int m_team; int m_crashSphereUsed; // number of spheres used Math::Vector m_crashSpherePos[MAXCRASHSPHERE]; diff --git a/src/object/object_manager.cpp b/src/object/object_manager.cpp index 1117e10b..fcedd438 100644 --- a/src/object/object_manager.cpp +++ b/src/object/object_manager.cpp @@ -130,6 +130,19 @@ CObject* CObjectManager::CreateObject(Math::Vector pos, return objectPtr; } +std::vector CObjectManager::GetObjectsOfTeam(int team) +{ + std::vector result; + for (CObject* object : GetAllObjects()) + { + if (object->GetTeam() == team) + { + result.push_back(object); + } + } + return result; +} + CObject* CObjectManager::Radar(CObject* pThis, ObjectType type, float angle, float focus, float minDist, float maxDist, bool furthest, RadarFilter filter, bool cbotTypes) { std::vector types; diff --git a/src/object/object_manager.h b/src/object/object_manager.h index 90e4b26b..fb4ae5b5 100644 --- a/src/object/object_manager.h +++ b/src/object/object_manager.h @@ -145,6 +145,9 @@ public: //! Gets object by id in range <0; number of objects - 1> CObject* GetObjectByRank(unsigned int id); + //! Gets all objects of given team + std::vector GetObjectsOfTeam(int team); + //! Returns all objects inline CObjectContainerProxy GetAllObjects() { diff --git a/src/object/robotmain.cpp b/src/object/robotmain.cpp index cea20360..ff90739e 100644 --- a/src/object/robotmain.cpp +++ b/src/object/robotmain.cpp @@ -175,7 +175,7 @@ CRobotMain::CRobotMain(CController* controller) m_infoUsed = 0; m_controller = nullptr; - m_retroStyle = false; + m_missionType = MISSION_NORMAL; m_immediatSatCom = false; m_beginSatCom = false; m_lockedSatCom = false; @@ -188,6 +188,9 @@ CRobotMain::CRobotMain(CController* controller) m_selectInsect = false; m_showSoluce = false; + m_codeBattleInit = false; + m_codeBattleStarted = false; + #if DEV_BUILD m_showAll = true; // for development #else @@ -1871,7 +1874,7 @@ bool CRobotMain::SelectObject(CObject* obj, bool displayError) if (m_camera->GetType() == Gfx::CAM_TYPE_VISIT) StopDisplayVisit(); - if (m_movieLock || m_editLock || m_pause->GetPause()) return false; + if (m_movieLock || m_editLock) return false; if (m_movie->IsExist()) return false; if (obj == nullptr || !IsSelectable(obj)) return false; @@ -2695,7 +2698,7 @@ bool CRobotMain::EventFrame(const Event &event) { dim.x = 32.0f/640.0f; dim.y = 32.0f/480.0f; - pos.x = 20.0f/640.0f; + pos.x = (640.0f-24.0f)/640.0f; pos.y = (480.0f-24.0f)/480.0f; float zoom = 1.0f+sinf(m_time*6.0f)*0.1f; // 0.9 .. 1.1 @@ -2758,6 +2761,17 @@ bool CRobotMain::EventFrame(const Event &event) } } + if(!m_codeBattleInit) { + // NOTE: It's important to do this AFTER the first update event finished processing + // because otherwise all robot parts are misplaced + ChangePause(PAUSE_USER); + m_codeBattleInit = true; // Will start on resume + } + if(!m_codeBattleStarted && m_pause->GetPause() == PAUSE_NONE) { + m_codeBattleStarted = true; + m_eventQueue->AddEvent(Event(EVENT_UPDINTERFACE)); + } + return true; } @@ -2920,9 +2934,11 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) strcpy(m_scriptName, scriptNameStr.c_str()); m_scriptFile[0] = 0; - m_retroStyle = false; + m_missionType = MISSION_NORMAL; + m_codeBattleInit = false; + m_codeBattleStarted = false; - m_missionResult = ERR_MISSION_NOTERM; + m_missionResult = ERR_MISSION_NOTERM; } //NOTE: Reset timer always, even when only resetting object positions @@ -3228,8 +3244,7 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) m_engine->SetTracePrecision(line->GetParam("traceQuality")->AsFloat(1.0f)); m_shortCut = line->GetParam("shortcut")->AsBool(true); - m_retroStyle = line->GetParam("retro")->AsBool(false); - if (m_retroStyle) GetLogger()->Info("Retro mode enabled.\n"); + m_missionType = line->GetParam("type")->AsMissionType(MISSION_NORMAL); continue; } @@ -3570,6 +3585,7 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) obj->SetRange(line->GetParam("range")->AsFloat(30.0f)); obj->SetShield(line->GetParam("shield")->AsFloat(1.0f)); obj->SetMagnifyDamage(line->GetParam("magnifyDamage")->AsFloat(1.0f)); + obj->SetTeam(line->GetParam("team")->AsInt(0)); obj->SetClip(line->GetParam("clip")->AsBool(true)); obj->SetCheckToken(!line->GetParam("checkToken")->IsDefined() ? trainer || !selectable : line->GetParam("checkToken")->AsBool(true)); // SetManual will affect bot speed @@ -5862,9 +5878,9 @@ const char* CRobotMain::GetFilesDir() return m_dialog->GetFilesDir().c_str(); } -bool CRobotMain::GetRetroMode() +MissionType CRobotMain::GetMissionType() { - return m_retroStyle; + return m_missionType; } //! Change the player's name @@ -6277,3 +6293,11 @@ void CRobotMain::SetExitAfterMission(bool exit) { m_exitAfterMission = exit; } + +bool CRobotMain::CanPlayerInteract() +{ + if(GetMissionType() == MISSION_CODE_BATTLE) { + return !m_codeBattleStarted; + } + return true; +} \ No newline at end of file diff --git a/src/object/robotmain.h b/src/object/robotmain.h index 8e4fcd04..8f3ee437 100644 --- a/src/object/robotmain.h +++ b/src/object/robotmain.h @@ -34,6 +34,7 @@ #include "object/drive_type.h" #include "object/tool_type.h" #include "object/mainmovie.h" +#include "object/mission_type.h" #include "app/pausemanager.h" @@ -287,7 +288,7 @@ public: const char* GetSavegameDir(); const char* GetPublicDir(); const char* GetFilesDir(); - bool GetRetroMode(); + MissionType GetMissionType(); void SetGamerName(const char *name); char* GetGamerName(); @@ -358,6 +359,9 @@ public: //! Enable mode where completing mission closes the game void SetExitAfterMission(bool exit); + //! Returns true if player can interact with things manually + bool CanPlayerInteract(); + protected: bool EventFrame(const Event &event); bool EventObject(const Event &event); @@ -452,7 +456,7 @@ protected: CObject* m_controller; - bool m_retroStyle; // Retro + MissionType m_missionType; bool m_immediatSatCom; // SatCom immediately? bool m_beginSatCom; // messages SatCom poster? bool m_lockedSatCom; // SatCom locked? @@ -489,6 +493,9 @@ protected: bool m_exitAfterMission; + bool m_codeBattleInit; + bool m_codeBattleStarted; + float m_fontSize; Math::Point m_windowPos; Math::Point m_windowDim; diff --git a/src/object/task/taskbuild.cpp b/src/object/task/taskbuild.cpp index 4363cef5..0725d4cb 100644 --- a/src/object/task/taskbuild.cpp +++ b/src/object/task/taskbuild.cpp @@ -82,6 +82,7 @@ bool CTaskBuild::CreateBuilding(Math::Vector pos, float angle) m_building = CObjectManager::GetInstancePointer()->CreateObject(pos, angle, m_type, power); m_building->UpdateMapping(); m_building->SetLock(true); // not yet usable + m_building->SetTeam(m_object->GetTeam()); if ( m_type == OBJECT_DERRICK ) m_buildingHeight = 35.0f; if ( m_type == OBJECT_FACTORY ) m_buildingHeight = 28.0f; diff --git a/src/ui/mainshort.cpp b/src/ui/mainshort.cpp index 805f34ae..bf70546b 100644 --- a/src/ui/mainshort.cpp +++ b/src/ui/mainshort.cpp @@ -127,7 +127,8 @@ bool CMainShort::CreateShortcuts() m_engine->GetPause()) ) // hangs during edition? { m_interface->CreateShortcut(pos, dim, 6, EVENT_OBJECT_EDITLOCK); - return true; + if(!m_engine->GetPause()) + return true; } rank = 0;