colobot/src/object/robotmain.cpp

7073 lines
225 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* This file is part of the Colobot: Gold Edition source code
* Copyright (C) 2001-2014, 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
*/
#include "object/robotmain.h"
#include "CBot/CBotDll.h"
#include "app/app.h"
#include "common/event.h"
#include "common/global.h"
#include "common/iman.h"
#include "common/logger.h"
#include "common/misc.h"
#include "common/profile.h"
#include "common/restext.h"
#include "common/resources/resourcemanager.h"
#include "common/resources/inputstream.h"
#include "common/resources/outputstream.h"
#include "graphics/engine/camera.h"
#include "graphics/engine/cloud.h"
#include "graphics/engine/engine.h"
#include "graphics/engine/lightman.h"
#include "graphics/engine/lightning.h"
#include "graphics/engine/modelmanager.h"
#include "graphics/engine/particle.h"
#include "graphics/engine/planet.h"
#include "graphics/engine/pyro.h"
#include "graphics/engine/terrain.h"
#include "graphics/engine/text.h"
#include "graphics/engine/water.h"
#include "math/const.h"
#include "math/geometry.h"
#include "object/auto/auto.h"
#include "object/auto/autobase.h"
#include "object/brain.h"
#include "object/mainmovie.h"
#include "object/motion/motion.h"
#include "object/motion/motionhuman.h"
#include "object/motion/motiontoto.h"
#include "object/object.h"
#include "object/task/task.h"
#include "object/task/taskbuild.h"
#include "object/task/taskmanip.h"
#include "object/level/parser.h"
#include "physics/physics.h"
#include "script/cbottoken.h"
#include "script/cmdtoken.h"
#include "script/script.h"
#include "sound/sound.h"
#include "ui/button.h"
#include "ui/displayinfo.h"
#include "ui/displaytext.h"
#include "ui/edit.h"
#include "ui/interface.h"
#include "ui/label.h"
#include "ui/maindialog.h"
#include "ui/mainmap.h"
#include "ui/mainshort.h"
#include "ui/map.h"
#include "ui/shortcut.h"
#include "ui/slider.h"
#include "ui/window.h"
#include <iomanip>
#include <boost/lexical_cast.hpp>
template<> CRobotMain* CSingleton<CRobotMain>::m_instance = nullptr;
// TODO: remove once using std::string
const int MAX_FNAME = 255;
const float UNIT = 4.0f;
// Global variables.
long g_id; // unique identifier
int g_build; // constructible buildings
int g_researchDone; // research done
long g_researchEnable; // research available
float g_unit; // conversion factor
// Static variables
static CBotClass* m_pClassFILE;
//static CBotProgram* m_pFuncFile;
static int m_CompteurFileOpen = 0;
static std::string m_filesDir;
// Prepares a file name.
void PrepareFilename(CBotString &filename)
{
int pos = filename.ReverseFind('/');
if ( pos > 0 )
{
filename = filename.Mid(pos+1); // Remove files with
}
pos = filename.ReverseFind('/');
if ( pos > 0 )
{
filename = filename.Mid(pos+1); // also with /
}
pos = filename.ReverseFind(':');
if ( pos > 0 )
{
filename = filename.Mid(pos+1); // also removes the drive letter C:
}
filename = CBotString(m_filesDir.c_str()) + CBotString("/") + filename;
}
// constructor of the class
// get the filename as a parameter
// execution
bool rfconstruct (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
{
CBotString mode;
// accepts no parameters
if ( pVar == NULL ) return true;
// must be a character string
if ( pVar->GetType() != CBotTypString ) { Exception = CBotErrBadString; return false; }
CBotString filename = pVar->GetValString();
PrepareFilename(filename);
// there may be a second parameter
pVar = pVar->GetNext();
if ( pVar != NULL )
{
// recover mode
mode = pVar->GetValString();
if ( mode != "r" && mode != "w" ) { Exception = CBotErrBadParam; return false; }
// no third parameter
if ( pVar->GetNext() != NULL ) { Exception = CBotErrOverParam; return false; }
}
// saves the file name
pVar = pThis->GetItem("filename");
pVar->SetValString(filename);
if ( ! mode.IsEmpty() )
{
// opens the requested file
FILE* pFile = fopen( filename, mode );
if ( pFile == NULL ) { Exception = CBotErrFileOpen; return false; }
m_CompteurFileOpen ++;
// save the channel file
pVar = pThis->GetItem("handle");
pVar->SetValInt(reinterpret_cast<long>(pFile));
}
return true;
}
// compilation
CBotTypResult cfconstruct (CBotVar* pThis, CBotVar* &pVar)
{
// accepts no parameters
if ( pVar == NULL ) return CBotTypResult( 0 );
// must be a character string
if ( pVar->GetType() != CBotTypString )
return CBotTypResult( CBotErrBadString );
// there may be a second parameter
pVar = pVar->GetNext();
if ( pVar != NULL )
{
// which must be a string
if ( pVar->GetType() != CBotTypString )
return CBotTypResult( CBotErrBadString );
// no third parameter
if ( pVar->GetNext() != NULL ) return CBotTypResult( CBotErrOverParam );
}
// the result is void (constructor)
return CBotTypResult( 0 );
}
// destructor of the class
// execution
bool rfdestruct (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
{
// retrieve the item "handle"
pVar = pThis->GetItem("handle");
// don't open? no problem :)
if ( pVar->GetInit() != IS_DEF) return true;
FILE* pFile= reinterpret_cast<FILE*>(pVar->GetValInt());
fclose(pFile);
m_CompteurFileOpen --;
pVar->SetInit(IS_NAN);
return true;
}
// process FILE :: open
// get the r/w mode as a parameter
// execution
bool rfopen (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
{
// there must be a parameter
if ( pVar == NULL ) { Exception = CBotErrLowParam; return false; }
// which must be a character string
if ( pVar->GetType() != CBotTypString ) { Exception = CBotErrBadString; return false; }
// There may be a second parameter
if ( pVar->GetNext() != NULL )
{
// if the first parameter is the file name
CBotString filename = pVar->GetValString();
PrepareFilename(filename);
// saves the file name
CBotVar* pVar2 = pThis->GetItem("filename");
pVar2->SetValString(filename);
// next parameter is the mode
pVar = pVar -> GetNext();
}
CBotString mode = pVar->GetValString();
if ( mode != "r" && mode != "w" ) { Exception = CBotErrBadParam; return false; }
// no third parameter
if ( pVar->GetNext() != NULL ) { Exception = CBotErrOverParam; return false; }
// retrieve the item "handle"
pVar = pThis->GetItem("handle");
// which must not be initialized
if ( pVar->GetInit() == IS_DEF) { Exception = CBotErrFileOpen; return false; }
// file contains the name
pVar = pThis->GetItem("filename");
CBotString filename = pVar->GetValString();
PrepareFilename(filename); // if the name was h.filename attribute = "...";
// opens the requested file
FILE* pFile = fopen( filename, mode );
if ( pFile == NULL )
{
pResult->SetValInt(false);
return true;
}
m_CompteurFileOpen ++;
// Registered the channel file
pVar = pThis->GetItem("handle");
pVar->SetValInt(reinterpret_cast<long>(pFile));
pResult->SetValInt(true);
return true;
}
// compilation
CBotTypResult cfopen (CBotVar* pThis, CBotVar* &pVar)
{
// there must be a parameter
if ( pVar == NULL ) return CBotTypResult( CBotErrLowParam );
// which must be a string
if ( pVar->GetType() != CBotTypString )
return CBotTypResult( CBotErrBadString );
// there may be a second parameter
pVar = pVar->GetNext();
if ( pVar != NULL )
{
// which must be a string
if ( pVar->GetType() != CBotTypString )
return CBotTypResult( CBotErrBadString );
// no third parameter
if ( pVar->GetNext() != NULL ) return CBotTypResult( CBotErrOverParam );
}
// the result is bool
return CBotTypResult(CBotTypBoolean);
}
// process FILE :: close
// execeution
bool rfclose (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
{
// it shouldn't be any parameters
if ( pVar != NULL ) return CBotErrOverParam;
// retrieve the item "handle"
pVar = pThis->GetItem("handle");
if ( pVar->GetInit() != IS_DEF) { Exception = CBotErrNotOpen; return false; }
FILE* pFile= reinterpret_cast<FILE*>(pVar->GetValInt());
fclose(pFile);
m_CompteurFileOpen --;
pVar->SetInit(IS_NAN);
return true;
}
// compilation
CBotTypResult cfclose (CBotVar* pThis, CBotVar* &pVar)
{
// it shouldn't be any parameters
if ( pVar != NULL ) return CBotTypResult( CBotErrOverParam );
// function returns a result "void"
return CBotTypResult( 0 );
}
// process FILE :: writeln
// execution
bool rfwrite (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
{
// there must be a parameter
if ( pVar == NULL ) { Exception = CBotErrLowParam; return false; }
// which must be a character string
if ( pVar->GetType() != CBotTypString ) { Exception = CBotErrBadString; return false; }
CBotString param = pVar->GetValString();
// retrieve the item "handle"
pVar = pThis->GetItem("handle");
if ( pVar->GetInit() != IS_DEF) { Exception = CBotErrNotOpen; return false; }
FILE* pFile= reinterpret_cast<FILE*>(pVar->GetValInt());
int res = fputs(param+CBotString("\n"), pFile);
// if an error occurs generate an exception
if ( res < 0 ) { Exception = CBotErrWrite; return false; }
return true;
}
// compilation
CBotTypResult cfwrite (CBotVar* pThis, CBotVar* &pVar)
{
// there must be a parameter
if ( pVar == NULL ) return CBotTypResult( CBotErrLowParam );
// which must be a character string
if ( pVar->GetType() != CBotTypString ) return CBotTypResult( CBotErrBadString );
// no other parameter
if ( pVar->GetNext() != NULL ) return CBotTypResult( CBotErrOverParam );
// the function returns a void result
return CBotTypResult( 0 );
}
// process FILE :: readln
// execution
bool rfread (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
{
// it shouldn't be any parameters
if ( pVar != NULL ) { Exception = CBotErrOverParam; return false; }
// retrieve the item "handle"
pVar = pThis->GetItem("handle");
if ( pVar->GetInit() != IS_DEF) { Exception = CBotErrNotOpen; return false; }
FILE* pFile= reinterpret_cast<FILE*>(pVar->GetValInt());
char chaine[2000];
int i;
for ( i = 0 ; i < 2000 ; i++ ) chaine[i] = 0;
fgets(chaine, 1999, pFile);
for ( i = 0 ; i < 2000 ; i++ ) if (chaine[i] == '\n') chaine[i] = 0;
// if an error occurs generate an exception
if ( ferror(pFile) ) { Exception = CBotErrRead; return false; }
pResult->SetValString( chaine );
return true;
}
// compilation
CBotTypResult cfread (CBotVar* pThis, CBotVar* &pVar)
{
// it should not be any parameter
if ( pVar != NULL ) return CBotTypResult( CBotErrOverParam );
// function returns a result "string"
return CBotTypResult( CBotTypString );
}
// process FILE :: readln
// execution
bool rfeof (CBotVar* pThis, CBotVar* pVar, CBotVar* pResult, int& Exception)
{
// it should not be any parameter
if ( pVar != NULL ) { Exception = CBotErrOverParam; return false; }
// retrieve the item "handle"
pVar = pThis->GetItem("handle");
if ( pVar->GetInit() != IS_DEF) { Exception = CBotErrNotOpen; return false; }
FILE* pFile= reinterpret_cast<FILE*>(pVar->GetValInt());
pResult->SetValInt( feof( pFile ) );
return true;
}
// compilation
CBotTypResult cfeof (CBotVar* pThis, CBotVar* &pVar)
{
// it shouldn't be any parameter
if ( pVar != NULL ) return CBotTypResult( CBotErrOverParam );
// the function returns a boolean result
return CBotTypResult( CBotTypBoolean );
}
void InitClassFILE()
{
// create a class for file management
// the use is as follows:
// file canal( "NomFichier.txt" )
// canal.open( "r" ); // open for read
// s = canal.readln( ); // reads a line
// canal.close(); // close the file
// create the class FILE
m_pClassFILE = new CBotClass("file", NULL);
// adds the component ".filename"
m_pClassFILE->AddItem("filename", CBotTypString);
// adds the component ".handle"
m_pClassFILE->AddItem("handle", CBotTypInt, PR_PRIVATE);
// define a constructor and a destructor
m_pClassFILE->AddFunction("file", rfconstruct, cfconstruct );
m_pClassFILE->AddFunction("~file", rfdestruct, NULL );
// end of the methods associated
m_pClassFILE->AddFunction("open", rfopen, cfopen );
m_pClassFILE->AddFunction("close", rfclose, cfclose );
m_pClassFILE->AddFunction("writeln", rfwrite, cfwrite );
m_pClassFILE->AddFunction("readln", rfread, cfread );
m_pClassFILE->AddFunction("eof", rfeof, cfeof );
//m_pFuncFile = new CBotProgram( );
//CBotStringArray ListFonctions;
//m_pFuncFile->Compile( "public file openfile(string name, string mode) {return new file(name, mode);}", ListFonctions);
//m_pFuncFile->SetIdent(-2); // restoreState in special identifier for this function
}
// Compilation of class "point".
CBotTypResult cPoint(CBotVar* pThis, CBotVar* &var)
{
if ( !pThis->IsElemOfClass("point") ) return CBotTypResult(CBotErrBadNum);
if ( var == NULL ) return CBotTypResult(0); // ok if no parameter
// First parameter (x):
if ( var->GetType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
var = var->GetNext();
// Second parameter (y):
if ( var == NULL ) return CBotTypResult(CBotErrLowParam);
if ( var->GetType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
var = var->GetNext();
// Third parameter (z):
if ( var == NULL ) // only 2 parameters?
{
return CBotTypResult(0); // this function returns void
}
if ( var->GetType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum);
var = var->GetNext();
if ( var != NULL ) return CBotTypResult(CBotErrOverParam);
return CBotTypResult(0); // this function returns void
}
//Execution of the class "point".
bool rPoint(CBotVar* pThis, CBotVar* var, CBotVar* pResult, int& Exception)
{
CBotVar *pX, *pY, *pZ;
if ( var == NULL ) return true; // constructor with no parameters is ok
if ( var->GetType() > CBotTypDouble )
{
Exception = CBotErrBadNum; return false;
}
pX = pThis->GetItem("x");
if ( pX == NULL )
{
Exception = CBotErrUndefItem; return false;
}
pX->SetValFloat( var->GetValFloat() );
var = var->GetNext();
if ( var == NULL )
{
Exception = CBotErrLowParam; return false;
}
if ( var->GetType() > CBotTypDouble )
{
Exception = CBotErrBadNum; return false;
}
pY = pThis->GetItem("y");
if ( pY == NULL )
{
Exception = CBotErrUndefItem; return false;
}
pY->SetValFloat( var->GetValFloat() );
var = var->GetNext();
if ( var == NULL )
{
return true; // ok with only two parameters
}
pZ = pThis->GetItem("z");
if ( pZ == NULL )
{
Exception = CBotErrUndefItem; return false;
}
pZ->SetValFloat( var->GetValFloat() );
var = var->GetNext();
if ( var != NULL )
{
Exception = CBotErrOverParam; return false;
}
return true; // no interruption
}
//! Constructor of robot application
CRobotMain::CRobotMain(CApplication* app, bool loadProfile)
{
m_app = app;
m_eventQueue = m_app->GetEventQueue();
m_sound = m_app->GetSound();
m_engine = Gfx::CEngine::GetInstancePointer();
m_lightMan = m_engine->GetLightManager();
m_particle = m_engine->GetParticle();
m_water = m_engine->GetWater();
m_cloud = m_engine->GetCloud();
m_lightning = m_engine->GetLightning();
m_planet = m_engine->GetPlanet();
m_pause = CPauseManager::GetInstancePointer();
m_interface = new Ui::CInterface();
m_terrain = new Gfx::CTerrain();
m_camera = new Gfx::CCamera();
m_displayText = new Ui::CDisplayText();
m_movie = new CMainMovie();
m_dialog = new Ui::CMainDialog();
m_short = new Ui::CMainShort();
m_map = new Ui::CMainMap();
m_displayInfo = nullptr;
m_engine->SetTerrain(m_terrain);
m_filesDir = m_dialog->GetFilesDir();
m_time = 0.0f;
m_gameTime = 0.0f;
m_missionTimerEnabled = false;
m_missionTimerStarted = false;
m_missionTimer = 0.0f;
m_phase = PHASE_NAME;
m_cameraRank = -1;
m_visitLast = EVENT_NULL;
m_visitObject = 0;
m_visitArrow = 0;
m_audioTrack = "";
m_audioRepeat = true;
m_satcomTrack = "";
m_satcomRepeat = true;
m_editorTrack = "";
m_editorRepeat = true;
m_delayWriteMessage = 0;
m_selectObject = 0;
m_infoUsed = 0;
m_version = 1;
m_controller = nullptr;
m_retroStyle = false;
m_immediatSatCom = false;
m_beginSatCom = false;
m_lockedSatCom = false;
m_movieLock = false;
m_satComLock = false;
m_editLock = false;
m_editFull = false;
m_hilite = false;
m_freePhoto = false;
m_selectInsect = false;
m_showSoluce = false;
#if DEV_BUILD
m_showAll = true; // for development
#else
m_showAll = false;
#endif
m_cheatRadar = false;
m_fixScene = false;
m_trainerPilot = false;
m_suspend = false;
m_friendAim = false;
m_resetCreate = false;
m_shortCut = true;
m_engine->SetMovieLock(m_movieLock);
m_movie->Flush();
m_movieInfoIndex = -1;
m_tooltipPos = Math::Point(0.0f, 0.0f);
m_tooltipName.clear();
m_tooltipTime = 0.0f;
m_endingWinRank = 0;
m_endingLostRank = 0;
m_winTerminate = false;
m_exitAfterMission = false;
m_autosave = true;
m_autosaveInterval = 15;
m_autosaveSlots = 3;
m_autosaveLast = 0.0f;
m_joystickDeadzone = 0.2f;
SetDefaultInputBindings();
FlushDisplayInfo();
m_fontSize = 19.0f;
m_windowPos = Math::Point(0.15f, 0.17f);
m_windowDim = Math::Point(0.70f, 0.66f);
float fValue;
int iValue;
if (loadProfile)
{
if (GetProfile().GetFloatProperty("Edit", "FontSize", fValue)) m_fontSize = fValue;
if (GetProfile().GetFloatProperty("Edit", "WindowPosX", fValue)) m_windowPos.x = fValue;
if (GetProfile().GetFloatProperty("Edit", "WindowPosY", fValue)) m_windowPos.y = fValue;
if (GetProfile().GetFloatProperty("Edit", "WindowDimX", fValue)) m_windowDim.x = fValue;
if (GetProfile().GetFloatProperty("Edit", "WindowDimY", fValue)) m_windowDim.y = fValue;
}
m_IOPublic = false;
m_IODim = Math::Point(320.0f/640.0f, (121.0f+18.0f*8)/480.0f);
m_IOPos.x = (1.0f-m_IODim.x)/2.0f; // in the middle
m_IOPos.y = (1.0f-m_IODim.y)/2.0f;
if (loadProfile)
{
if (GetProfile().GetIntProperty ("Edit", "IOPublic", iValue)) m_IOPublic = iValue;
if (GetProfile().GetFloatProperty("Edit", "IOPosX", fValue)) m_IOPos.x = fValue;
if (GetProfile().GetFloatProperty("Edit", "IOPosY", fValue)) m_IOPos.y = fValue;
if (GetProfile().GetFloatProperty("Edit", "IODimX", fValue)) m_IODim.x = fValue;
if (GetProfile().GetFloatProperty("Edit", "IODimY", fValue)) m_IODim.y = fValue;
}
m_short->FlushShortcuts();
InitEye();
m_engine->SetTracePrecision(1.0f);
m_cameraPan = 0.0f;
m_cameraZoom = 0.0f;
g_id = 0;
g_build = 0;
g_researchDone = 0; // no research done
g_researchEnable = 0;
g_unit = UNIT;
m_gamerName = "";
if (loadProfile) GetProfile().GetStringProperty("Gamer", "LastName", m_gamerName);
SetGlobalGamerName(m_gamerName);
ReadFreeParam();
if (loadProfile) m_dialog->SetupRecall();
for (int i = 0; i < MAXSHOWLIMIT; i++)
{
m_showLimit[i].used = false;
m_showLimit[i].total = 0;
m_showLimit[i].link = 0;
}
CBotProgram::SetTimer(100);
CBotProgram::Init();
for (int i = 0; i < OBJECT_MAX; i++)
{
ObjectType type = static_cast<ObjectType>(i);
const char* token = GetObjectName(type);
if (token[0] != 0)
CBotProgram::DefineNum(token, type);
token = GetObjectAlias(type);
if (token[0] != 0)
CBotProgram::DefineNum(token, type);
}
CBotProgram::DefineNum("White", 0);
CBotProgram::DefineNum("Black", 1);
CBotProgram::DefineNum("Gray", 2);
CBotProgram::DefineNum("LightGray", 3);
CBotProgram::DefineNum("Red", 4);
CBotProgram::DefineNum("Pink", 5);
CBotProgram::DefineNum("Purple", 6);
CBotProgram::DefineNum("Orange", 7);
CBotProgram::DefineNum("Yellow", 8);
CBotProgram::DefineNum("Beige", 9);
CBotProgram::DefineNum("Brown", 10);
CBotProgram::DefineNum("Skin", 11);
CBotProgram::DefineNum("Green", 12);
CBotProgram::DefineNum("LightGreen", 13);
CBotProgram::DefineNum("Blue", 14);
CBotProgram::DefineNum("LightBlue", 15);
CBotProgram::DefineNum("BlackArrow", 16);
CBotProgram::DefineNum("RedArrow", 17);
CBotProgram::DefineNum("Metal", OM_METAL);
CBotProgram::DefineNum("Plastic", OM_PLASTIC);
CBotProgram::DefineNum("InFront", TMA_FFRONT);
CBotProgram::DefineNum("Behind", TMA_FBACK);
CBotProgram::DefineNum("EnergyCell", TMA_POWER);
CBotProgram::DefineNum("DisplayError", Ui::TT_ERROR);
CBotProgram::DefineNum("DisplayWarning", Ui::TT_WARNING);
CBotProgram::DefineNum("DisplayInfo", Ui::TT_INFO);
CBotProgram::DefineNum("DisplayMessage", Ui::TT_MESSAGE);
CBotProgram::DefineNum("FilterNone", FILTER_NONE);
CBotProgram::DefineNum("FilterOnlyLanding", FILTER_ONLYLANDING);
CBotProgram::DefineNum("FilterOnlyFliying", FILTER_ONLYFLYING);
CBotProgram::DefineNum("ExploNone", 0);
CBotProgram::DefineNum("ExploBoum", EXPLO_BOUM);
CBotProgram::DefineNum("ExploBurn", EXPLO_BURN);
CBotProgram::DefineNum("ExploWater", EXPLO_WATER);
CBotProgram::DefineNum("ResultNotEnded", ERR_MISSION_NOTERM);
CBotProgram::DefineNum("ResultLost", INFO_LOST);
CBotProgram::DefineNum("ResultLostQuick", INFO_LOSTq);
CBotProgram::DefineNum("ResultWin", ERR_OK);
CBotProgram::DefineNum("BuildBotFactory", BUILD_FACTORY);
CBotProgram::DefineNum("BuildDerrick", BUILD_DERRICK);
CBotProgram::DefineNum("BuildConverter", BUILD_CONVERT);
CBotProgram::DefineNum("BuildRadarStation", BUILD_RADAR);
CBotProgram::DefineNum("BuildPowerPlant", BUILD_ENERGY);
CBotProgram::DefineNum("BuildNuclearPlant", BUILD_NUCLEAR);
CBotProgram::DefineNum("BuildPowerStation", BUILD_STATION);
CBotProgram::DefineNum("BuildRepairCenter", BUILD_REPAIR);
CBotProgram::DefineNum("BuildDefenseTower", BUILD_TOWER);
CBotProgram::DefineNum("BuildResearchCenter", BUILD_RESEARCH);
CBotProgram::DefineNum("BuildAutoLab", BUILD_LABO);
CBotProgram::DefineNum("BuildPowerCaptor", BUILD_PARA);
CBotProgram::DefineNum("BuildExchangePost", BUILD_INFO);
CBotProgram::DefineNum("BuildDestroyer", BUILD_DESTROYER);
CBotProgram::DefineNum("FlatGround", BUILD_GFLAT);
CBotProgram::DefineNum("UseFlags", BUILD_FLAG);
CBotProgram::DefineNum("ResearchTracked", RESEARCH_TANK);
CBotProgram::DefineNum("ResearchWinged", RESEARCH_FLY);
CBotProgram::DefineNum("ResearchShooter", RESEARCH_CANON);
CBotProgram::DefineNum("ResearchDefenseTower", RESEARCH_TOWER);
CBotProgram::DefineNum("ResearchNuclearPlant", RESEARCH_ATOMIC);
CBotProgram::DefineNum("ResearchThumper", RESEARCH_THUMP);
CBotProgram::DefineNum("ResearchShielder", RESEARCH_SHIELD);
CBotProgram::DefineNum("ResearchPhazerShooter", RESEARCH_PHAZER);
CBotProgram::DefineNum("ResearchLegged", RESEARCH_iPAW);
CBotProgram::DefineNum("ResearchOrgaShooter", RESEARCH_iGUN);
CBotProgram::DefineNum("ResearchRecycler", RESEARCH_RECYCLER);
CBotProgram::DefineNum("ResearchSubber", RESEARCH_SUBM);
CBotProgram::DefineNum("ResearchSniffer", RESEARCH_SNIFFER);
CBotProgram::DefineNum("PolskiPortalColobota", 1337);
CBotClass* bc;
// Add the class Point.
bc = new CBotClass("point", NULL, true); // intrinsic class
bc->AddItem("x", CBotTypFloat);
bc->AddItem("y", CBotTypFloat);
bc->AddItem("z", CBotTypFloat);
bc->AddFunction("point", rPoint, cPoint);
// Adds the class Object.
bc = new CBotClass("object", NULL);
bc->AddItem("category", CBotTypResult(CBotTypInt), PR_READ);
bc->AddItem("position", CBotTypResult(CBotTypClass, "point"), PR_READ);
bc->AddItem("orientation", CBotTypResult(CBotTypFloat), PR_READ);
bc->AddItem("pitch", CBotTypResult(CBotTypFloat), PR_READ);
bc->AddItem("roll", CBotTypResult(CBotTypFloat), PR_READ);
bc->AddItem("energyLevel", CBotTypResult(CBotTypFloat), PR_READ);
bc->AddItem("shieldLevel", CBotTypResult(CBotTypFloat), PR_READ);
bc->AddItem("temperature", CBotTypResult(CBotTypFloat), PR_READ);
bc->AddItem("altitude", CBotTypResult(CBotTypFloat), PR_READ);
bc->AddItem("lifeTime", CBotTypResult(CBotTypFloat), PR_READ);
bc->AddItem("material", CBotTypResult(CBotTypInt), PR_READ);
bc->AddItem("energyCell", CBotTypResult(CBotTypPointer, "object"), PR_READ);
bc->AddItem("load", CBotTypResult(CBotTypPointer, "object"), PR_READ);
bc->AddItem("id", CBotTypResult(CBotTypInt), PR_READ);
bc->AddFunction("busy", CScript::rBusy, CScript::cBusy);
bc->AddFunction("factory", CScript::rFactory, CScript::cFactory);
bc->AddFunction("research", CScript::rResearch, CScript::cClassOneFloat);
bc->AddFunction("takeoff", CScript::rTakeOff, CScript::cClassNull);
bc->AddFunction("destroy", CScript::rDestroy, CScript::cClassNull);
// Initializes the class FILE.
InitClassFILE();
CScript::InitFonctions();
}
//! Destructor of robot application
CRobotMain::~CRobotMain()
{
delete m_displayText;
m_displayText = nullptr;
delete m_interface;
m_interface = nullptr;
delete m_terrain;
m_terrain = nullptr;
delete m_camera;
m_camera = nullptr;
delete m_displayText;
m_displayText = nullptr;
delete m_movie;
m_movie = nullptr;
delete m_dialog;
m_dialog = nullptr;
delete m_short;
m_short = nullptr;
delete m_map;
m_map = nullptr;
m_app = nullptr;
}
Gfx::CCamera* CRobotMain::GetCamera()
{
return m_camera;
}
Gfx::CTerrain* CRobotMain::GetTerrain()
{
return m_terrain;
}
Ui::CInterface* CRobotMain::GetInterface()
{
return m_interface;
}
Ui::CDisplayText* CRobotMain::GetDisplayText()
{
return m_displayText;
}
void CRobotMain::LoadSceneOnStart(const std::string& name, int rank)
{
m_exitAfterMission = true;
// TODO: fix this ugly dependency :(
ChangePhase(PHASE_USER); // To load userlevel list
m_dialog->SetSceneName(name.c_str());
m_dialog->SetSceneRank(rank);
ChangePhase(PHASE_LOADING);
}
void CRobotMain::ResetAfterDeviceChanged()
{
if(m_phase == PHASE_SETUPds ||
m_phase == PHASE_SETUPgs ||
m_phase == PHASE_SETUPps ||
m_phase == PHASE_SETUPcs ||
m_phase == PHASE_SETUPss ||
m_phase == PHASE_SIMUL ||
m_phase == PHASE_WIN ||
m_phase == PHASE_LOST)
ChangeColor();
UpdateMap();
}
//! Creates the file colobot.ini at the first time
void CRobotMain::CreateIni()
{
m_dialog->SetupMemorize();
GetProfile().SetFloatProperty("Edit", "FontSize", m_fontSize);
GetProfile().SetFloatProperty("Edit", "WindowPosX", m_windowPos.x);
GetProfile().SetFloatProperty("Edit", "WindowPosY", m_windowPos.y);
GetProfile().SetFloatProperty("Edit", "WindowDimX", m_windowDim.x);
GetProfile().SetFloatProperty("Edit", "WindowDimY", m_windowDim.y);
GetProfile().SetIntProperty("Edit", "IOPublic", m_IOPublic);
GetProfile().SetFloatProperty("Edit", "IOPosX", m_IOPos.x);
GetProfile().SetFloatProperty("Edit", "IOPosY", m_IOPos.y);
GetProfile().SetFloatProperty("Edit", "IODimX", m_IODim.x);
GetProfile().SetFloatProperty("Edit", "IODimY", m_IODim.y);
GetProfile().Save();
}
void CRobotMain::SetDefaultInputBindings()
{
for (int i = 0; i < INPUT_SLOT_MAX; i++)
{
m_inputBindings[i].primary = m_inputBindings[i].secondary = KEY_INVALID;
}
for (int i = 0; i < JOY_AXIS_SLOT_MAX; i++)
{
m_joyAxisBindings[i].axis = AXIS_INVALID;
m_joyAxisBindings[i].invert = false;
}
m_inputBindings[INPUT_SLOT_LEFT ].primary = KEY(LEFT);
m_inputBindings[INPUT_SLOT_RIGHT ].primary = KEY(RIGHT);
m_inputBindings[INPUT_SLOT_UP ].primary = KEY(UP);
m_inputBindings[INPUT_SLOT_DOWN ].primary = KEY(DOWN);
m_inputBindings[INPUT_SLOT_LEFT ].secondary = KEY(a);
m_inputBindings[INPUT_SLOT_RIGHT ].secondary = KEY(d);
m_inputBindings[INPUT_SLOT_UP ].secondary = KEY(w);
m_inputBindings[INPUT_SLOT_DOWN ].secondary = KEY(s);
m_inputBindings[INPUT_SLOT_GUP ].primary = VIRTUAL_KMOD(SHIFT);
m_inputBindings[INPUT_SLOT_GDOWN ].primary = VIRTUAL_KMOD(CTRL);
m_inputBindings[INPUT_SLOT_CAMERA ].primary = KEY(SPACE);
// m_inputBindings[INPUT_SLOT_CAMERA ].secondary = VIRTUAL_JOY(2);
m_inputBindings[INPUT_SLOT_DESEL ].primary = KEY(KP0);
// m_inputBindings[INPUT_SLOT_DESEL ].secondary = VIRTUAL_JOY(6);
m_inputBindings[INPUT_SLOT_ACTION ].primary = KEY(RETURN);
// m_inputBindings[INPUT_SLOT_ACTION ].secondary = VIRTUAL_JOY(1);
m_inputBindings[INPUT_SLOT_ACTION ].secondary = KEY(e);
m_inputBindings[INPUT_SLOT_NEAR ].primary = KEY(KP_PLUS);
// m_inputBindings[INPUT_SLOT_NEAR ].secondary = VIRTUAL_JOY(5);
m_inputBindings[INPUT_SLOT_AWAY ].primary = KEY(KP_MINUS);
// m_inputBindings[INPUT_SLOT_AWAY ].secondary = VIRTUAL_JOY(4);
m_inputBindings[INPUT_SLOT_NEXT ].primary = KEY(TAB);
// m_inputBindings[INPUT_SLOT_NEXT ].secondary = VIRTUAL_JOY(3);
m_inputBindings[INPUT_SLOT_HUMAN ].primary = KEY(HOME);
// m_inputBindings[INPUT_SLOT_HUMAN ].secondary = VIRTUAL_JOY(7);
m_inputBindings[INPUT_SLOT_QUIT ].primary = KEY(ESCAPE);
m_inputBindings[INPUT_SLOT_HELP ].primary = KEY(F1);
m_inputBindings[INPUT_SLOT_PROG ].primary = KEY(F2);
m_inputBindings[INPUT_SLOT_CBOT ].primary = KEY(F3);
m_inputBindings[INPUT_SLOT_VISIT ].primary = KEY(KP_PERIOD);
m_inputBindings[INPUT_SLOT_SPEED10].primary = KEY(F4);
m_inputBindings[INPUT_SLOT_SPEED15].primary = KEY(F5);
m_inputBindings[INPUT_SLOT_SPEED20].primary = KEY(F6);
m_joyAxisBindings[JOY_AXIS_SLOT_X].axis = 0;
m_joyAxisBindings[JOY_AXIS_SLOT_Y].axis = 1;
m_joyAxisBindings[JOY_AXIS_SLOT_Z].axis = 2;
}
void CRobotMain::SetInputBinding(InputSlot slot, InputBinding binding)
{
unsigned int index = static_cast<unsigned int>(slot);
m_inputBindings[index] = binding;
}
const InputBinding& CRobotMain::GetInputBinding(InputSlot slot)
{
unsigned int index = static_cast<unsigned int>(slot);
return m_inputBindings[index];
}
void CRobotMain::SetJoyAxisBinding(JoyAxisSlot slot, JoyAxisBinding binding)
{
unsigned int index = static_cast<unsigned int>(slot);
m_joyAxisBindings[index] = binding;
}
const JoyAxisBinding& CRobotMain::GetJoyAxisBinding(JoyAxisSlot slot)
{
unsigned int index = static_cast<unsigned int>(slot);
return m_joyAxisBindings[index];
}
void CRobotMain::SetJoystickDeadzone(float zone)
{
m_joystickDeadzone = zone;
}
float CRobotMain::GetJoystickDeadzone()
{
return m_joystickDeadzone;
}
void CRobotMain::ResetKeyStates()
{
m_keyMotion = Math::Vector(0.0f, 0.0f, 0.0f);
m_joyMotion = Math::Vector(0.0f, 0.0f, 0.0f);
}
//! Changes phase
void CRobotMain::ChangePhase(Phase phase)
{
m_missionTimerEnabled = m_missionTimerStarted = false;
m_missionTimer = 0.0f;
if (m_phase == PHASE_SIMUL) // ends a simulation?
{
SaveAllScript();
m_sound->StopMusic(0.0f);
m_camera->SetControllingObject(0);
if (m_gameTime > 10.0f) // did you play at least 10 seconds?
{
int rank = m_dialog->GetSceneRank();
int numTry = m_dialog->GetGamerInfoTry(rank);
m_dialog->SetGamerInfoTry(rank, numTry+1);
m_dialog->WriteGamerInfo();
}
}
if (phase == PHASE_WIN) // wins a simulation?
{
int rank = m_dialog->GetSceneRank();
m_dialog->SetGamerInfoPassed(rank, true);
m_dialog->NextMission(); // passes to the next mission
m_dialog->WriteGamerInfo();
}
m_app->SetLowCPU(true); // doesn't use much CPU in interface phases
DeleteAllObjects(); // removes all the current 3D Scene
m_phase = phase;
m_winDelay = 0.0f;
m_lostDelay = 0.0f;
m_beginSatCom = false;
m_movieLock = false;
m_satComLock = false;
m_editLock = false;
m_freePhoto = false;
m_resetCreate = false;
m_engine->SetMovieLock(m_movieLock);
ChangePause(PAUSE_NONE);
FlushDisplayInfo();
m_engine->SetRankView(0);
m_terrain->FlushRelief();
m_engine->DeleteAllObjects();
Gfx::CModelManager::GetInstancePointer()->DeleteAllModelCopies();
m_engine->SetWaterAddColor(Gfx::Color(0.0f, 0.0f, 0.0f, 0.0f));
m_engine->SetBackground("");
m_engine->SetBackForce(false);
m_engine->SetForegroundName("");
m_engine->SetOverColor();
m_engine->DeleteGroundMark(0);
SetSpeed(1.0f);
m_terrain->SetWind(Math::Vector(0.0f, 0.0f, 0.0f));
m_terrain->FlushBuildingLevel();
m_terrain->FlushFlyingLimit();
m_lightMan->FlushLights();
m_particle->FlushParticle();
m_water->Flush();
m_cloud->Flush();
m_lightning->Flush();
m_planet->Flush();
m_interface->Flush();
ClearInterface();
FlushNewScriptName();
m_sound->SetListener(Math::Vector(0.0f, 0.0f, 0.0f), Math::Vector(0.0f, 0.0f, 1.0f));
m_camera->SetType(Gfx::CAM_TYPE_DIALOG);
m_movie->Flush();
m_movieInfoIndex = -1;
m_cameraPan = 0.0f;
m_cameraZoom = 0.0f;
m_shortCut = true;
CInstanceManager* iMan = CInstanceManager::GetInstancePointer();
iMan->Flush(CLASS_OBJECT);
iMan->Flush(CLASS_PHYSICS);
iMan->Flush(CLASS_BRAIN);
iMan->Flush(CLASS_PYRO);
CObjectManager::GetInstancePointer()->Flush();
Math::Point dim, pos;
// Creates and hide the command console.
dim.x = 200.0f/640.0f;
dim.y = 18.0f/480.0f;
pos.x = 50.0f/640.0f;
pos.y = 452.0f/480.0f;
Ui::CEdit* pe = static_cast<Ui::CEdit*>(m_interface->CreateEdit(pos, dim, 0, EVENT_CMD));
if (pe == nullptr) return;
pe->ClearState(Ui::STATE_VISIBLE);
m_cmdEdit = false; // hidden for now
// Creates the speedometer.
dim.x = 30.0f/640.0f;
dim.y = 20.0f/480.0f;
pos.x = 4.0f/640.0f;
pos.y = 426.0f/480.0f;
Ui::CButton* pb = m_interface->CreateButton(pos, dim, 0, EVENT_SPEED);
if (pb == nullptr) return;
pb->SetState(Ui::STATE_SIMPLY);
pb->ClearState(Ui::STATE_VISIBLE);
m_dialog->ChangePhase(m_phase);
dim.x = 32.0f/640.0f;
dim.y = 32.0f/480.0f;
float ox = 3.0f/640.0f;
float oy = 3.0f/480.0f;
float sx = (32.0f+2.0f)/640.0f;
float sy = (32.0f+2.0f)/480.0f;
if (m_phase != PHASE_PERSO)
{
m_engine->SetDrawWorld(true);
m_engine->SetDrawFront(false);
m_fixScene = false;
}
if (m_phase == PHASE_INIT)
{
m_engine->DeleteTexture("generic.png");
}
if (m_phase == PHASE_SIMUL)
{
m_engine->DeleteTexture("interface.png");
m_app->SetLowCPU(false); // high CPU for simulation
bool loading = (m_dialog->GetSceneRead()[0] != 0);
m_map->CreateMap();
try {
CreateScene(m_dialog->GetSceneSoluce(), false, false); // interactive scene
if (m_mapImage)
m_map->SetFixImage(m_mapFilename);
m_app->ResetTimeAfterLoading();
if (m_immediatSatCom && !loading &&
m_infoFilename[SATCOM_HUSTON][0] != 0)
StartDisplayInfo(SATCOM_HUSTON, false); // shows the instructions
m_sound->StopMusic(0.0f);
if (m_base == nullptr || loading) StartMusic();
}
catch(const CLevelParserException& e)
{
CLogger::GetInstancePointer()->Error("An error occured while trying to load a level\n");
CLogger::GetInstancePointer()->Error("%s\n", e.what());
ChangePhase(PHASE_INIT);
}
}
if (m_phase == PHASE_WIN)
{
m_sound->StopAll();
if (m_endingWinRank == -1)
{
ChangePhase(PHASE_TERM);
}
else
{
m_winTerminate = (m_endingWinRank == 904);
m_dialog->SetSceneName("win");
m_dialog->SetSceneRank(m_endingWinRank);
try {
CreateScene(false, true, false); // sets scene
pos.x = ox+sx*1; pos.y = oy+sy*1;
Math::Point ddim;
ddim.x = dim.x*2; ddim.y = dim.y*2;
m_interface->CreateButton(pos, ddim, 16, EVENT_BUTTON_OK);
if (m_winTerminate)
{
pos.x = ox+sx*3; pos.y = oy+sy*0.2f;
ddim.x = dim.x*15; ddim.y = dim.y*3.0f;
pe = m_interface->CreateEdit(pos, ddim, 0, EVENT_EDIT0);
pe->SetGenericMode(true);
pe->SetFontType(Gfx::FONT_COLOBOT);
pe->SetEditCap(false);
pe->SetHighlightCap(false);
pe->ReadText(std::string("help/") + m_app->GetLanguageChar() + std::string("/win.txt"));
}
else
{
m_displayText->DisplayError(INFO_WIN, Math::Vector(0.0f,0.0f,0.0f), 15.0f, 60.0f, 1000.0f);
}
StartMusic();
}
catch(const CLevelParserException& e)
{
CLogger::GetInstancePointer()->Error("An error occured while trying to load win scene\n");
CLogger::GetInstancePointer()->Error("%s\n", e.what());
ChangePhase(PHASE_TERM);
}
}
}
if (m_phase == PHASE_LOST)
{
m_sound->StopAll();
if (m_endingLostRank == -1)
{
ChangePhase(PHASE_TERM);
}
else
{
m_winTerminate = false;
m_dialog->SetSceneName("lost");
m_dialog->SetSceneRank(m_endingLostRank);
try {
CreateScene(false, true, false); // sets scene
pos.x = ox+sx*1; pos.y = oy+sy*1;
Math::Point ddim;
ddim.x = dim.x*2; ddim.y = dim.y*2;
m_interface->CreateButton(pos, ddim, 16, EVENT_BUTTON_OK);
m_displayText->DisplayError(INFO_LOST, Math::Vector(0.0f,0.0f,0.0f), 15.0f, 60.0f, 1000.0f);
StartMusic();
}
catch(const CLevelParserException& e)
{
CLogger::GetInstancePointer()->Error("An error occured while trying to load lost scene\n");
CLogger::GetInstancePointer()->Error("%s\n", e.what());
ChangePhase(PHASE_TERM);
}
}
}
if (m_phase == PHASE_LOADING)
m_app->SetMouseMode(MOUSE_NONE);
else
m_app->SetMouseMode(MOUSE_ENGINE);
m_engine->LoadAllTextures();
}
//! Processes an event
bool CRobotMain::ProcessEvent(Event &event)
{
/* Motion vector management */
if (event.type == EVENT_KEY_DOWN)
{
if (event.key.key == GetInputBinding(INPUT_SLOT_UP ).primary) m_keyMotion.y = 1.0f;
if (event.key.key == GetInputBinding(INPUT_SLOT_UP ).secondary) m_keyMotion.y = 1.0f;
if (event.key.key == GetInputBinding(INPUT_SLOT_DOWN ).primary) m_keyMotion.y = -1.0f;
if (event.key.key == GetInputBinding(INPUT_SLOT_DOWN ).secondary) m_keyMotion.y = -1.0f;
if (event.key.key == GetInputBinding(INPUT_SLOT_LEFT ).primary) m_keyMotion.x = -1.0f;
if (event.key.key == GetInputBinding(INPUT_SLOT_LEFT ).secondary) m_keyMotion.x = -1.0f;
if (event.key.key == GetInputBinding(INPUT_SLOT_RIGHT).primary) m_keyMotion.x = 1.0f;
if (event.key.key == GetInputBinding(INPUT_SLOT_RIGHT).secondary) m_keyMotion.x = 1.0f;
if (event.key.key == GetInputBinding(INPUT_SLOT_GUP ).primary) m_keyMotion.z = 1.0f;
if (event.key.key == GetInputBinding(INPUT_SLOT_GUP ).secondary) m_keyMotion.z = 1.0f;
if (event.key.key == GetInputBinding(INPUT_SLOT_GDOWN).primary) m_keyMotion.z = -1.0f;
if (event.key.key == GetInputBinding(INPUT_SLOT_GDOWN).secondary) m_keyMotion.z = -1.0f;
}
else if (event.type == EVENT_KEY_UP)
{
if (event.key.key == GetInputBinding(INPUT_SLOT_UP ).primary) m_keyMotion.y = 0.0f;
if (event.key.key == GetInputBinding(INPUT_SLOT_UP ).secondary) m_keyMotion.y = 0.0f;
if (event.key.key == GetInputBinding(INPUT_SLOT_DOWN ).primary) m_keyMotion.y = 0.0f;
if (event.key.key == GetInputBinding(INPUT_SLOT_DOWN ).secondary) m_keyMotion.y = 0.0f;
if (event.key.key == GetInputBinding(INPUT_SLOT_LEFT ).primary) m_keyMotion.x = 0.0f;
if (event.key.key == GetInputBinding(INPUT_SLOT_LEFT ).secondary) m_keyMotion.x = 0.0f;
if (event.key.key == GetInputBinding(INPUT_SLOT_RIGHT).primary) m_keyMotion.x = 0.0f;
if (event.key.key == GetInputBinding(INPUT_SLOT_RIGHT).secondary) m_keyMotion.x = 0.0f;
if (event.key.key == GetInputBinding(INPUT_SLOT_GUP ).primary) m_keyMotion.z = 0.0f;
if (event.key.key == GetInputBinding(INPUT_SLOT_GUP ).secondary) m_keyMotion.z = 0.0f;
if (event.key.key == GetInputBinding(INPUT_SLOT_GDOWN).primary) m_keyMotion.z = 0.0f;
if (event.key.key == GetInputBinding(INPUT_SLOT_GDOWN).secondary) m_keyMotion.z = 0.0f;
}
else if (event.type == EVENT_JOY_AXIS)
{
if (event.joyAxis.axis == GetJoyAxisBinding(JOY_AXIS_SLOT_X).axis)
{
m_joyMotion.x = Math::Neutral(event.joyAxis.value / 32768.0f, m_joystickDeadzone);
if (GetJoyAxisBinding(JOY_AXIS_SLOT_X).invert)
m_joyMotion.x *= -1.0f;
}
if (event.joyAxis.axis == GetJoyAxisBinding(JOY_AXIS_SLOT_Y).axis)
{
m_joyMotion.y = Math::Neutral(event.joyAxis.value / 32768.0f, m_joystickDeadzone);
if (GetJoyAxisBinding(JOY_AXIS_SLOT_Y).invert)
m_joyMotion.y *= -1.0f;
}
if (event.joyAxis.axis == GetJoyAxisBinding(JOY_AXIS_SLOT_Z).axis)
{
m_joyMotion.z = Math::Neutral(event.joyAxis.value / 32768.0f, m_joystickDeadzone);
if (GetJoyAxisBinding(JOY_AXIS_SLOT_Z).invert)
m_joyMotion.z *= -1.0f;
}
}
event.motionInput = Math::Clamp(m_joyMotion + m_keyMotion, Math::Vector(-1.0f, -1.0f, -1.0f), Math::Vector(1.0f, 1.0f, 1.0f));
if (event.type == EVENT_FRAME)
{
if (!m_movie->EventProcess(event)) // end of the movie?
{
MainMovieType type = m_movie->GetStopType();
if (type == MM_SATCOMopen)
{
ChangePause(PAUSE_NONE);
SelectObject(m_infoObject, false); // hands over the command buttons
m_map->ShowMap(m_mapShow);
m_displayText->HideText(false);
int i = m_movieInfoIndex;
StartDisplayInfo(m_movieInfoIndex, false);
m_movieInfoIndex = i;
}
}
m_dialog->EventProcess(event);
m_displayText->EventProcess(event);
RemoteCamera(m_cameraPan, m_cameraZoom, event.rTime);
m_interface->EventProcess(event);
if (m_displayInfo != nullptr) // current edition?
m_displayInfo->EventProcess(event);
UpdateInfoText();
return EventFrame(event);
}
// Management of the console.
if (m_phase != PHASE_NAME &&
!m_movie->IsExist() &&
!m_movieLock && !m_editLock && !m_engine->GetPause() &&
event.type == EVENT_KEY_DOWN &&
event.key.key == KEY(BACKQUOTE)) // Pause ?
{
Ui::CEdit* pe = static_cast<Ui::CEdit*>(m_interface->SearchControl(EVENT_CMD));
if (pe == nullptr) return false;
pe->SetState(Ui::STATE_VISIBLE);
pe->SetFocus(true);
if (m_phase == PHASE_SIMUL) ChangePause(PAUSE_CHEAT);
m_cmdEdit = true;
return false;
}
if (event.type == EVENT_KEY_DOWN &&
event.key.key == KEY(RETURN) && m_cmdEdit)
{
char cmd[50];
Ui::CEdit* pe = static_cast<Ui::CEdit*>(m_interface->SearchControl(EVENT_CMD));
if (pe == nullptr) return false;
pe->GetText(cmd, 50);
pe->SetText("");
pe->ClearState(Ui::STATE_VISIBLE);
if (m_phase == PHASE_SIMUL) ChangePause(PAUSE_NONE);
ExecuteCmd(cmd);
m_cmdEdit = false;
return false;
}
// Management of the speed change.
if (event.type == EVENT_SPEED)
SetSpeed(1.0f);
if (!m_dialog->EventProcess(event))
{
if (event.type == EVENT_MOUSE_MOVE)
{
m_lastMousePos = event.mousePos;
HiliteObject(event.mousePos);
}
return false;
}
if (!m_displayText->EventProcess(event))
return false;
if (event.type == EVENT_MOUSE_MOVE)
{
m_lastMousePos = event.mousePos;
HiliteObject(event.mousePos);
}
if (m_displayInfo != nullptr) // current info?
{
m_displayInfo->EventProcess(event);
if (event.type == EVENT_KEY_DOWN)
{
if (event.key.key == GetInputBinding(INPUT_SLOT_HELP).primary ||
event.key.key == GetInputBinding(INPUT_SLOT_HELP).secondary ||
event.key.key == GetInputBinding(INPUT_SLOT_PROG).primary ||
event.key.key == GetInputBinding(INPUT_SLOT_PROG).secondary ||
event.key.key == KEY(ESCAPE))
{
StopDisplayInfo();
}
}
if (event.type == EVENT_OBJECT_INFOOK)
StopDisplayInfo();
return false;
}
CObject* obj;
// Simulation phase of the game
if (m_phase == PHASE_SIMUL)
{
if (!m_editFull)
m_camera->EventProcess(event);
switch (event.type)
{
case EVENT_KEY_DOWN:
KeyCamera(event.type, event.key.key);
HiliteClear();
if (event.key.key == KEY(F11))
{
m_particle->WriteWheelTrace("Savegame/t.png", 256, 256, Math::Vector(16.0f, 0.0f, -368.0f), Math::Vector(140.0f, 0.0f, -248.0f));
return false;
}
if (m_editLock) // current edition?
{
if (event.key.key == GetInputBinding(INPUT_SLOT_HELP).primary ||
event.key.key == GetInputBinding(INPUT_SLOT_HELP).secondary)
{
StartDisplayInfo(SATCOM_HUSTON, false);
return false;
}
if (event.key.key == GetInputBinding(INPUT_SLOT_PROG).primary ||
event.key.key == GetInputBinding(INPUT_SLOT_PROG).secondary)
{
StartDisplayInfo(SATCOM_PROG, false);
return false;
}
break;
}
if (m_movieLock) // current movie?
{
if (event.key.key == GetInputBinding(INPUT_SLOT_QUIT).primary ||
event.key.key == GetInputBinding(INPUT_SLOT_QUIT).secondary ||
event.key.key == KEY(ESCAPE))
{
AbortMovie();
}
return false;
}
if (m_camera->GetType() == Gfx::CAM_TYPE_VISIT)
{
if (event.key.key == GetInputBinding(INPUT_SLOT_VISIT).primary ||
event.key.key == GetInputBinding(INPUT_SLOT_VISIT).secondary)
{
StartDisplayVisit(EVENT_NULL);
}
if (event.key.key == GetInputBinding(INPUT_SLOT_QUIT).primary ||
event.key.key == GetInputBinding(INPUT_SLOT_QUIT).secondary ||
event.key.key == KEY(ESCAPE))
{
StopDisplayVisit();
}
return false;
}
if (event.key.key == GetInputBinding(INPUT_SLOT_QUIT).primary ||
event.key.key == GetInputBinding(INPUT_SLOT_QUIT).secondary)
{
if (m_movie->IsExist())
StartDisplayInfo(SATCOM_HUSTON, false);
else if (m_winDelay > 0.0f)
ChangePhase(PHASE_WIN);
else if (m_lostDelay > 0.0f)
ChangePhase(PHASE_LOST);
else if (!m_cmdEdit)
m_dialog->StartAbort(); // do you want to leave?
}
if (event.key.key == KEY(PAUSE))
{
if (!m_movieLock && !m_editLock && !m_cmdEdit &&
m_camera->GetType() != Gfx::CAM_TYPE_VISIT &&
!m_movie->IsExist())
{
ChangePause(m_pause->GetPause(PAUSE_USER) ? PAUSE_NONE : PAUSE_USER);
}
}
if (event.key.key == GetInputBinding(INPUT_SLOT_CAMERA).primary ||
event.key.key == GetInputBinding(INPUT_SLOT_CAMERA).secondary)
{
ChangeCamera();
}
if (event.key.key == GetInputBinding(INPUT_SLOT_DESEL).primary ||
event.key.key == GetInputBinding(INPUT_SLOT_DESEL).secondary)
{
if (m_shortCut)
DeselectObject();
}
if (event.key.key == GetInputBinding(INPUT_SLOT_HUMAN).primary ||
event.key.key == GetInputBinding(INPUT_SLOT_HUMAN).secondary)
{
SelectHuman();
}
if (event.key.key == GetInputBinding(INPUT_SLOT_NEXT).primary ||
event.key.key == GetInputBinding(INPUT_SLOT_NEXT).secondary)
{
if (m_shortCut)
m_short->SelectNext();
}
if (event.key.key == GetInputBinding(INPUT_SLOT_HELP).primary ||
event.key.key == GetInputBinding(INPUT_SLOT_HELP).secondary)
{
StartDisplayInfo(SATCOM_HUSTON, true);
}
if (event.key.key == GetInputBinding(INPUT_SLOT_PROG).primary ||
event.key.key == GetInputBinding(INPUT_SLOT_PROG).secondary)
{
StartDisplayInfo(SATCOM_PROG, true);
}
if (event.key.key == GetInputBinding(INPUT_SLOT_VISIT).primary ||
event.key.key == GetInputBinding(INPUT_SLOT_VISIT).secondary)
{
StartDisplayVisit(EVENT_NULL);
}
if (event.key.key == GetInputBinding(INPUT_SLOT_SPEED10).primary ||
event.key.key == GetInputBinding(INPUT_SLOT_SPEED10).secondary)
{
SetSpeed(1.0f);
}
if (event.key.key == GetInputBinding(INPUT_SLOT_SPEED15).primary ||
event.key.key == GetInputBinding(INPUT_SLOT_SPEED15).secondary)
{
SetSpeed(1.5f);
}
if (event.key.key == GetInputBinding(INPUT_SLOT_SPEED20).primary ||
event.key.key == GetInputBinding(INPUT_SLOT_SPEED20).secondary)
{
SetSpeed(2.0f);
}
break;
case EVENT_KEY_UP:
KeyCamera(event.type, event.key.key);
break;
case EVENT_MOUSE_BUTTON_DOWN:
if (event.mouseButton.button != MOUSE_BUTTON_LEFT) // only left mouse button
break;
obj = DetectObject(event.mousePos);
if (!m_shortCut) obj = nullptr;
if (obj != nullptr && obj->GetType() == OBJECT_TOTO)
{
if (m_displayInfo != nullptr) // current info?
{
StopDisplayInfo();
}
else
{
if (!m_editLock)
StartDisplayInfo(SATCOM_HUSTON, true);
}
}
else
SelectObject(obj);
break;
case EVENT_MOUSE_BUTTON_UP:
if (event.mouseButton.button != MOUSE_BUTTON_LEFT) // only left mouse button
break;
m_cameraPan = 0.0f;
m_cameraZoom = 0.0f;
break;
case EVENT_OBJECT_LIMIT:
StartShowLimit();
break;
case EVENT_OBJECT_DESELECT:
if (m_shortCut)
DeselectObject();
break;
case EVENT_OBJECT_HELP:
HelpObject();
break;
case EVENT_OBJECT_CAMERA:
ChangeCamera();
break;
case EVENT_OBJECT_CAMERAleft:
m_cameraPan = -1.0f;
break;
case EVENT_OBJECT_CAMERAright:
m_cameraPan = 1.0f;
break;
case EVENT_OBJECT_CAMERAnear:
m_cameraZoom = -1.0f;
break;
case EVENT_OBJECT_CAMERAaway:
m_cameraZoom = 1.0f;
break;
case EVENT_OBJECT_DELETE:
m_dialog->StartDeleteObject(); // do you want to destroy it?
break;
case EVENT_OBJECT_BHELP:
StartDisplayInfo(SATCOM_HUSTON, true);
break;
case EVENT_OBJECT_SOLUCE:
StartDisplayInfo(SATCOM_SOLUCE, true);
break;
case EVENT_OBJECT_MAPZOOM:
m_map->ZoomMap();
break;
case EVENT_DT_VISIT0:
case EVENT_DT_VISIT1:
case EVENT_DT_VISIT2:
case EVENT_DT_VISIT3:
case EVENT_DT_VISIT4:
StartDisplayVisit(event.type);
break;
case EVENT_DT_END:
StopDisplayVisit();
break;
case EVENT_OBJECT_SHORTCUT00:
case EVENT_OBJECT_SHORTCUT01:
case EVENT_OBJECT_SHORTCUT02:
case EVENT_OBJECT_SHORTCUT03:
case EVENT_OBJECT_SHORTCUT04:
case EVENT_OBJECT_SHORTCUT05:
case EVENT_OBJECT_SHORTCUT06:
case EVENT_OBJECT_SHORTCUT07:
case EVENT_OBJECT_SHORTCUT08:
case EVENT_OBJECT_SHORTCUT09:
case EVENT_OBJECT_SHORTCUT10:
case EVENT_OBJECT_SHORTCUT11:
case EVENT_OBJECT_SHORTCUT12:
case EVENT_OBJECT_SHORTCUT13:
case EVENT_OBJECT_SHORTCUT14:
case EVENT_OBJECT_SHORTCUT15:
case EVENT_OBJECT_SHORTCUT16:
case EVENT_OBJECT_SHORTCUT17:
case EVENT_OBJECT_SHORTCUT18:
case EVENT_OBJECT_SHORTCUT19:
m_short->SelectShortcut(event.type);
break;
case EVENT_OBJECT_MOVIELOCK:
AbortMovie();
break;
case EVENT_WIN:
m_missionTimerEnabled = m_missionTimerStarted = false;
ChangePhase(PHASE_WIN);
break;
case EVENT_LOST:
m_missionTimerEnabled = m_missionTimerStarted = false;
ChangePhase(PHASE_LOST);
break;
default:
break;
}
EventObject(event);
return false;
}
if (m_phase == PHASE_PERSO)
EventObject(event);
if (m_phase == PHASE_WIN ||
m_phase == PHASE_LOST)
{
EventObject(event);
switch (event.type)
{
case EVENT_KEY_DOWN:
if (event.key.key == KEY(ESCAPE) ||
event.key.key == KEY(RETURN))
{
if (m_winTerminate)
ChangePhase(PHASE_INIT);
else
ChangePhase(PHASE_TERM);
}
break;
case EVENT_BUTTON_OK:
if (m_winTerminate)
ChangePhase(PHASE_INIT);
else
ChangePhase(PHASE_TERM);
break;
default:
break;
}
}
return true;
}
//! Executes a command
void CRobotMain::ExecuteCmd(char *cmd)
{
if (cmd[0] == 0) return;
if (m_phase == PHASE_SIMUL)
{
if (strcmp(cmd, "winmission") == 0)
m_eventQueue->AddEvent(Event(EVENT_WIN));
if (strcmp(cmd, "lostmission") == 0)
m_eventQueue->AddEvent(Event(EVENT_LOST));
if (strcmp(cmd, "trainerpilot") == 0)
{
m_trainerPilot = !m_trainerPilot;
return;
}
if (strcmp(cmd, "fly") == 0)
{
g_researchDone |= RESEARCH_FLY;
m_eventQueue->AddEvent(Event(EVENT_UPDINTERFACE));
return;
}
if (strcmp(cmd, "allresearch") == 0)
{
g_researchDone = -1; // all research are done
m_eventQueue->AddEvent(Event(EVENT_UPDINTERFACE));
return;
}
if (strcmp(cmd, "allbuildings") == 0)
{
g_build = -1; // all buildings are available
m_eventQueue->AddEvent(Event(EVENT_UPDINTERFACE));
return;
}
if (strcmp(cmd, "all") == 0)
{
g_researchDone = -1; // all research are done
g_build = -1; // all buildings are available
m_eventQueue->AddEvent(Event(EVENT_UPDINTERFACE));
return;
}
if (strcmp(cmd, "nolimit") == 0)
{
m_terrain->SetFlyingMaxHeight(280.0f);
return;
}
if (strcmp(cmd, "controller") == 0)
{
if (m_controller != nullptr)
{
// Don't use SelectObject because it checks if the object is selectable
if (m_camera->GetType() == Gfx::CAM_TYPE_VISIT)
StopDisplayVisit();
CObject* prev = DeselectAll();
if (prev != nullptr && prev != m_controller)
m_controller->AddDeselList(prev);
SelectOneObject(m_controller, true);
m_short->UpdateShortcuts();
}
return;
}
if (strcmp(cmd, "photo1") == 0)
{
m_freePhoto = !m_freePhoto;
if (m_freePhoto)
{
m_camera->SetType(Gfx::CAM_TYPE_FREE);
ChangePause(PAUSE_PHOTO);
}
else
{
m_camera->SetType(Gfx::CAM_TYPE_BACK);
ChangePause(PAUSE_NONE);
}
return;
}
if (strcmp(cmd, "photo2") == 0)
{
m_freePhoto = !m_freePhoto;
if (m_freePhoto)
{
m_camera->SetType(Gfx::CAM_TYPE_FREE);
ChangePause(PAUSE_PHOTO);
DeselectAll(); // removes the control buttons
m_map->ShowMap(false);
m_displayText->HideText(true);
}
else
{
m_camera->SetType(Gfx::CAM_TYPE_BACK);
ChangePause(PAUSE_NONE);
m_map->ShowMap(m_mapShow);
m_displayText->HideText(false);
}
return;
}
if (strcmp(cmd, "noclip") == 0)
{
CObject* object = GetSelect();
if (object != nullptr)
object->SetClip(false);
return;
}
if (strcmp(cmd, "clip") == 0)
{
CObject* object = GetSelect();
if (object != nullptr)
object->SetClip(true);
return;
}
if (strcmp(cmd, "addhusky") == 0)
{
CObject* object = GetSelect();
if (object != nullptr)
object->SetMagnifyDamage(object->GetMagnifyDamage()*0.1f);
return;
}
if (strcmp(cmd, "addfreezer") == 0)
{
CObject* object = GetSelect();
if (object != nullptr)
object->SetRange(object->GetRange()*10.0f);
return;
}
if (strcmp(cmd, "\155\157\157") == 0)
{
// VGhpcyBpcyBlYXN0ZXItZWdnIGFuZCBzbyBpdCBzaG91bGQgYmUgb2JmdXNjYXRlZCEgRG8gbm90
// IGNsZWFuLXVwIHRoaXMgY29kZSEK
GetLogger()->Info(" _________________________\n");
GetLogger()->Info("< \x50\x6F\x6C\x73\x6B\x69 \x50\x6F\x72\x74\x61\x6C C\x6F\x6C\x6F\x62\x6F\x74\x61! \x3E\n");
GetLogger()->Info(" -------------------------\n");
GetLogger()->Info(" \x5C\x20\x20\x20\x5E\x5F\x5F\x5E\n");
GetLogger()->Info(" \x20\x5C\x20\x20\x28\x6F\x6F\x29\x5C\x5F\x5F\x5F\x5F\x5F\x5F\x5F\n");
GetLogger()->Info(" \x28\x5F\x5F\x29\x5C \x20\x20\x20\x20\x29\x5C\x2F\x5C\n");
GetLogger()->Info(" \x20\x20\x20\x20\x7C|\x2D\x2D\x2D\x2D\x77\x20\x7C\n");
GetLogger()->Info(" \x20\x20 \x7C\x7C\x20\x20\x20\x20 ||\n");
}
if (strcmp(cmd, "fullpower") == 0)
{
CObject* object = GetSelect();
if (object != nullptr)
{
CObject* power = object->GetPower();
if (power != nullptr)
power->SetEnergy(1.0f);
object->SetShield(1.0f);
CPhysics* physics = object->GetPhysics();
if (physics != nullptr)
physics->SetReactorRange(1.0f);
}
return;
}
if (strcmp(cmd, "fullenergy") == 0)
{
CObject* object = GetSelect();
if (object != nullptr)
{
CObject* power = object->GetPower();
if (power != nullptr)
power->SetEnergy(1.0f);
}
return;
}
if (strcmp(cmd, "fullshield") == 0)
{
CObject* object = GetSelect();
if (object != nullptr)
object->SetShield(1.0f);
return;
}
if (strcmp(cmd, "fullrange") == 0)
{
CObject* object = GetSelect();
if (object != nullptr)
{
CPhysics* physics = object->GetPhysics();
if (physics != nullptr)
physics->SetReactorRange(1.0f);
}
return;
}
}
if (strcmp(cmd, "debugmode") == 0)
{
if (m_app->IsDebugModeActive(DEBUG_ALL))
{
m_app->SetDebugModeActive(DEBUG_ALL, false);
}
else
{
m_app->SetDebugModeActive(DEBUG_ALL, true);
}
return;
}
if (strcmp(cmd, "showstat") == 0)
{
m_engine->SetShowStats(!m_engine->GetShowStats());
return;
}
if (strcmp(cmd, "invshadow") == 0)
{
m_engine->SetShadow(!m_engine->GetShadow());
return;
}
if (strcmp(cmd, "invdirty") == 0)
{
m_engine->SetDirty(!m_engine->GetDirty());
return;
}
if (strcmp(cmd, "invfog") == 0)
{
m_engine->SetFog(!m_engine->GetFog());
return;
}
if (strcmp(cmd, "invlens") == 0)
{
m_engine->SetLensMode(!m_engine->GetLensMode());
return;
}
if (strcmp(cmd, "invwater") == 0)
{
m_engine->SetWaterMode(!m_engine->GetWaterMode());
return;
}
if (strcmp(cmd, "invsky") == 0)
{
m_engine->SetSkyMode(!m_engine->GetSkyMode());
return;
}
if (strcmp(cmd, "invplanet") == 0)
{
m_engine->SetPlanetMode(!m_engine->GetPlanetMode());
return;
}
if (strcmp(cmd, "selectinsect") == 0)
{
m_selectInsect = !m_selectInsect;
return;
}
if (strcmp(cmd, "showsoluce") == 0)
{
m_showSoluce = !m_showSoluce;
m_dialog->ShowSoluceUpdate();
return;
}
if (strcmp(cmd, "allmission") == 0)
{
m_showAll = !m_showAll;
m_dialog->AllMissionUpdate();
return;
}
if (strcmp(cmd, "invradar") == 0)
{
m_cheatRadar = !m_cheatRadar;
return;
}
if (strcmp(cmd, "speed4") == 0)
{
SetSpeed(4.0f);
UpdateSpeedLabel();
return;
}
if (strcmp(cmd, "speed8") == 0)
{
SetSpeed(8.0f);
UpdateSpeedLabel();
return;
}
if (strcmp(cmd, "crazy") == 0)
{
SetSpeed(1000.0f);
UpdateSpeedLabel();
return;
}
if (m_phase == PHASE_SIMUL)
m_displayText->DisplayError(ERR_CMD, Math::Vector(0.0f,0.0f,0.0f));
}
//! Returns the type of current movie
MainMovieType CRobotMain::GetMainMovie()
{
return m_movie->GetType();
}
//! Clears the display of instructions
void CRobotMain::FlushDisplayInfo()
{
for (int i = 0; i < SATCOM_MAX; i++)
{
m_infoFilename[i][0] = 0;
m_infoPos[i] = 0;
}
strcpy(m_infoFilename[SATCOM_OBJECT], "objects.txt");
m_infoIndex = 0;
}
//! Beginning of the displaying of instructions.
//! index: SATCOM_*
void CRobotMain::StartDisplayInfo(int index, bool movie)
{
if (m_cmdEdit || m_satComLock || m_lockedSatCom) return;
CObject* obj = GetSelect();
bool human = obj != nullptr && obj->GetType() == OBJECT_HUMAN;
if (!m_editLock && movie && !m_movie->IsExist() && human)
{
CMotion* motion = obj->GetMotion();
if (motion != nullptr && motion->GetAction() == -1)
{
m_movieInfoIndex = index;
m_movie->Start(MM_SATCOMopen, 2.5f);
ChangePause(PAUSE_SATCOMMOVIE);
m_infoObject = DeselectAll(); // removes the control buttons
m_displayText->HideText(true);
return;
}
}
if (m_movie->IsExist())
{
m_movie->Stop();
ChangePause(PAUSE_NONE);
SelectObject(m_infoObject, false); // hands over the command buttons
m_displayText->HideText(false);
}
StartDisplayInfo(m_infoFilename[index], index);
}
//! Beginning of the displaying of instructions
void CRobotMain::StartDisplayInfo(const char *filename, int index)
{
if (m_cmdEdit) return;
m_movieInfoIndex = -1;
ClearInterface(); // removes setting evidence and tooltip
if (!m_editLock)
{
m_infoObject = DeselectAll(); // removes the control buttons
m_displayText->HideText(true);
m_sound->MuteAll(true);
}
bool soluce = m_dialog->GetSceneSoluce();
m_displayInfo = new Ui::CDisplayInfo();
m_displayInfo->StartDisplayInfo(filename, index, soluce);
m_infoIndex = index;
if (index != -1)
m_displayInfo->SetPosition(m_infoPos[index]);
}
//! End of displaying of instructions
void CRobotMain::StopDisplayInfo()
{
if (m_cmdEdit) return;
if (m_movieInfoIndex != -1) // film to read the SatCom?
m_movie->Start(MM_SATCOMclose, 2.0f);
if (m_infoIndex != -1)
m_infoPos[m_infoIndex] = m_displayInfo->GetPosition();
m_displayInfo->StopDisplayInfo();
delete m_displayInfo;
m_displayInfo = nullptr;
if (!m_editLock)
{
SelectObject(m_infoObject, false); // gives the command buttons
m_displayText->HideText(false);
m_sound->MuteAll(false);
}
if (m_infoUsed == 0)
m_displayText->ClearText(); // removes message "see SatCom ..."
m_infoUsed ++;
}
//! Returns the name of the text display
char* CRobotMain::GetDisplayInfoName(int index)
{
return m_infoFilename[index];
}
//! Returns the name of the text display
int CRobotMain::GetDisplayInfoPosition(int index)
{
return m_infoPos[index];
}
//! Returns the name of the text display
void CRobotMain::SetDisplayInfoPosition(int index, int pos)
{
m_infoPos[index] = pos;
}
//! Beginning of a dialogue during the game
void CRobotMain::StartSuspend()
{
m_map->ShowMap(false);
m_infoObject = DeselectAll(); // removes the control buttons
m_displayText->HideText(true);
m_suspend = true;
}
//! End of dialogue during the game
void CRobotMain::StopSuspend()
{
SelectObject(m_infoObject, false); // gives the command buttons
m_map->ShowMap(m_mapShow);
m_displayText->HideText(false);
m_suspend = false;
}
//! Returns the absolute time of the game
float CRobotMain::GetGameTime()
{
return m_gameTime;
}
//! Managing the size of the default fonts
void CRobotMain::SetFontSize(float size)
{
m_fontSize = size;
GetProfile().SetFloatProperty("Edit", "FontSize", m_fontSize);
}
float CRobotMain::GetFontSize()
{
return m_fontSize;
}
//! Managing the size of the default window
void CRobotMain::SetWindowPos(Math::Point pos)
{
m_windowPos = pos;
GetProfile().SetFloatProperty("Edit", "WindowPosX", m_windowPos.x);
GetProfile().SetFloatProperty("Edit", "WindowPosY", m_windowPos.y);
}
Math::Point CRobotMain::GetWindowPos()
{
return m_windowPos;
}
void CRobotMain::SetWindowDim(Math::Point dim)
{
m_windowDim = dim;
GetProfile().SetFloatProperty("Edit", "WindowDimX", m_windowDim.x);
GetProfile().SetFloatProperty("Edit", "WindowDimY", m_windowDim.y);
}
Math::Point CRobotMain::GetWindowDim()
{
return m_windowDim;
}
//! Managing windows open/save
void CRobotMain::SetIOPublic(bool mode)
{
m_IOPublic = mode;
GetProfile().SetIntProperty("Edit", "IOPublic", m_IOPublic);
}
bool CRobotMain::GetIOPublic()
{
return m_IOPublic;
}
void CRobotMain::SetIOPos(Math::Point pos)
{
m_IOPos = pos;
GetProfile().SetFloatProperty("Edit", "IOPosX", m_IOPos.x);
GetProfile().SetFloatProperty("Edit", "IOPosY", m_IOPos.y);
}
Math::Point CRobotMain::GetIOPos()
{
return m_IOPos;
}
void CRobotMain::SetIODim(Math::Point dim)
{
m_IODim = dim;
GetProfile().SetFloatProperty("Edit", "IODimX", m_IODim.x);
GetProfile().SetFloatProperty("Edit", "IODimY", m_IODim.y);
}
Math::Point CRobotMain::GetIODim()
{
return m_IODim;
}
//! Start of the visit instead of an error
void CRobotMain::StartDisplayVisit(EventType event)
{
if (m_editLock) return;
Ui::CWindow* pw = static_cast<Ui::CWindow*>(m_interface->SearchControl(EVENT_WINDOW2));
if (pw == nullptr) return;
if (event == EVENT_NULL) // visit by keyboard shortcut?
{
int i;
if (m_visitLast != EVENT_NULL) // already a current visit?
i = m_visitLast-EVENT_DT_VISIT0;
else
i = Ui::MAXDTLINE;
// Seeks the last.
for (int j = 0; j < Ui::MAXDTLINE; j++)
{
i --;
if (i < 0) i = Ui::MAXDTLINE-1;
Ui::CButton* button = static_cast<Ui::CButton*>(pw->SearchControl(static_cast<EventType>(EVENT_DT_VISIT0+i)));
if (button == nullptr || !button->TestState(Ui::STATE_ENABLE)) continue;
Ui::CGroup* group = static_cast<Ui::CGroup*>(pw->SearchControl(static_cast<EventType>(EVENT_DT_GROUP0+i)));
if (group != nullptr)
{
event = static_cast<EventType>(EVENT_DT_VISIT0+i);
break;
}
}
}
if (event == EVENT_NULL)
{
m_sound->Play(SOUND_TZOING); // nothing to do!
return;
}
m_visitLast = event;
ClearInterface(); // removes setting evidence and tooltip
if (m_camera->GetType() == Gfx::CAM_TYPE_VISIT) // already a current visit?
{
m_camera->StopVisit();
m_displayText->ClearVisit();
}
else
{
m_visitObject = DeselectAll(); // removes the control buttons
}
// Creates the "continue" button.
if (m_interface->SearchControl(EVENT_DT_END) == 0)
{
Math::Point pos, dim;
pos.x = 10.0f/640.0f;
pos.y = 10.0f/480.0f;
dim.x = 50.0f/640.0f;
dim.y = 50.0f/480.0f;
m_interface->CreateButton(pos, dim, 16, EVENT_DT_END);
}
// Creates the arrow to show the place.
if (m_visitArrow != 0)
{
m_visitArrow->DeleteObject();
delete m_visitArrow;
m_visitArrow = 0;
}
Math::Vector goal = m_displayText->GetVisitGoal(event);
m_visitArrow = CObjectManager::GetInstancePointer()->CreateObject(goal, 0.0f, OBJECT_SHOW, -1.0f, 1.0f, 10.0f);
m_visitPos = m_visitArrow->GetPosition(0);
m_visitPosArrow = m_visitPos;
m_visitPosArrow.y += m_displayText->GetVisitHeight(event);
m_visitArrow->SetPosition(0, m_visitPosArrow);
m_visitTime = 0.0;
m_visitParticle = 0.0f;
m_particle->DeleteParticle(Gfx::PARTISHOW);
m_camera->StartVisit(m_displayText->GetVisitGoal(event),
m_displayText->GetVisitDist(event));
m_displayText->SetVisit(event);
ChangePause(PAUSE_VISIT);
}
//! Move the arrow to visit
void CRobotMain::FrameVisit(float rTime)
{
if (m_visitArrow == 0) return;
// Moves the arrow.
m_visitTime += rTime;
Math::Vector pos = m_visitPosArrow;
pos.y += 1.5f+sinf(m_visitTime*4.0f)*4.0f;
m_visitArrow->SetPosition(0, pos);
m_visitArrow->SetAngleY(0, m_visitTime*2.0f);
// Manages the particles "arrows".
m_visitParticle -= rTime;
if (m_visitParticle <= 0.0f)
{
m_visitParticle = 1.5f;
pos = m_visitPos;
float level = m_terrain->GetFloorLevel(pos)+2.0f;
if (pos.y < level) pos.y = level; // not below the ground
Math::Vector speed(0.0f, 0.0f, 0.0f);
Math::Point dim;
dim.x = 30.0f;
dim.y = dim.x;
m_particle->CreateParticle(pos, speed, dim, Gfx::PARTISHOW, 2.0f);
}
}
//! End of the visit instead of an error
void CRobotMain::StopDisplayVisit()
{
m_visitLast = EVENT_NULL;
// Removes the button.
m_interface->DeleteControl(EVENT_DT_END);
// Removes the arrow.
if (m_visitArrow != nullptr)
{
m_visitArrow->DeleteObject();
delete m_visitArrow;
m_visitArrow = nullptr;
}
// Removes particles "arrows".
m_particle->DeleteParticle(Gfx::PARTISHOW);
m_camera->StopVisit();
m_displayText->ClearVisit();
ChangePause(PAUSE_NONE);
if (m_visitObject != 0)
{
SelectObject(m_visitObject, false); // gives the command buttons
m_visitObject = 0;
}
}
//! Updates all the shortcuts
void CRobotMain::UpdateShortcuts()
{
m_short->UpdateShortcuts();
}
//! Returns the object that default was select after the creation of a scene
CObject* CRobotMain::GetSelectObject()
{
if (m_selectObject != nullptr) return m_selectObject;
return SearchHuman();
}
//! Deselects everything, and returns the object that was selected
CObject* CRobotMain::DeselectAll()
{
CInstanceManager* iMan = CInstanceManager::GetInstancePointer();
CObject* prev = nullptr;
for (int i = 0; i < 1000000; i++)
{
CObject* obj = static_cast<CObject*>(iMan->SearchInstance(CLASS_OBJECT, i));
if (obj == nullptr) break;
if (obj->GetSelect()) prev = obj;
obj->SetSelect(false);
}
return prev;
}
//! Selects an object, without attending to deselect the rest
void CRobotMain::SelectOneObject(CObject* obj, bool displayError)
{
obj->SetSelect(true, displayError);
m_camera->SetControllingObject(obj);
ObjectType type = obj->GetType();
if ( type == OBJECT_HUMAN ||
type == OBJECT_MOBILEfa ||
type == OBJECT_MOBILEta ||
type == OBJECT_MOBILEwa ||
type == OBJECT_MOBILEia ||
type == OBJECT_MOBILEfc ||
type == OBJECT_MOBILEtc ||
type == OBJECT_MOBILEwc ||
type == OBJECT_MOBILEic ||
type == OBJECT_MOBILEfi ||
type == OBJECT_MOBILEti ||
type == OBJECT_MOBILEwi ||
type == OBJECT_MOBILEii ||
type == OBJECT_MOBILEfs ||
type == OBJECT_MOBILEts ||
type == OBJECT_MOBILEws ||
type == OBJECT_MOBILEis ||
type == OBJECT_MOBILErt ||
type == OBJECT_MOBILErc ||
type == OBJECT_MOBILErr ||
type == OBJECT_MOBILErs ||
type == OBJECT_MOBILEsa ||
type == OBJECT_MOBILEft ||
type == OBJECT_MOBILEtt ||
type == OBJECT_MOBILEwt ||
type == OBJECT_MOBILEit ||
type == OBJECT_MOBILEdr ||
type == OBJECT_APOLLO2 )
{
m_camera->SetType(obj->GetCameraType());
m_camera->SetDist(obj->GetCameraDist());
}
else
{
m_camera->SetType(Gfx::CAM_TYPE_BACK);
}
CObject* toto = SearchToto();
if (toto != nullptr)
{
CMotionToto* mt = static_cast<CMotionToto*>(toto->GetMotion());
if (mt != nullptr)
mt->SetLinkType(type);
}
}
//! Selects the object aimed by the mouse
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_movie->IsExist()) return false;
if (obj == nullptr || !IsSelectable(obj)) return false;
CObject* prev = DeselectAll();
if (prev != nullptr && prev != obj)
obj->AddDeselList(prev);
SelectOneObject(obj, displayError);
m_short->UpdateShortcuts();
return true;
}
//! Deselects the selected object
bool CRobotMain::DeselectObject()
{
CObject* obj = nullptr;
CObject* prev = DeselectAll();
if (prev == nullptr)
obj = SearchHuman();
else
obj = prev->SubDeselList();
if (obj == nullptr)
obj = SearchHuman();
if (obj != nullptr)
SelectOneObject(obj);
else
m_camera->SetType(Gfx::CAM_TYPE_FREE);
m_short->UpdateShortcuts();
return true;
}
//! Quickly removes all objects
void CRobotMain::DeleteAllObjects()
{
CInstanceManager* iMan = CInstanceManager::GetInstancePointer();
// Removes all pyrotechnic effects in progress.
while (true)
{
Gfx::CPyro* pyro = static_cast<Gfx::CPyro*>(iMan->SearchInstance(CLASS_PYRO, 0));
if (pyro == nullptr) break;
pyro->DeleteObject();
delete pyro;
}
// Removes the arrow.
if (m_visitArrow != nullptr)
{
m_visitArrow->DeleteObject();
delete m_visitArrow;
m_visitArrow = nullptr;
}
for (int i = 0; i < MAXSHOWLIMIT; i++)
FlushShowLimit(i);
while (true)
{
CObject* obj = static_cast<CObject*>(iMan->SearchInstance(CLASS_OBJECT, 0));
if (obj == nullptr) break;
obj->DeleteObject(true); // destroys rapidly
delete obj;
}
}
//! Selects the human
void CRobotMain::SelectHuman()
{
SelectObject(SearchHuman());
}
//! Returns the object human
CObject* CRobotMain::SearchHuman()
{
CInstanceManager* iMan = CInstanceManager::GetInstancePointer();
for (int i = 0; i < 1000000; i++)
{
CObject* obj = static_cast<CObject*>(iMan->SearchInstance(CLASS_OBJECT, i));
if (obj == 0) break;
ObjectType type = obj->GetType();
if (type == OBJECT_HUMAN)
return obj;
}
return 0;
}
//! Returns the object toto
CObject* CRobotMain::SearchToto()
{
CInstanceManager* iMan = CInstanceManager::GetInstancePointer();
for (int i = 0; i < 1000000; i++)
{
CObject* obj = static_cast<CObject*>(iMan->SearchInstance(CLASS_OBJECT, i));
if (obj == nullptr) break;
ObjectType type = obj->GetType();
if (type == OBJECT_TOTO)
return obj;
}
return nullptr;
}
//! Returns the nearest selectable object from a given position
CObject* CRobotMain::SearchNearest(Math::Vector pos, CObject* exclu)
{
CInstanceManager* iMan = CInstanceManager::GetInstancePointer();
float min = 100000.0f;
CObject* best = 0;
for (int i = 0; i < 1000000; i++)
{
CObject* obj = static_cast<CObject*>(iMan->SearchInstance(CLASS_OBJECT, i));
if (obj == nullptr) break;
if (obj == exclu) continue;
if (!IsSelectable(obj)) continue;
ObjectType type = obj->GetType();
if (type == OBJECT_TOTO) continue;
Math::Vector oPos = obj->GetPosition(0);
float dist = Math::DistanceProjected(oPos, pos);
if (dist < min)
{
min = dist;
best = obj;
}
}
return best;
}
//! Returns the selected object
CObject* CRobotMain::GetSelect()
{
CInstanceManager* iMan = CInstanceManager::GetInstancePointer();
for (int i = 0; i < 1000000; i++)
{
CObject* obj = static_cast<CObject*>(iMan->SearchInstance(CLASS_OBJECT, i));
if (obj == nullptr) break;
if (obj->GetSelect())
return obj;
}
return nullptr;
}
CObject* CRobotMain::SearchObject(ObjectType type)
{
CInstanceManager* iMan = CInstanceManager::GetInstancePointer();
for (int i = 0; i < 1000000; i++)
{
CObject* obj = static_cast<CObject*>(iMan->SearchInstance(CLASS_OBJECT, i));
if (obj == nullptr) break;
if (obj->GetType() == type)
return obj;
}
return nullptr;
}
//! Detects the object aimed by the mouse
CObject* CRobotMain::DetectObject(Math::Point pos)
{
int objRank = m_engine->DetectObject(pos);
CInstanceManager* iMan = CInstanceManager::GetInstancePointer();
for (int i = 0; i < 1000000; i++)
{
CObject* obj = static_cast<CObject*>(iMan->SearchInstance(CLASS_OBJECT, i));
if (obj == nullptr) break;
if (!obj->GetActif()) continue;
CObject* truck = obj->GetTruck();
if (truck != nullptr) if (!truck->GetActif()) continue;
if (obj->GetProxyActivate()) continue;
CObject* target = nullptr;
ObjectType type = obj->GetType();
if ( type == OBJECT_PORTICO ||
type == OBJECT_BASE ||
type == OBJECT_DERRICK ||
type == OBJECT_FACTORY ||
type == OBJECT_REPAIR ||
type == OBJECT_DESTROYER ||
type == OBJECT_STATION ||
type == OBJECT_CONVERT ||
type == OBJECT_TOWER ||
type == OBJECT_RESEARCH ||
type == OBJECT_RADAR ||
type == OBJECT_INFO ||
type == OBJECT_ENERGY ||
type == OBJECT_LABO ||
type == OBJECT_NUCLEAR ||
type == OBJECT_PARA ||
type == OBJECT_SAFE ||
type == OBJECT_HUSTON ||
type == OBJECT_TARGET1 ||
type == OBJECT_TARGET2 ||
type == OBJECT_START ||
type == OBJECT_END ||
type == OBJECT_STONE ||
type == OBJECT_URANIUM ||
type == OBJECT_BULLET ||
type == OBJECT_METAL ||
type == OBJECT_BBOX ||
type == OBJECT_KEYa ||
type == OBJECT_KEYb ||
type == OBJECT_KEYc ||
type == OBJECT_KEYd ||
type == OBJECT_TNT ||
type == OBJECT_SCRAP1 ||
type == OBJECT_SCRAP2 ||
type == OBJECT_SCRAP3 ||
type == OBJECT_SCRAP4 ||
type == OBJECT_SCRAP5 ||
type == OBJECT_BOMB ||
type == OBJECT_BAG ||
type == OBJECT_WAYPOINT ||
type == OBJECT_FLAGb ||
type == OBJECT_FLAGr ||
type == OBJECT_FLAGg ||
type == OBJECT_FLAGy ||
type == OBJECT_FLAGv ||
type == OBJECT_MARKPOWER ||
type == OBJECT_MARKSTONE ||
type == OBJECT_MARKURANIUM ||
type == OBJECT_MARKKEYa ||
type == OBJECT_MARKKEYb ||
type == OBJECT_MARKKEYc ||
type == OBJECT_MARKKEYd ||
type == OBJECT_HUMAN ||
type == OBJECT_TECH ||
type == OBJECT_TOTO ||
type == OBJECT_MOBILEfa ||
type == OBJECT_MOBILEta ||
type == OBJECT_MOBILEwa ||
type == OBJECT_MOBILEia ||
type == OBJECT_MOBILEfc ||
type == OBJECT_MOBILEtc ||
type == OBJECT_MOBILEwc ||
type == OBJECT_MOBILEic ||
type == OBJECT_MOBILEfi ||
type == OBJECT_MOBILEti ||
type == OBJECT_MOBILEwi ||
type == OBJECT_MOBILEii ||
type == OBJECT_MOBILEfs ||
type == OBJECT_MOBILEts ||
type == OBJECT_MOBILEws ||
type == OBJECT_MOBILEis ||
type == OBJECT_MOBILErt ||
type == OBJECT_MOBILErc ||
type == OBJECT_MOBILErr ||
type == OBJECT_MOBILErs ||
type == OBJECT_MOBILEsa ||
type == OBJECT_MOBILEtg ||
type == OBJECT_MOBILEft ||
type == OBJECT_MOBILEtt ||
type == OBJECT_MOBILEwt ||
type == OBJECT_MOBILEit ||
type == OBJECT_MOBILEdr ||
type == OBJECT_MOTHER ||
type == OBJECT_ANT ||
type == OBJECT_SPIDER ||
type == OBJECT_BEE ||
type == OBJECT_WORM ||
type == OBJECT_EGG ||
type == OBJECT_RUINmobilew1 ||
type == OBJECT_RUINmobilew2 ||
type == OBJECT_RUINmobilet1 ||
type == OBJECT_RUINmobilet2 ||
type == OBJECT_RUINmobiler1 ||
type == OBJECT_RUINmobiler2 ||
type == OBJECT_RUINfactory ||
type == OBJECT_RUINdoor ||
type == OBJECT_RUINsupport ||
type == OBJECT_RUINradar ||
type == OBJECT_RUINconvert ||
type == OBJECT_RUINbase ||
type == OBJECT_RUINhead ||
type == OBJECT_APOLLO1 ||
type == OBJECT_APOLLO2 ||
type == OBJECT_APOLLO3 ||
type == OBJECT_APOLLO4 ||
type == OBJECT_APOLLO5 )
{
target = obj;
}
else if ((type == OBJECT_POWER ||
type == OBJECT_ATOMIC) &&
obj->GetTruck() != nullptr) // battery used?
{
target = obj->GetTruck();
}
else if (type == OBJECT_POWER ||
type == OBJECT_ATOMIC)
{
target = obj;
}
for (int j = 0; j < OBJECTMAXPART; j++)
{
int rank = obj->GetObjectRank(j);
if (rank == -1) continue;
if (rank != objRank) continue;
return target;
}
}
return 0;
}
//! Indicates whether an object is selectable
bool CRobotMain::IsSelectable(CObject* obj)
{
if (!obj->GetSelectable()) return false;
ObjectType type = obj->GetType();
if ( type == OBJECT_HUMAN ||
type == OBJECT_TOTO ||
type == OBJECT_MOBILEfa ||
type == OBJECT_MOBILEta ||
type == OBJECT_MOBILEwa ||
type == OBJECT_MOBILEia ||
type == OBJECT_MOBILEfc ||
type == OBJECT_MOBILEtc ||
type == OBJECT_MOBILEwc ||
type == OBJECT_MOBILEic ||
type == OBJECT_MOBILEfi ||
type == OBJECT_MOBILEti ||
type == OBJECT_MOBILEwi ||
type == OBJECT_MOBILEii ||
type == OBJECT_MOBILEfs ||
type == OBJECT_MOBILEts ||
type == OBJECT_MOBILEws ||
type == OBJECT_MOBILEis ||
type == OBJECT_MOBILErt ||
type == OBJECT_MOBILErc ||
type == OBJECT_MOBILErr ||
type == OBJECT_MOBILErs ||
type == OBJECT_MOBILEsa ||
type == OBJECT_MOBILEft ||
type == OBJECT_MOBILEtt ||
type == OBJECT_MOBILEwt ||
type == OBJECT_MOBILEit ||
type == OBJECT_MOBILEdr ||
type == OBJECT_APOLLO2 ||
type == OBJECT_BASE ||
type == OBJECT_DERRICK ||
type == OBJECT_FACTORY ||
type == OBJECT_REPAIR ||
type == OBJECT_DESTROYER||
type == OBJECT_STATION ||
type == OBJECT_CONVERT ||
type == OBJECT_TOWER ||
type == OBJECT_RESEARCH ||
type == OBJECT_RADAR ||
type == OBJECT_INFO ||
type == OBJECT_ENERGY ||
type == OBJECT_LABO ||
type == OBJECT_NUCLEAR ||
type == OBJECT_PARA ||
type == OBJECT_SAFE ||
type == OBJECT_HUSTON )
{
return true;
}
if (m_selectInsect)
{
if ( type == OBJECT_MOTHER ||
type == OBJECT_ANT ||
type == OBJECT_SPIDER ||
type == OBJECT_BEE ||
type == OBJECT_WORM ||
type == OBJECT_MOBILEtg )
{
return true;
}
}
return false;
}
//! Deletes the selected object
bool CRobotMain::DeleteObject()
{
CObject* obj = GetSelect();
if (obj == nullptr) return false;
Gfx::CPyro* pyro = new Gfx::CPyro();
pyro->Create(Gfx::PT_FRAGT, obj);
obj->SetSelect(false); // deselects the object
m_camera->SetType(Gfx::CAM_TYPE_EXPLO);
DeselectAll();
obj->DeleteDeselList(obj);
return true;
}
//! Removes setting evidence of the object with the mouse hovers over
void CRobotMain::HiliteClear()
{
ClearTooltip();
m_tooltipName.clear(); // really removes the tooltip
if (!m_hilite) return;
int rank = -1;
m_engine->SetHighlightRank(&rank); // nothing more selected
CInstanceManager* iMan = CInstanceManager::GetInstancePointer();
for (int i = 0; i < 1000000; i++)
{
CObject* obj = static_cast<CObject*>(iMan->SearchInstance(CLASS_OBJECT, i));
if (obj == nullptr) break;
obj->SetHilite(false);
m_map->SetHighlight(0);
m_short->SetHighlight(0);
}
m_hilite = false;
}
//! Highlights the object with the mouse hovers over
void CRobotMain::HiliteObject(Math::Point pos)
{
if (m_fixScene && m_phase != PHASE_PERSO) return;
if (m_movieLock) return;
if (m_movie->IsExist()) return;
if (m_app->GetMouseMode() == MOUSE_NONE) return;
ClearInterface(); // removes setting evidence and tooltip
CObject* obj = m_short->DetectShort(pos);
std::string interfaceTooltipName;
if (m_dialog->GetTooltip() && m_interface->GetTooltip(pos, interfaceTooltipName))
{
m_tooltipPos = pos;
m_tooltipName = interfaceTooltipName;
m_tooltipTime = 0.0f;
if (obj == nullptr) return;
}
if (m_suspend) return;
if (obj == nullptr)
{
bool inMap = false;
obj = m_map->DetectMap(pos, inMap);
if (obj == nullptr)
{
if (inMap) return;
obj = DetectObject(pos);
if ((m_camera->GetType() == Gfx::CAM_TYPE_ONBOARD) &&
(m_camera->GetControllingObject() == obj))
return;
}
}
if (obj != nullptr)
{
std::string objectTooltipName;
if (m_dialog->GetTooltip() && obj->GetTooltipName(objectTooltipName))
{
m_tooltipPos = pos;
m_tooltipName = objectTooltipName;
m_tooltipTime = 0.0f;
}
if (IsSelectable(obj))
{
obj->SetHilite(true);
m_map->SetHighlight(obj);
m_short->SetHighlight(obj);
m_hilite = true;
}
}
}
//! Highlights the object with the mouse hovers over
void CRobotMain::HiliteFrame(float rTime)
{
if (m_fixScene && m_phase != PHASE_PERSO) return;
if (m_movieLock) return;
if (m_movie->IsExist()) return;
m_tooltipTime += rTime;
ClearTooltip();
if (m_tooltipTime >= 0.2f && !m_tooltipName.empty())
{
CreateTooltip(m_tooltipPos, m_tooltipName);
}
}
//! Creates a tooltip
void CRobotMain::CreateTooltip(Math::Point pos, const std::string& text)
{
Math::Point corner;
corner.x = pos.x+0.022f;
corner.y = pos.y-0.052f;
Math::Point start, end;
m_engine->GetText()->SizeText(text, Gfx::FONT_COLOBOT, Gfx::FONT_SIZE_SMALL,
corner, Gfx::TEXT_ALIGN_LEFT,
start, end);
start.x -= 0.010f;
start.y -= 0.006f;
end.x += 0.010f;
end.y += 0.008f; // small'ish margin
pos.x = start.x;
pos.y = start.y;
Math::Point dim;
dim.x = end.x-start.x;
dim.y = end.y-start.y;
Math::Point offset;
offset.x = 0.0f;
offset.y = 0.0f;
if (pos.x+dim.x > 1.0f) offset.x = 1.0f-(pos.x+dim.x);
if (pos.y < 0.0f) offset.y = -pos.y;
corner.x += offset.x;
corner.y += offset.y;
pos.x += offset.x;
pos.y += offset.y;
m_interface->CreateWindows(pos, dim, 1, EVENT_TOOLTIP);
Ui::CWindow* pw = static_cast<Ui::CWindow*>(m_interface->SearchControl(EVENT_TOOLTIP));
if (pw != nullptr)
{
pw->SetState(Ui::STATE_SHADOW);
pw->SetTrashEvent(false);
pos.y -= m_engine->GetText()->GetHeight(Gfx::FONT_COLOBOT, Gfx::FONT_SIZE_SMALL) / 2.0f;
pw->CreateLabel(pos, dim, -1, EVENT_LABEL2, text);
}
}
//! Clears the previous tooltip
void CRobotMain::ClearTooltip()
{
m_interface->DeleteControl(EVENT_TOOLTIP);
}
//! Displays help for an object
void CRobotMain::HelpObject()
{
CObject* obj = GetSelect();
if (obj == nullptr) return;
const char* filename = GetHelpFilename(obj->GetType()).c_str();
if (filename[0] == 0) return;
StartDisplayInfo(filename, -1);
}
//! Change the mode of the camera
void CRobotMain::ChangeCamera()
{
CInstanceManager* iMan = CInstanceManager::GetInstancePointer();
for (int i = 0; i < 1000000; i++)
{
CObject* obj = static_cast<CObject*>(iMan->SearchInstance(CLASS_OBJECT, i));
if (obj == nullptr) break;
if (obj->GetSelect())
{
if (obj->GetCameraLock()) return;
ObjectType oType = obj->GetType();
Gfx::CameraType type = obj->GetCameraType();
if ( oType != OBJECT_MOBILEfa &&
oType != OBJECT_MOBILEta &&
oType != OBJECT_MOBILEwa &&
oType != OBJECT_MOBILEia &&
oType != OBJECT_MOBILEfc &&
oType != OBJECT_MOBILEtc &&
oType != OBJECT_MOBILEwc &&
oType != OBJECT_MOBILEic &&
oType != OBJECT_MOBILEfi &&
oType != OBJECT_MOBILEti &&
oType != OBJECT_MOBILEwi &&
oType != OBJECT_MOBILEii &&
oType != OBJECT_MOBILEfs &&
oType != OBJECT_MOBILEts &&
oType != OBJECT_MOBILEws &&
oType != OBJECT_MOBILEis &&
oType != OBJECT_MOBILErt &&
oType != OBJECT_MOBILErc &&
oType != OBJECT_MOBILErr &&
oType != OBJECT_MOBILErs &&
oType != OBJECT_MOBILEsa &&
oType != OBJECT_MOBILEtg &&
oType != OBJECT_MOBILEft &&
oType != OBJECT_MOBILEtt &&
oType != OBJECT_MOBILEwt &&
oType != OBJECT_MOBILEit &&
oType != OBJECT_MOBILEdr &&
oType != OBJECT_APOLLO2 ) return;
if (oType == OBJECT_MOBILEdr) // designer?
{
if (type == Gfx::CAM_TYPE_PLANE ) type = Gfx::CAM_TYPE_BACK;
else if (type == Gfx::CAM_TYPE_BACK ) type = Gfx::CAM_TYPE_PLANE;
}
else if (obj->GetTrainer()) // trainer?
{
if (type == Gfx::CAM_TYPE_ONBOARD) type = Gfx::CAM_TYPE_FIX;
else if (type == Gfx::CAM_TYPE_FIX ) type = Gfx::CAM_TYPE_PLANE;
else if (type == Gfx::CAM_TYPE_PLANE ) type = Gfx::CAM_TYPE_BACK;
else if (type == Gfx::CAM_TYPE_BACK ) type = Gfx::CAM_TYPE_ONBOARD;
}
else
{
if (type == Gfx::CAM_TYPE_ONBOARD) type = Gfx::CAM_TYPE_BACK;
else if (type == Gfx::CAM_TYPE_BACK ) type = Gfx::CAM_TYPE_ONBOARD;
}
obj->SetCameraType(type);
m_camera->SetType(type);
}
}
}
//! Remote control the camera using the arrow keys
void CRobotMain::KeyCamera(EventType type, unsigned int key)
{
// TODO: rewrite key handling to input bindings
if (type == EVENT_KEY_UP)
{
if (key == GetInputBinding(INPUT_SLOT_LEFT).primary ||
key == GetInputBinding(INPUT_SLOT_LEFT).secondary)
{
m_cameraPan = 0.0f;
}
if (key == GetInputBinding(INPUT_SLOT_RIGHT).primary ||
key == GetInputBinding(INPUT_SLOT_RIGHT).secondary)
{
m_cameraPan = 0.0f;
}
if (key == GetInputBinding(INPUT_SLOT_UP).primary ||
key == GetInputBinding(INPUT_SLOT_UP).secondary)
{
m_cameraZoom = 0.0f;
}
if (key == GetInputBinding(INPUT_SLOT_DOWN).primary ||
key == GetInputBinding(INPUT_SLOT_DOWN).secondary)
{
m_cameraZoom = 0.0f;
}
}
if (m_phase != PHASE_SIMUL) return;
if (m_editLock) return; // current edition?
if (m_trainerPilot) return;
CObject* obj = GetSelect();
if (obj == nullptr) return;
if (!obj->GetTrainer()) return;
if (type == EVENT_KEY_DOWN)
{
if (key == GetInputBinding(INPUT_SLOT_LEFT).primary ||
key == GetInputBinding(INPUT_SLOT_LEFT).secondary)
{
m_cameraPan = -1.0f;
}
if (key == GetInputBinding(INPUT_SLOT_RIGHT).primary ||
key == GetInputBinding(INPUT_SLOT_RIGHT).secondary)
{
m_cameraPan = 1.0f;
}
if (key == GetInputBinding(INPUT_SLOT_UP).primary ||
key == GetInputBinding(INPUT_SLOT_UP).secondary)
{
m_cameraZoom = -1.0f;
}
if (key == GetInputBinding(INPUT_SLOT_DOWN).primary ||
key == GetInputBinding(INPUT_SLOT_DOWN).secondary)
{
m_cameraZoom = 1.0f;
}
}
}
//! Panned with the camera if a button is pressed
void CRobotMain::RemoteCamera(float pan, float zoom, float rTime)
{
if (pan != 0.0f)
{
float value = m_camera->GetRemotePan();
value += pan*rTime*1.5f;
m_camera->SetRemotePan(value);
}
if (zoom != 0.0f)
{
float value = m_camera->GetRemoteZoom();
value += zoom*rTime*0.3f;
m_camera->SetRemoteZoom(value);
}
}
//! Cancels the current movie
void CRobotMain::AbortMovie()
{
CInstanceManager* iMan = CInstanceManager::GetInstancePointer();
for (int i = 0; i < 1000000; i++)
{
CObject* obj = static_cast<CObject*>(iMan->SearchInstance(CLASS_OBJECT, i));
if (obj == nullptr) break;
CAuto* automat = obj->GetAuto();
if (automat != 0)
automat->Abort();
}
m_app->SetMouseMode(MOUSE_ENGINE);
}
//! Updates the text information
void CRobotMain::UpdateInfoText()
{
if (m_phase == PHASE_SIMUL)
{
CObject* obj = GetSelect();
if (obj != nullptr)
{
Math::Vector pos = obj->GetPosition(0);
m_engine->SetStatisticPos(pos);
}
}
m_engine->SetTimerDisplay(m_missionTimerEnabled && m_missionTimerStarted ? TimeFormat(m_missionTimer) : "");
}
//! Initializes the view
void CRobotMain::InitEye()
{
if (m_phase == PHASE_SIMUL)
m_camera->Init(Math::Vector( 0.0f, 10.0f, 0.0f),
Math::Vector(10.0f, 5.0f, 0.0f), 0.0f);
}
//! Advances the entire scene
bool CRobotMain::EventFrame(const Event &event)
{
m_time += event.rTime;
if (!m_movieLock && m_pause->GetPause() == PAUSE_NONE) m_gameTime += event.rTime;
if (!m_immediatSatCom && !m_beginSatCom &&
m_gameTime > 0.1f && m_phase == PHASE_SIMUL)
{
m_displayText->DisplayError(INFO_BEGINSATCOM, Math::Vector(0.0f,0.0f,0.0f));
m_beginSatCom = true; // message appears
}
if(!m_movieLock && m_pause->GetPause() == PAUSE_NONE && m_missionTimerStarted)
m_missionTimer += event.rTime;
if(m_pause->GetPause() == PAUSE_NONE && m_autosave && m_gameTime >= m_autosaveLast+(m_autosaveInterval*60) && m_phase == PHASE_SIMUL) {
m_autosaveLast = m_gameTime;
Autosave();
}
//CLogger::GetInstancePointer()->Debug("%f %f %d\n", m_gameTime, m_autosaveLast, m_autosaveInterval);
m_water->EventProcess(event);
m_cloud->EventProcess(event);
m_lightning->EventProcess(event);
m_planet->EventProcess(event);
Ui::CMap* pm = nullptr;
Ui::CWindow* pw = static_cast<Ui::CWindow*>(m_interface->SearchControl(EVENT_WINDOW1));
if (pw == nullptr)
{
pm = nullptr;
}
else
{
pm = static_cast<Ui::CMap*>(pw->SearchControl(EVENT_OBJECT_MAP));
if (pm != nullptr) pm->FlushObject();
}
CInstanceManager* iMan = CInstanceManager::GetInstancePointer();
CObject* toto = nullptr;
if (!m_freePhoto)
{
// Advances all the robots, but not toto.
for (int i = 0; i < 1000000; i++)
{
CObject* obj = static_cast<CObject*>(iMan->SearchInstance(CLASS_OBJECT, i));
if (obj == nullptr) break;
if (pm != nullptr) pm->UpdateObject(obj);
if (obj->GetTruck() != nullptr) continue;
ObjectType type = obj->GetType();
if (type == OBJECT_TOTO)
toto = obj;
else
obj->EventProcess(event);
}
// Advances all objects transported by robots.
for (int i = 0; i < 1000000; i++)
{
CObject* obj = static_cast<CObject*>(iMan->SearchInstance(CLASS_OBJECT, i));
if (obj == nullptr) break;
if (obj->GetTruck() == nullptr) continue;
obj->EventProcess(event);
}
// Advances pyrotechnic effects.
for (int i = 0; i < 1000000; i++)
{
Gfx::CPyro* pyro = static_cast<Gfx::CPyro*>(iMan->SearchInstance(CLASS_PYRO, i));
if (pyro == nullptr) break;
pyro->EventProcess(event);
if (pyro->IsEnded() != ERR_CONTINUE)
{
pyro->DeleteObject();
delete pyro;
}
}
}
// The camera follows the object, because its position
// may depend on the selected object (Gfx::CAM_TYPE_ONBOARD or Gfx::CAM_TYPE_BACK).
if (m_phase == PHASE_SIMUL && !m_editFull)
{
m_camera->EventProcess(event);
if (m_engine->GetFog())
m_camera->SetOverBaseColor(m_particle->GetFogColor(m_engine->GetEyePt()));
}
if (m_phase == PHASE_PERSO ||
m_phase == PHASE_WIN ||
m_phase == PHASE_LOST)
{
m_camera->EventProcess(event);
}
// Advances toto following the camera, because its position depends on the camera.
if (toto != nullptr)
toto->EventProcess(event);
HiliteFrame(event.rTime);
// Moves the film indicator.
if (m_movieLock && !m_editLock) // movie in progress?
{
Ui::CControl* pc = m_interface->SearchControl(EVENT_OBJECT_MOVIELOCK);
if (pc != nullptr)
{
Math::Point pos, dim;
dim.x = 32.0f/640.0f;
dim.y = 32.0f/480.0f;
pos.x = 20.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
dim.x *= zoom;
dim.y *= zoom;
pos.x -= dim.x/2.0f;
pos.y -= dim.y/2.0f;
pc->SetPos(pos);
pc->SetDim(dim);
}
}
// Moves edition indicator.
if (m_editLock || m_pause->GetPause()) // edition in progress?
{
Ui::CControl* pc = m_interface->SearchControl(EVENT_OBJECT_EDITLOCK);
if (pc != nullptr)
{
Math::Point pos, dim;
if (m_editFull || m_editLock)
{
dim.x = 10.0f/640.0f;
dim.y = 10.0f/480.0f;
pos.x = -20.0f/640.0f;
pos.y = -20.0f/480.0f; // invisible!
}
else
{
dim.x = 32.0f/640.0f;
dim.y = 32.0f/480.0f;
pos.x = 20.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
dim.x *= zoom;
dim.y *= zoom;
pos.x -= dim.x/2.0f;
pos.y -= dim.y/2.0f;
}
pc->SetPos(pos);
pc->SetDim(dim);
}
}
// Will move the arrow to visit.
if (m_camera->GetType() == Gfx::CAM_TYPE_VISIT)
FrameVisit(event.rTime);
// Moves the boundaries.
FrameShowLimit(event.rTime);
if (m_phase == PHASE_SIMUL)
{
if (!m_editLock)
{
CheckEndMission(true);
UpdateAudio(true);
}
if (m_winDelay > 0.0f && !m_editLock)
{
m_winDelay -= event.rTime;
if (m_winDelay <= 0.0f)
{
if (m_movieLock)
m_winDelay = 1.0f;
else
m_eventQueue->AddEvent(Event(EVENT_WIN));
}
}
if (m_lostDelay > 0.0f && !m_editLock)
{
m_lostDelay -= event.rTime;
if (m_lostDelay <= 0.0f)
{
if (m_movieLock)
m_winDelay = 1.0f;
else
m_eventQueue->AddEvent(Event(EVENT_LOST));
}
}
}
if (m_delayWriteMessage > 0)
{
m_delayWriteMessage --;
if (m_delayWriteMessage == 0)
{
m_displayText->DisplayError(INFO_WRITEOK, Math::Vector(0.0f,0.0f,0.0f));
}
}
return true;
}
//! Makes the event for all robots
bool CRobotMain::EventObject(const Event &event)
{
if (m_freePhoto) return true;
m_resetCreate = false;
CInstanceManager* iMan = CInstanceManager::GetInstancePointer();
for (int i = 0; i < 1000000; i++)
{
CObject* obj = static_cast<CObject*>(iMan->SearchInstance(CLASS_OBJECT, i));
if (obj == nullptr) break;
obj->EventProcess(event);
}
if (m_resetCreate)
ResetCreate();
return true;
}
//! Calculates the point of arrival of the camera
Math::Vector CRobotMain::LookatPoint(Math::Vector eye, float angleH, float angleV,
float length)
{
Math::Vector lookat = eye;
lookat.z += length;
RotatePoint(eye, angleH, angleV, lookat);
return lookat;
}
char* SkipNum(char *p)
{
while (*p == ' ' || *p == '.' || *p == '-' || (*p >= '0' && *p <= '9'))
{
p++;
}
return p;
}
//! Load the scene for the character
void CRobotMain::ScenePerso()
{
DeleteAllObjects(); // removes all the current 3D Scene
m_terrain->FlushRelief();
m_engine->DeleteAllObjects();
Gfx::CModelManager::GetInstancePointer()->DeleteAllModelCopies();
m_terrain->FlushBuildingLevel();
m_terrain->FlushFlyingLimit();
m_lightMan->FlushLights();
m_particle->FlushParticle();
CInstanceManager* iMan = CInstanceManager::GetInstancePointer();
iMan->Flush(CLASS_OBJECT);
iMan->Flush(CLASS_PHYSICS);
iMan->Flush(CLASS_BRAIN);
iMan->Flush(CLASS_PYRO);
CObjectManager::GetInstancePointer()->Flush();
m_dialog->SetSceneName("perso");
m_dialog->SetSceneRank(0);
try {
CreateScene(false, true, false); // sets scene
}
catch(const CLevelParserException& e)
{
CLogger::GetInstancePointer()->Error("An error occured while trying to load apperance scene\n");
CLogger::GetInstancePointer()->Error("%s\n", e.what());
}
m_engine->SetDrawWorld(false); // does not draw anything on the interface
m_engine->SetDrawFront(true); // draws on the human interface
CObject* obj = SearchHuman();
if (obj != nullptr)
{
obj->SetDrawFront(true); // draws the interface
CMotionHuman* mh = static_cast<CMotionHuman*>(obj->GetMotion());
if (mh != nullptr)
mh->StartDisplayPerso();
}
}
//! Creates the whole scene
void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject)
{
char* base = m_dialog->GetSceneName();
int rank = m_dialog->GetSceneRank();
const char* read = m_dialog->GetSceneRead().c_str();
const char* stack = m_dialog->GetStackRead().c_str();
m_fixScene = fixScene;
g_id = 0;
m_base = nullptr;
if (!resetObject)
{
g_build = 0;
g_researchDone = 0; // no research done
g_researchEnable = 0;
FlushDisplayInfo();
m_terrain->FlushMaterials();
m_audioTrack = "";
m_audioRepeat = true;
m_satcomTrack = "";
m_satcomRepeat = true;
m_editorTrack = "";
m_editorRepeat = true;
m_displayText->SetDelay(1.0f);
m_displayText->SetEnable(true);
m_immediatSatCom = false;
m_lockedSatCom = false;
m_endingWinRank = 0;
m_endingLostRank = 0;
m_audioChangeTotal = 0;
m_endTakeTotal = 0;
m_endTakeResearch = 0;
m_endTakeNever = false;
m_endTakeWinDelay = 2.0f;
m_endTakeLostDelay = 2.0f;
m_obligatoryTotal = 0;
m_prohibitedTotal = 0;
m_mapShow = true;
m_mapImage = false;
m_mapFilename[0] = 0;
m_controller = nullptr;
m_colorRefBot.r = 10.0f/256.0f;
m_colorRefBot.g = 166.0f/256.0f;
m_colorRefBot.b = 254.0f/256.0f; // blue
m_colorRefBot.a = 0.0f;
m_colorNewBot = m_colorRefBot;
m_colorRefAlien.r = 135.0f/256.0f;
m_colorRefAlien.g = 170.0f/256.0f;
m_colorRefAlien.b = 13.0f/256.0f; // green
m_colorRefAlien.a = 0.0f;
m_colorNewAlien = m_colorRefAlien;
m_colorRefGreen.r = 135.0f/256.0f;
m_colorRefGreen.g = 170.0f/256.0f;
m_colorRefGreen.b = 13.0f/256.0f; // green
m_colorRefGreen.a = 0.0f;
m_colorNewGreen = m_colorRefGreen;
m_colorRefWater.r = 25.0f/256.0f;
m_colorRefWater.g = 255.0f/256.0f;
m_colorRefWater.b = 240.0f/256.0f; // cyan
m_colorRefWater.a = 0.0f;
m_colorNewWater = m_colorRefWater;
m_engine->SetAmbientColor(Gfx::Color(0.5f, 0.5f, 0.5f, 0.5f), 0);
m_engine->SetAmbientColor(Gfx::Color(0.5f, 0.5f, 0.5f, 0.5f), 1);
m_engine->SetFogColor(Gfx::Color(1.0f, 1.0f, 1.0f, 1.0f), 0);
m_engine->SetFogColor(Gfx::Color(1.0f, 1.0f, 1.0f, 1.0f), 1);
m_engine->SetDeepView(1000.0f, 0);
m_engine->SetDeepView(1000.0f, 1);
m_engine->SetFogStart(0.75f, 0);
m_engine->SetFogStart(0.75f, 1);
m_engine->SetSecondTexture("");
m_engine->SetForegroundName("");
m_dialog->BuildResumeName(m_title, base, rank);
m_dialog->BuildResumeName(m_resume, base, rank);
std::string scriptNameStr;
GetResource(RES_TEXT, RT_SCRIPT_NEW, scriptNameStr);
strcpy(m_scriptName, scriptNameStr.c_str());
m_scriptFile[0] = 0;
m_version = 1;
m_retroStyle = false;
m_missionResult = ERR_MISSION_NOTERM;
}
//NOTE: Reset timer always, even when only resetting object positions
m_missionTimerEnabled = false;
m_missionTimerStarted = false;
m_missionTimer = 0.0f;
try {
CLevelParser* level = new CLevelParser(base, rank/100, rank%100);
level->Load();
int rankObj = 0;
int rankGadget = 0;
CObject* sel = 0;
/*
* NOTE: Moving frequently used lines to the top
* may speed up loading
*/
for(auto& line : level->GetLines())
{
if (line->GetCommand() == "MissionFile" && !resetObject)
{
m_version = line->GetParam("version")->AsInt(1);
continue;
}
if(line->GetCommand() == "Title" && !resetObject)
{
strcpy(m_title, line->GetParam("text")->AsString().c_str());
continue;
}
if(line->GetCommand() == "Resume" && !resetObject)
{
strcpy(m_resume, line->GetParam("text")->AsString().c_str());
continue;
}
if(line->GetCommand() == "ScriptName" && !resetObject)
{
strcpy(m_scriptName, line->GetParam("text")->AsString().c_str());
continue;
}
if (line->GetCommand() == "ScriptFile" && !resetObject)
{
strcpy(m_scriptFile, line->GetParam("name")->AsString().c_str());
continue;
}
if (line->GetCommand() == "Instructions" && !resetObject)
{
strcpy(m_infoFilename[SATCOM_HUSTON], line->GetParam("name")->AsPath("help/%lng%").c_str());
m_immediatSatCom = line->GetParam("immediat")->AsBool(false);
if (m_version >= 2) m_beginSatCom = m_lockedSatCom = line->GetParam("lock")->AsBool(false);
if (m_app->GetSceneTestMode()) m_immediatSatCom = false;
continue;
}
if (line->GetCommand() == "Satellite" && !resetObject)
{
strcpy(m_infoFilename[SATCOM_SAT], line->GetParam("name")->AsPath("help/%lng%").c_str());
continue;
}
if (line->GetCommand() == "Loading" && !resetObject)
{
strcpy(m_infoFilename[SATCOM_LOADING], line->GetParam("name")->AsPath("help/%lng%").c_str());
continue;
}
if (line->GetCommand() == "HelpFile" && !resetObject)
{
strcpy(m_infoFilename[SATCOM_PROG], line->GetParam("name")->AsPath("help/%lng%").c_str());
continue;
}
if (line->GetCommand() == "SoluceFile" && !resetObject)
{
strcpy(m_infoFilename[SATCOM_SOLUCE], line->GetParam("name")->AsPath("help/%lng%").c_str());
continue;
}
if (line->GetCommand() == "EndingFile" && !resetObject)
{
// NOTE: The old default was 0, but I think -1 is more correct - 0 means "ending file 000", while -1 means "no ending file"
m_endingWinRank = line->GetParam("win")->AsInt(-1);
m_endingLostRank = line->GetParam("lost")->AsInt(-1);
continue;
}
if (line->GetCommand() == "MessageDelay" && !resetObject)
{
m_displayText->SetDelay(line->GetParam("factor")->AsFloat());
continue;
}
if (line->GetCommand() == "MissionTimer")
{
m_missionTimerEnabled = line->GetParam("enabled")->AsBool();
if(!line->GetParam("program")->AsBool(false)) {
m_missionTimerStarted = true;
}
continue;
}
if (line->GetCommand() == "CacheAudio" && !resetObject && m_version >= 2)
{
m_sound->CacheMusic(std::string("../")+line->GetParam("filename")->AsPath("music"));
continue;
}
if (line->GetCommand() == "AudioChange" && !resetObject && m_version >= 2 && m_controller == nullptr)
{
int i = m_audioChangeTotal;
if (i < 10)
{
m_audioChange[i].pos = line->GetParam("pos")->AsPoint(Math::Vector(0.0f, 0.0f, 0.0f))*g_unit;
m_audioChange[i].dist = line->GetParam("dist")->AsFloat(1000.0f)*g_unit;
m_audioChange[i].type = line->GetParam("type")->AsObjectType(OBJECT_NULL);
m_audioChange[i].min = line->GetParam("min")->AsInt(1);
m_audioChange[i].max = line->GetParam("max")->AsInt(9999);
m_audioChange[i].powermin = line->GetParam("powermin")->AsFloat(-1);
m_audioChange[i].powermax = line->GetParam("powermax")->AsFloat(100);
m_audioChange[i].tool = line->GetParam("tool")->AsToolType(TOOL_OTHER);
m_audioChange[i].drive = line->GetParam("drive")->AsDriveType(DRIVE_OTHER);
strcpy(m_audioChange[i].music, (std::string("../")+line->GetParam("filename")->AsPath("music")).c_str());
m_audioChange[i].repeat = line->GetParam("repeat")->AsBool(true);
m_audioChange[i].changed = false;
m_sound->CacheMusic(m_audioChange[i].music);
m_audioChangeTotal ++;
}
continue;
}
if (line->GetCommand() == "Audio" && !resetObject && m_controller == nullptr)
{
if (m_version < 2)
{
int trackid = line->GetParam("track")->AsInt();
if (trackid != 0)
{
std::stringstream filenameStr;
filenameStr << "music" << std::setfill('0') << std::setw(3) << trackid << ".ogg";
m_audioTrack = filenameStr.str();
}
m_audioRepeat = line->GetParam("repeat")->AsBool(true);
}
else
{
if(line->GetParam("main")->IsDefined()) {
m_audioTrack = std::string("../")+line->GetParam("main")->AsPath("music");
m_audioRepeat = line->GetParam("mainRepeat")->AsBool(true);
} else {
m_audioTrack = "";
}
if(line->GetParam("satcom")->IsDefined()) {
m_satcomTrack = std::string("../")+line->GetParam("satcom")->AsPath("music");
m_satcomRepeat = line->GetParam("satcomRepeat")->AsBool(true);
} else {
m_satcomTrack = "";
}
if(line->GetParam("editor")->IsDefined()) {
m_editorTrack = std::string("../")+line->GetParam("editor")->AsPath("music");
m_editorRepeat = line->GetParam("editorRepeat")->AsBool(true);
} else {
m_editorTrack = "";
}
}
if (m_audioTrack != "") m_sound->CacheMusic(m_audioTrack);
if (m_satcomTrack != "") m_sound->CacheMusic(m_satcomTrack);
if (m_editorTrack != "") m_sound->CacheMusic(m_editorTrack);
continue;
}
if (line->GetCommand() == "AmbientColor" && !resetObject)
{
m_engine->SetAmbientColor(line->GetParam("air")->AsColor(Gfx::Color(0.533f, 0.533f, 0.533f, 0.533f)), 0);
m_engine->SetAmbientColor(line->GetParam("water")->AsColor(Gfx::Color(0.533f, 0.533f, 0.533f, 0.533f)), 1);
continue;
}
if (line->GetCommand() == "FogColor" && !resetObject)
{
m_engine->SetFogColor(line->GetParam("air")->AsColor(Gfx::Color(0.533f, 0.533f, 0.533f, 0.533f)), 0);
m_engine->SetFogColor(line->GetParam("water")->AsColor(Gfx::Color(0.533f, 0.533f, 0.533f, 0.533f)), 1);
continue;
}
if (line->GetCommand() == "VehicleColor" && !resetObject)
{
m_colorNewBot = line->GetParam("color")->AsColor(Gfx::Color(0.533f, 0.533f, 0.533f, 0.533f));
continue;
}
if (line->GetCommand() == "InsectColor" && !resetObject)
{
m_colorNewAlien = line->GetParam("color")->AsColor(Gfx::Color(0.533f, 0.533f, 0.533f, 0.533f));
continue;
}
if (line->GetCommand() == "GreeneryColor" && !resetObject)
{
m_colorNewGreen = line->GetParam("color")->AsColor(Gfx::Color(0.533f, 0.533f, 0.533f, 0.533f));
continue;
}
if (line->GetCommand() == "DeepView" && !resetObject)
{
m_engine->SetDeepView(line->GetParam("air")->AsFloat(500.0f)*g_unit, 0, true);
m_engine->SetDeepView(line->GetParam("water")->AsFloat(100.0f)*g_unit, 1, true);
continue;
}
if (line->GetCommand() == "FogStart" && !resetObject)
{
m_engine->SetFogStart(line->GetParam("air")->AsFloat(0.5f), 0);
m_engine->SetFogStart(line->GetParam("water")->AsFloat(0.5f), 1);
continue;
}
if (line->GetCommand() == "SecondTexture" && !resetObject)
{
if(line->GetParam("rank")->IsDefined()) {
char tex[20] = { 0 };
sprintf(tex, "dirty%.2d.png", line->GetParam("rank")->AsInt());
m_engine->SetSecondTexture(tex);
} else {
m_engine->SetSecondTexture("../"+line->GetParam("texture")->AsPath("textures"));
}
continue;
}
if (line->GetCommand() == "Background" && !resetObject)
{
std::string path = "";
if(line->GetParam("image")->IsDefined())
path = "../"+line->GetParam("image")->AsPath("textures");
m_engine->SetBackground(path.c_str(),
line->GetParam("up")->AsColor(Gfx::Color(0.0f, 0.0f, 0.0f, 0.0f)),
line->GetParam("down")->AsColor(Gfx::Color(0.0f, 0.0f, 0.0f, 0.0f)),
line->GetParam("cloudUp")->AsColor(Gfx::Color(0.0f, 0.0f, 0.0f, 0.0f)),
line->GetParam("cloudDown")->AsColor(Gfx::Color(0.0f, 0.0f, 0.0f, 0.0f)),
line->GetParam("full")->AsBool(false));
continue;
}
if (line->GetCommand() == "Planet" && !resetObject)
{
Math::Vector ppos, uv1, uv2;
ppos = line->GetParam("pos")->AsPoint();
uv1 = line->GetParam("uv1")->AsPoint();
uv2 = line->GetParam("uv2")->AsPoint();
m_planet->Create(line->GetParam("mode")->AsInt(0),
Math::Point(ppos.x, ppos.z),
line->GetParam("dim")->AsFloat(0.2f),
line->GetParam("speed")->AsFloat(0.0f),
line->GetParam("dir")->AsFloat(0.0f),
"../"+line->GetParam("image")->AsPath("textures"),
Math::Point(uv1.x, uv1.z),
Math::Point(uv2.x, uv2.z),
line->GetParam("image")->AsPath("textures").find("planet") != std::string::npos // TODO: add transparent op or modify textures
);
continue;
}
if (line->GetCommand() == "ForegroundName" && !resetObject)
{
m_engine->SetForegroundName("../"+line->GetParam("image")->AsPath("textures"));
continue;
}
if (((line->GetCommand() == "Global") || (m_version >= 2 && line->GetCommand() == "Mission")) && !resetObject)
{
g_unit = line->GetParam("unitScale")->AsFloat(4.0f);
m_engine->SetTracePrecision(line->GetParam("traceQuality")->AsFloat(1.0f));
m_shortCut = line->GetParam("shortcut")->AsBool(true);
if (m_version >= 2)
{
m_retroStyle = line->GetParam("retro")->AsBool(false);
if (m_retroStyle) GetLogger()->Info("Retro mode enabled.\n");
}
continue;
}
if (line->GetCommand() == "TerrainGenerate" && !resetObject)
{
m_terrain->Generate(line->GetParam("mosaic")->AsInt(20),
line->GetParam("brick")->AsInt(3),
line->GetParam("size")->AsFloat(20.0f),
line->GetParam("vision")->AsFloat(500.0f)*g_unit,
line->GetParam("depth")->AsInt(2),
line->GetParam("hard")->AsFloat(0.5f));
continue;
}
if (line->GetCommand() == "TerrainWind" && !resetObject)
{
m_terrain->SetWind(line->GetParam("speed")->AsPoint());
continue;
}
if (line->GetCommand() == "TerrainRelief" && !resetObject)
{
m_terrain->LoadRelief(
line->GetParam("image")->AsPath("textures"),
line->GetParam("factor")->AsFloat(1.0f),
line->GetParam("border")->AsBool(true));
continue;
}
if (line->GetCommand() == "TerrainRandomRelief" && !resetObject)
{
m_terrain->RandomizeRelief();
continue;
}
if (line->GetCommand() == "TerrainResource" && !resetObject)
{
m_terrain->LoadResources(line->GetParam("image")->AsPath("textures"));
continue;
}
if (line->GetCommand() == "TerrainWater" && !resetObject)
{
Math::Vector pos;
pos.x = line->GetParam("moxeX")->AsFloat(0.0f);
pos.y = line->GetParam("moxeY")->AsFloat(0.0f);
pos.z = pos.x;
m_water->Create(line->GetParam("air")->AsWaterType(Gfx::WATER_TT),
line->GetParam("water")->AsWaterType(Gfx::WATER_TT),
"../"+line->GetParam("image")->AsPath("textures"),
line->GetParam("diffuse")->AsColor(Gfx::Color(1.0f, 1.0f, 1.0f, 1.0f)),
line->GetParam("ambient")->AsColor(Gfx::Color(1.0f, 1.0f, 1.0f, 1.0f)),
line->GetParam("level")->AsFloat(100.0f)*g_unit,
line->GetParam("glint")->AsFloat(1.0f),
pos);
m_colorNewWater = line->GetParam("color")->AsColor(m_colorRefWater);
m_colorShiftWater = line->GetParam("brightness")->AsFloat(0.0f);
continue;
}
if (line->GetCommand() == "TerrainLava" && !resetObject)
{
m_water->SetLava(line->GetParam("mode")->AsBool());
continue;
}
if (line->GetCommand() == "TerrainCloud" && !resetObject)
{
std::string path = "";
if(line->GetParam("image")->IsDefined())
path = "../"+line->GetParam("image")->AsPath("textures");
m_cloud->Create(path,
line->GetParam("diffuse")->AsColor(Gfx::Color(1.0f, 1.0f, 1.0f, 1.0f)),
line->GetParam("ambient")->AsColor(Gfx::Color(1.0f, 1.0f, 1.0f, 1.0f)),
line->GetParam("level")->AsFloat(500.0f)*g_unit);
continue;
}
if (line->GetCommand() == "TerrainBlitz" && !resetObject)
{
m_lightning->Create(line->GetParam("sleep")->AsFloat(0.0f),
line->GetParam("delay")->AsFloat(3.0f),
line->GetParam("magnetic")->AsFloat(50.0f)*g_unit);
continue;
}
if (line->GetCommand() == "TerrainInitTextures" && !resetObject)
{
std::string name = "../"+line->GetParam("image")->AsPath("textures");
if(name.find(".") == std::string::npos)
name += ".png";
unsigned int dx = line->GetParam("dx")->AsInt(1);
unsigned int dy = line->GetParam("dy")->AsInt(1);
int tt[100]; //TODO: I have no idea how TerrainInitTextures works, but maybe we shuld remove the limit to 100?
if(dx*dy > 100)
throw CLevelParserException("In TerrainInitTextures: dx*dy must be <100");
if(line->GetParam("table")->IsDefined()) {
const std::vector<CLevelParserParam*>& table = line->GetParam("table")->AsArray();
if(table.size() > dx*dy)
throw CLevelParserException("In TerrainInitTextures: table size must be dx*dy");
for (unsigned int i = 0; i < dx*dy; i++)
{
if(i >= table.size())
{
tt[i] = 0;
} else {
tt[i] = table[i]->AsInt();
}
}
} else {
for (unsigned int i = 0; i < dx*dy; i++)
{
tt[i] = 0;
}
}
m_terrain->InitTextures(name.c_str(), tt, dx, dy);
continue;
}
if (line->GetCommand() == "TerrainInit" && !resetObject)
{
m_terrain->InitMaterials(line->GetParam("id")->AsInt(1));
continue;
}
if (line->GetCommand() == "TerrainMaterial" && !resetObject)
{
std::string name = line->GetParam("image")->AsPath("textures");
if(name.find(".") == std::string::npos)
name += ".png";
name = "../"+name;
m_terrain->AddMaterial(line->GetParam("id")->AsInt(0),
name.c_str(),
Math::Point(line->GetParam("u")->AsFloat(),
line->GetParam("v")->AsFloat()),
line->GetParam("up")->AsInt(),
line->GetParam("right")->AsInt(),
line->GetParam("down")->AsInt(),
line->GetParam("left")->AsInt(),
line->GetParam("hard")->AsFloat(0.5f));
continue;
}
if (line->GetCommand() == "TerrainLevel" && !resetObject)
{
int id[50]; //TODO: I have no idea how TerrainLevel works, but maybe we should remove the limit to 50?
if(line->GetParam("id")->IsDefined()) {
const std::vector<CLevelParserParam*>& id_array = line->GetParam("id")->AsArray();
if(id_array.size() > 50)
throw CLevelParserException("In TerrainLevel: id array size must be < 50");
unsigned int i = 0;
while (i < 50)
{
id[i] = id_array[i]->AsInt();
i++;
if(i >= id_array.size()) break;
}
id[i] = 0;
}
m_terrain->GenerateMaterials(id,
line->GetParam("min")->AsFloat(0.0f)*g_unit,
line->GetParam("max")->AsFloat(100.0f)*g_unit,
line->GetParam("slope")->AsFloat(5.0f),
line->GetParam("freq")->AsFloat(100.0f),
line->GetParam("center")->AsPoint(Math::Vector(0.0f, 0.0f, 0.0f))*g_unit,
line->GetParam("radius")->AsFloat(0.0f)*g_unit);
continue;
}
if (line->GetCommand() == "TerrainCreate" && !resetObject)
{
m_terrain->CreateObjects();
continue;
}
if (line->GetCommand() == "BeginObject")
{
InitEye();
SetMovieLock(false);
if (read[0] != 0) // loading file ?
sel = IOReadScene(read, stack);
continue;
}
if (line->GetCommand() == "MissionController" && read[0] == 0 && m_version >= 2)
{
m_controller = CObjectManager::GetInstancePointer()->CreateObject(Math::Vector(0.0f, 0.0f, 0.0f), 0.0f, OBJECT_CONTROLLER, 100.0f);
m_controller->SetMagnifyDamage(100.0f);
m_controller->SetIgnoreBuildCheck(true);
CBrain* brain = m_controller->GetBrain();
if (brain != nullptr)
{
std::string name = "../"+line->GetParam("script")->AsPath("ai");
if (!name.empty())
brain->SetScriptName(0, const_cast<char*>(name.c_str()));
brain->SetScriptRun(0);
}
continue;
}
if (line->GetCommand() == "CreateObject" && read[0] == 0)
{
ObjectType type = line->GetParam("type")->AsObjectType();
int gadget = line->GetParam("gadget")->AsInt(-1);
if ( gadget == -1 )
{
gadget = 0;
if ( type == OBJECT_TECH ||
(type >= OBJECT_PLANT0 &&
type <= OBJECT_PLANT19 ) ||
(type >= OBJECT_TREE0 &&
type <= OBJECT_TREE5 ) ||
(type >= OBJECT_TEEN0 &&
type <= OBJECT_TEEN44 ) ||
(type >= OBJECT_QUARTZ0 &&
type <= OBJECT_QUARTZ3 ) ||
(type >= OBJECT_ROOT0 &&
type <= OBJECT_ROOT4 ) ) // not ROOT5!
{
if ( type != OBJECT_TEEN11 && // lamp?
type != OBJECT_TEEN12 && // coke?
type != OBJECT_TEEN20 && // wall?
type != OBJECT_TEEN21 && // wall?
type != OBJECT_TEEN22 && // wall?
type != OBJECT_TEEN26 && // lamp?
type != OBJECT_TEEN28 && // bottle?
type != OBJECT_TEEN34 ) // stone?
{
gadget = 1;
}
}
}
if (gadget != 0) // is this a gadget?
{
if (!TestGadgetQuantity(rankGadget++)) continue;
}
Math::Vector pos = line->GetParam("pos")->AsPoint()*g_unit;
float dirAngle = line->GetParam("dir")->AsFloat(0.0f)*Math::PI;
bool trainer;
CObject* obj = CObjectManager::GetInstancePointer()->CreateObject(
pos, dirAngle,
type,
line->GetParam("power")->AsFloat(1.0f),
line->GetParam("z")->AsFloat(1.0f),
line->GetParam("h")->AsFloat(0.0f),
trainer = line->GetParam("trainer")->AsBool(false),
line->GetParam("toy")->AsBool(false),
line->GetParam("option")->AsInt(0)
);
if (m_fixScene && type == OBJECT_HUMAN)
{
CMotion* motion = obj->GetMotion();
if (m_phase == PHASE_WIN ) motion->SetAction(MHS_WIN, 0.4f);
if (m_phase == PHASE_LOST) motion->SetAction(MHS_LOST, 0.5f);
}
if (obj != nullptr)
{
obj->SetDefRank(rankObj);
if (type == OBJECT_BASE) m_base = obj;
Gfx::CameraType cType = line->GetParam("camera")->AsCameraType(Gfx::CAM_TYPE_NULL);
if (cType != Gfx::CAM_TYPE_NULL)
obj->SetCameraType(cType);
obj->SetCameraDist(line->GetParam("cameraDist")->AsFloat(50.0f));
obj->SetCameraLock(line->GetParam("cameraLock")->AsBool(false));
Gfx::PyroType pType = line->GetParam("pyro")->AsPyroType(Gfx::PT_NULL);
if (pType != Gfx::PT_NULL)
{
Gfx::CPyro* pyro = new Gfx::CPyro();
pyro->Create(pType, obj);
}
// Puts information in terminal (OBJECT_INFO).
for (int i = 0; i < OBJECTMAXINFO; i++)
{
std::string op = "info"+boost::lexical_cast<std::string>(i+1);
if(!line->GetParam(op)->IsDefined()) break;
std::string text = line->GetParam(op)->AsString();
std::size_t p = text.find_first_of("=");
if(p == std::string::npos)
throw CLevelParserExceptionBadParam(line->GetParam(op), "info");
Info info;
strcpy(info.name, text.substr(0, p).c_str());
try {
info.value = boost::lexical_cast<float>(text.substr(p+1).c_str());
}
catch(...)
{
throw CLevelParserExceptionBadParam(line->GetParam(op), "info.value (float)");
}
obj->SetInfo(i, info);
}
// Sets the parameters of the command line.
if(line->GetParam("cmdline")->IsDefined()) {
const std::vector<CLevelParserParam*>& cmdline = line->GetParam("cmdline")->AsArray();
for (unsigned int i = 0; i < OBJECTMAXCMDLINE && i < cmdline.size(); i++) //TODO: get rid of the limit
{
obj->SetCmdLine(i, cmdline[i]->AsFloat());
}
}
if (line->GetParam("select")->AsBool(false))
{
sel = obj;
}
bool selectable = line->GetParam("selectable")->AsBool(true);
obj->SetSelectable(selectable);
obj->SetIgnoreBuildCheck(line->GetParam("ignoreBuildCheck")->AsBool(false));
obj->SetEnable(line->GetParam("enable")->AsBool(true));
obj->SetProxyActivate(line->GetParam("proxyActivate")->AsBool(false));
obj->SetProxyDistance(line->GetParam("proxyDistance")->AsFloat(15.0f)*g_unit);
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->SetClip(line->GetParam("clip")->AsBool(true));
obj->SetCheckToken(m_version >= 2 ? trainer || !selectable : line->GetParam("checkToken")->AsBool(true));
// SetManual will affect bot speed
if (type == OBJECT_MOBILEdr)
{
obj->SetManual(m_version >= 2 ? !trainer : line->GetParam("manual")->AsBool(false));
}
if (m_version >= 2)
{
Math::Vector zoom = line->GetParam("zoom")->AsPoint(Math::Vector(0.0f, 0.0f, 0.0f));
if (zoom.x != 0.0f || zoom.y != 0.0f || zoom.z != 0.0f)
obj->SetZoom(0, zoom);
}
//TODO: I don't remember what this is used for
CMotion* motion = obj->GetMotion();
if (motion != nullptr && line->GetParam("param")->IsDefined())
{
const std::vector<CLevelParserParam*>& p = line->GetParam("param")->AsArray();
for (unsigned int i = 0; i < 10 && i < p.size(); i++)
{
motion->SetParam(i, p[i]->AsFloat());
}
}
int run = -1;
CBrain* brain = obj->GetBrain();
if (brain != nullptr)
{
for (int i = 0; i < 10; i++)
{
std::string op = "script"+boost::lexical_cast<std::string>(i+1); // script1..script10
if(line->GetParam(op)->IsDefined()) {
brain->SetScriptName(i, const_cast<char*>(("../"+line->GetParam(op)->AsPath("ai")).c_str()));
}
}
int i = line->GetParam("run")->AsInt(0);
if (i != 0)
{
run = i-1;
brain->SetScriptRun(run);
}
}
CAuto* automat = obj->GetAuto();
if (automat != nullptr)
{
type = line->GetParam("autoType")->AsObjectType(OBJECT_NULL);
automat->SetType(type);
for (int i = 0; i < 5; i++)
{
std::string op = "autoValue"+boost::lexical_cast<std::string>(i+1); // autoValue1..autoValue5
automat->SetValue(i, line->GetParam(op)->AsFloat(0.0f));
}
automat->SetString(const_cast<char*>(line->GetParam("autoString")->AsPath("ai", "").c_str()));
int i = line->GetParam("run")->AsInt(-1);
if (i != -1)
{
if (i != PARAM_FIXSCENE &&
!m_dialog->GetMovies()) i = 0;
automat->Start(i); // starts the film
}
}
if (soluce && brain != nullptr && line->GetParam("soluce")->IsDefined())
brain->SetSoluceName(const_cast<char*>(line->GetParam("soluce")->AsString().c_str()));
obj->SetResetPosition(obj->GetPosition(0));
obj->SetResetAngle(obj->GetAngle(0));
obj->SetResetRun(run);
if (line->GetParam("reset")->AsBool(false))
obj->SetResetCap(RESET_MOVE);
}
rankObj ++;
continue;
}
if (line->GetCommand() == "CreateFog" && !resetObject)
{
Gfx::ParticleType type = static_cast<Gfx::ParticleType>(Gfx::PARTIFOG0+(line->GetParam("type")->AsInt()));
Math::Vector pos = line->GetParam("pos")->AsPoint()*g_unit;
float height = line->GetParam("height")->AsFloat(1.0f)*g_unit;
float ddim = line->GetParam("dim")->AsFloat(50.0f)*g_unit;
float delay = line->GetParam("delay")->AsFloat(2.0f);
m_terrain->AdjustToFloor(pos);
pos.y += height;
Math::Point dim;
dim.x = ddim;
dim.y = dim.x;
m_particle->CreateParticle(pos, Math::Vector(0.0f, 0.0f, 0.0f), dim, type, delay, 0.0f, 0.0f);
continue;
}
if (line->GetCommand() == "CreateLight" && !resetObject)
{
Gfx::EngineObjectType type;
int lightRank = CreateLight(line->GetParam("dir")->AsPoint(),
line->GetParam("color")->AsColor(Gfx::Color(0.5f, 0.5f, 0.5f, 1.0f)));
type = line->GetParam("type")->AsTerrainType(Gfx::ENG_OBJTYPE_NULL);
if (type == Gfx::ENG_OBJTYPE_TERRAIN)
{
m_lightMan->SetLightPriority(lightRank, Gfx::LIGHT_PRI_HIGHEST);
m_lightMan->SetLightIncludeType(lightRank, Gfx::ENG_OBJTYPE_TERRAIN);
}
if (type == Gfx::ENG_OBJTYPE_QUARTZ)
m_lightMan->SetLightIncludeType(lightRank, Gfx::ENG_OBJTYPE_QUARTZ);
if (type == Gfx::ENG_OBJTYPE_METAL)
m_lightMan->SetLightIncludeType(lightRank, Gfx::ENG_OBJTYPE_METAL);
if (type == Gfx::ENG_OBJTYPE_FIX)
m_lightMan->SetLightExcludeType(lightRank, Gfx::ENG_OBJTYPE_TERRAIN);
continue;
}
if (line->GetCommand() == "CreateSpot" && !resetObject)
{
Gfx::EngineObjectType type;
int rankLight = CreateSpot(line->GetParam("pos")->AsPoint()*g_unit,
line->GetParam("color")->AsColor(Gfx::Color(0.5f, 0.5f, 0.5f, 1.0f)));
type = line->GetParam("type")->AsTerrainType(Gfx::ENG_OBJTYPE_NULL);
if (type == Gfx::ENG_OBJTYPE_TERRAIN)
m_lightMan->SetLightIncludeType(rankLight, Gfx::ENG_OBJTYPE_TERRAIN);
if (type == Gfx::ENG_OBJTYPE_QUARTZ)
m_lightMan->SetLightIncludeType(rankLight, Gfx::ENG_OBJTYPE_QUARTZ);
if (type == Gfx::ENG_OBJTYPE_METAL)
m_lightMan->SetLightIncludeType(rankLight, Gfx::ENG_OBJTYPE_METAL);
if (type == Gfx::ENG_OBJTYPE_FIX)
m_lightMan->SetLightExcludeType(rankLight, Gfx::ENG_OBJTYPE_TERRAIN);
continue;
}
if (line->GetCommand() == "GroundSpot" && !resetObject)
{
rank = m_engine->CreateGroundSpot();
if (rank != -1)
{
m_engine->SetObjectGroundSpotPos(rank, line->GetParam("pos")->AsPoint(Math::Vector(0.0f, 0.0f, 0.0f))*g_unit);
m_engine->SetObjectGroundSpotRadius(rank, line->GetParam("radius")->AsFloat(10.0f)*g_unit);
m_engine->SetObjectGroundSpotColor(rank, line->GetParam("color")->AsColor(Gfx::Color(0.533f, 0.533f, 0.533f, 0.533f)));
m_engine->SetObjectGroundSpotSmooth(rank, line->GetParam("smooth")->AsFloat(1.0f));
m_engine->SetObjectGroundSpotMinMax(rank, line->GetParam("min")->AsFloat(0.0f)*g_unit,
line->GetParam("max")->AsFloat(0.0f)*g_unit);
}
continue;
}
if (line->GetCommand() == "WaterColor" && !resetObject)
{
m_engine->SetWaterAddColor(line->GetParam("color")->AsColor());
continue;
}
if (line->GetCommand() == "MapColor" && !resetObject)
{
m_map->FloorColorMap(line->GetParam("floor")->AsColor(Gfx::Color(0.533f, 0.533f, 0.533f, 0.533f)),
line->GetParam("water")->AsColor(Gfx::Color(0.533f, 0.533f, 0.533f, 0.533f)));
m_mapShow = line->GetParam("show")->AsBool(true);
m_map->ShowMap(m_mapShow);
m_map->SetToy(line->GetParam("toyIcon")->AsBool(false));
m_mapImage = line->GetParam("image")->AsBool(false);
if (m_mapImage)
{
Math::Vector offset;
strcpy(m_mapFilename, ("../"+line->GetParam("filename")->AsPath("textures")).c_str());
offset = line->GetParam("offset")->AsPoint(Math::Vector(0.0f, 0.0f, 0.0f));
m_map->SetFixParam(line->GetParam("zoom")->AsFloat(1.0f),
offset.x, offset.z,
line->GetParam("angle")->AsFloat(0.0f)*Math::PI/180.0f,
line->GetParam("mode")->AsInt(0),
line->GetParam("debug")->AsBool(false));
}
continue;
}
if (line->GetCommand() == "MapZoom" && !resetObject)
{
m_map->ZoomMap(line->GetParam("factor")->AsFloat(2.0f));
m_map->MapEnable(line->GetParam("enable")->AsBool(true));
continue;
}
if (line->GetCommand() == "MaxFlyingHeight" && !resetObject)
{
m_terrain->SetFlyingMaxHeight(line->GetParam("max")->AsFloat(280.0f)*g_unit);
continue;
}
if (line->GetCommand() == "AddFlyingHeight" && !resetObject)
{
m_terrain->AddFlyingLimit(line->GetParam("center")->AsPoint()*g_unit,
line->GetParam("extRadius")->AsFloat(20.0f)*g_unit,
line->GetParam("intRadius")->AsFloat(10.0f)*g_unit,
line->GetParam("maxHeight")->AsFloat(200.0f));
continue;
}
if (line->GetCommand() == "Camera")
{
m_camera->Init(line->GetParam("eye")->AsPoint(Math::Vector(0.0f, 0.0f, 0.0f))*g_unit,
line->GetParam("lookat")->AsPoint(Math::Vector(0.0f, 0.0f, 0.0f))*g_unit,
resetObject ? 0.0f : line->GetParam("delay")->AsFloat(0.0f));
if (line->GetParam("fadeIn")->AsBool(false))
m_camera->StartOver(Gfx::CAM_OVER_EFFECT_FADEIN_WHITE, Math::Vector(0.0f, 0.0f, 0.0f), 1.0f);
m_camera->SetFixDirection(line->GetParam("fixDirection")->AsFloat(0.25f)*Math::PI);
continue;
}
if (line->GetCommand() == "EndMissionTake" && !resetObject && m_controller == nullptr)
{
int i = m_endTakeTotal;
if (i < 10)
{
m_endTake[i].pos = line->GetParam("pos")->AsPoint(Math::Vector(0.0f, 0.0f, 0.0f))*g_unit;
m_endTake[i].dist = line->GetParam("dist")->AsFloat(m_version < 2 ? 8.0f : 100.0f)*g_unit;
m_endTake[i].type = line->GetParam("type")->AsObjectType(OBJECT_NULL);
m_endTake[i].min = line->GetParam("min")->AsInt(1);
m_endTake[i].max = line->GetParam("max")->AsInt(9999);
if (m_version >= 2)
{
m_endTake[i].powermin = line->GetParam("powermin")->AsFloat(-1);
m_endTake[i].powermax = line->GetParam("powermax")->AsFloat(100);
m_endTake[i].tool = line->GetParam("tool")->AsToolType(TOOL_OTHER);
m_endTake[i].drive = line->GetParam("drive")->AsDriveType(DRIVE_OTHER);
}
else
{
m_endTake[i].powermin = -1;
m_endTake[i].powermax = 100;
m_endTake[i].tool = TOOL_OTHER;
m_endTake[i].drive = DRIVE_OTHER;
}
m_endTake[i].lost = line->GetParam("lost")->AsInt(-1);
m_endTake[i].immediat = line->GetParam("immediat")->AsBool(false);
strcpy(m_endTake[i].message, line->GetParam("message")->AsString("").c_str()); //TODO: Really, ending mission on message()? Is this used anywhere? Do we need that?
m_endTakeTotal ++;
}
continue;
}
if (line->GetCommand() == "EndMissionDelay" && !resetObject && m_controller == nullptr)
{
m_endTakeWinDelay = line->GetParam("win")->AsFloat(2.0f);
m_endTakeLostDelay = line->GetParam("lost")->AsFloat(2.0f);
continue;
}
if (line->GetCommand() == "EndMissionResearch" && !resetObject && m_controller == nullptr) //TODO: Is this used anywhere?
{
m_endTakeResearch |= line->GetParam("type")->AsResearchFlag();
continue;
}
if (line->GetCommand() == "EndMissionNever" && !resetObject && m_controller == nullptr)
{
m_endTakeNever = true;
continue;
}
if (line->GetCommand() == "ObligatoryToken" && !resetObject) //NOTE: This was used only in CeeBot, maybe we should add this to some Colobot exercises?
{
int i = m_obligatoryTotal;
if (i < 100) //TODO: remove the limit
{
strcpy(m_obligatoryToken[i], line->GetParam("text")->AsString().c_str());
m_obligatoryTotal ++;
}
continue;
}
if (line->GetCommand() == "ProhibitedToken" && !resetObject) //NOTE: This was used only in CeeBot, maybe we should add this to some Colobot exercises?
{
int i = m_prohibitedTotal;
if (i < 100) //TODO: remove the limit
{
strcpy(m_prohibitedToken[i], line->GetParam("text")->AsString().c_str());
m_prohibitedTotal ++;
}
continue;
}
if (line->GetCommand() == "EnableBuild" && !resetObject)
{
g_build |= line->GetParam("type")->AsBuildFlag();
continue;
}
if (line->GetCommand() == "EnableResearch" && !resetObject)
{
g_researchEnable |= line->GetParam("type")->AsResearchFlag();
continue;
}
if (line->GetCommand() == "DoneResearch" && read[0] == 0 && !resetObject) // not loading file?
{
g_researchDone |= line->GetParam("type")->AsResearchFlag();
continue;
}
if (line->GetCommand() == "NewScript" && !resetObject)
{
AddNewScriptName(line->GetParam("type")->AsObjectType(OBJECT_NULL), const_cast<char*>(line->GetParam("name")->AsPath("ai").c_str()));
continue;
}
if(read[0] != 0) continue; // ignore errors when loading saved game (TODO: don't report ones that are just not loaded when loading saved game)
if(resetObject) continue; // ignore when reseting just objects (TODO: see above)
throw CLevelParserException("Unknown command: '"+line->GetCommand()+"' in "+line->GetLevel()->GetFilename()+":"+boost::lexical_cast<std::string>(line->GetLineNumber()));
}
if (read[0] == 0)
CompileScript(soluce); // compiles all scripts
if (strcmp(base, "missions") == 0 && !resetObject) // mission?
WriteFreeParam();
if (strcmp(base, "freemissions") == 0 && !resetObject) // free play?
{
g_researchDone = m_freeResearch;
g_build = m_freeBuild;
g_build &= ~BUILD_RESEARCH;
g_build &= ~BUILD_LABO;
g_build |= BUILD_FACTORY;
g_build |= BUILD_GFLAT;
g_build |= BUILD_FLAG;
}
if (!resetObject)
{
ChangeColor(); // changes the colors of texture
m_short->SetMode(false); // vehicles?
}
CreateShortcuts();
m_map->UpdateMap();
// TODO: m_engine->TimeInit(); ??
m_app->ResetKeyStates();
m_time = 0.0f;
m_gameTime = 0.0f;
m_autosaveLast = 0.0f;
m_infoUsed = 0;
m_selectObject = sel;
if (m_base == nullptr && // no main base?
!m_fixScene) // interractive scene?
{
CObject* obj;
if (sel == nullptr)
obj = SearchHuman();
else
obj = sel;
if (obj != nullptr)
{
SelectObject(obj);
m_camera->SetControllingObject(obj);
m_camera->SetType(obj->GetCameraType());
}
}
if (m_fixScene)
m_camera->SetType(Gfx::CAM_TYPE_SCRIPT);
if (read[0] != 0 && sel != 0) // loading file?
{
Math::Vector pos = sel->GetPosition(0);
m_camera->Init(pos, pos, 0.0f);
m_camera->FixCamera();
SelectObject(sel);
m_camera->SetControllingObject(sel);
m_beginSatCom = true; // message already displayed
}
} catch(...) {
m_dialog->SetSceneRead("");
m_dialog->SetStackRead("");
throw;
}
m_dialog->SetSceneRead("");
m_dialog->SetStackRead("");
if(m_app->GetSceneTestMode())
m_eventQueue->AddEvent(Event(EVENT_QUIT));
}
//! Creates a directional light
int CRobotMain::CreateLight(Math::Vector direction, Gfx::Color color)
{
if (direction.x == 0.0f &&
direction.y == 0.0f &&
direction.z == 0.0f)
{
direction.y = -1.0f;
}
Gfx::Light light;
light.type = Gfx::LIGHT_DIRECTIONAL;
light.diffuse = color;
light.ambient = color * 0.1f;
light.direction = direction;
int obj = m_lightMan->CreateLight(Gfx::LIGHT_PRI_HIGH);
m_lightMan->SetLight(obj, light);
return obj;
}
//! Creates a light spot
int CRobotMain::CreateSpot(Math::Vector pos, Gfx::Color color)
{
if (!m_engine->GetLightMode()) return -1;
pos.y += m_terrain->GetFloorLevel(pos);
Gfx::Light light;
light.type = Gfx::LIGHT_SPOT;
light.diffuse = color;
light.ambient = color * 0.1f;
light.position = pos;
light.direction = Math::Vector(0.0f, -1.0f, 0.0f);
light.spotIntensity = 1.0f;
light.spotAngle = 90.0f*Math::PI/180.0f;
light.attenuation0 = 2.0f;
light.attenuation1 = 0.0f;
light.attenuation2 = 0.0f;
int obj = m_lightMan->CreateLight(Gfx::LIGHT_PRI_HIGH);
m_lightMan->SetLight(obj, light);
return obj;
}
//! Change the colors and textures
void CRobotMain::ChangeColor()
{
Math::Point ts = Math::Point(0.0f, 0.0f);
Math::Point ti = Math::Point(1.0f, 1.0f); // the entire image
Gfx::Color colorRef1, colorNew1, colorRef2, colorNew2;
colorRef1.a = 0.0f;
colorRef2.a = 0.0f;
colorRef1.r = 206.0f/256.0f;
colorRef1.g = 206.0f/256.0f;
colorRef1.b = 204.0f/256.0f; // ~white
colorNew1 = m_dialog->GetGamerColorCombi();
colorRef2.r = 255.0f/256.0f;
colorRef2.g = 132.0f/256.0f;
colorRef2.b = 1.0f/256.0f; // orange
colorNew2 = m_dialog->GetGamerColorBand();
Math::Point exclu[6];
exclu[0] = Math::Point(192.0f/256.0f, 0.0f/256.0f);
exclu[1] = Math::Point(256.0f/256.0f, 64.0f/256.0f); // crystals + cylinders
exclu[2] = Math::Point(208.0f/256.0f, 224.0f/256.0f);
exclu[3] = Math::Point(256.0f/256.0f, 256.0f/256.0f); // SatCom screen
exclu[4] = Math::Point(0.0f, 0.0f);
exclu[5] = Math::Point(0.0f, 0.0f); // terminator
m_engine->ChangeTextureColor("textures/objects/human.png", colorRef1, colorNew1, colorRef2, colorNew2, 0.30f, 0.01f, ts, ti, exclu);
float tolerance;
int face = GetGamerFace();
if (face == 0) // normal?
{
colorRef1.r = 90.0f/256.0f;
colorRef1.g = 95.0f/256.0f;
colorRef1.b = 85.0f/256.0f; // black
tolerance = 0.15f;
}
if (face == 1) // bald?
{
colorRef1.r = 74.0f/256.0f;
colorRef1.g = 58.0f/256.0f;
colorRef1.b = 46.0f/256.0f; // brown
tolerance = 0.20f;
}
if (face == 2) // carlos?
{
colorRef1.r = 70.0f/256.0f;
colorRef1.g = 40.0f/256.0f;
colorRef1.b = 8.0f/256.0f; // brown
tolerance = 0.30f;
}
if (face == 3) // blonde?
{
colorRef1.r = 74.0f/256.0f;
colorRef1.g = 16.0f/256.0f;
colorRef1.b = 0.0f/256.0f; // yellow
tolerance = 0.20f;
}
colorNew1 = m_dialog->GetGamerColorHair();
colorRef2.r = 0.0f;
colorRef2.g = 0.0f;
colorRef2.b = 0.0f;
colorNew2.r = 0.0f;
colorNew2.g = 0.0f;
colorNew2.b = 0.0f;
char name[100];
sprintf(name, "textures/objects/face%.2d.png", face+1);
exclu[0] = Math::Point(105.0f/256.0f, 47.0f/166.0f);
exclu[1] = Math::Point(153.0f/256.0f, 79.0f/166.0f); // blue canister
exclu[2] = Math::Point(0.0f, 0.0f);
exclu[3] = Math::Point(0.0f, 0.0f); // terminator
m_engine->ChangeTextureColor(name, colorRef1, colorNew1, colorRef2, colorNew2, tolerance, 0.00f, ts, ti, exclu);
colorRef2.r = 0.0f;
colorRef2.g = 0.0f;
colorRef2.b = 0.0f;
colorNew2.r = 0.0f;
colorNew2.g = 0.0f;
colorNew2.b = 0.0f;
m_engine->ChangeTextureColor("textures/objects/base1.png", m_colorRefBot, m_colorNewBot, colorRef2, colorNew2, 0.10f, -1.0f, ts, ti, 0, 0, true);
m_engine->ChangeTextureColor("textures/objects/convert.png", m_colorRefBot, m_colorNewBot, colorRef2, colorNew2, 0.10f, -1.0f, ts, ti, 0, 0, true);
m_engine->ChangeTextureColor("textures/objects/derrick.png", m_colorRefBot, m_colorNewBot, colorRef2, colorNew2, 0.10f, -1.0f, ts, ti, 0, 0, true);
m_engine->ChangeTextureColor("textures/objects/factory.png", m_colorRefBot, m_colorNewBot, colorRef2, colorNew2, 0.10f, -1.0f, ts, ti, 0, 0, true);
m_engine->ChangeTextureColor("textures/objects/lemt.png", m_colorRefBot, m_colorNewBot, colorRef2, colorNew2, 0.10f, -1.0f, ts, ti, 0, 0, true);
m_engine->ChangeTextureColor("textures/objects/roller.png", m_colorRefBot, m_colorNewBot, colorRef2, colorNew2, 0.10f, -1.0f, ts, ti, 0, 0, true);
m_engine->ChangeTextureColor("textures/objects/search.png", m_colorRefBot, m_colorNewBot, colorRef2, colorNew2, 0.10f, -1.0f, ts, ti, 0, 0, true);
exclu[0] = Math::Point( 0.0f/256.0f, 160.0f/256.0f);
exclu[1] = Math::Point(256.0f/256.0f, 256.0f/256.0f); // pencils
exclu[2] = Math::Point(0.0f, 0.0f);
exclu[3] = Math::Point(0.0f, 0.0f); // terminator
m_engine->ChangeTextureColor("textures/objects/drawer.png", m_colorRefBot, m_colorNewBot, colorRef2, colorNew2, 0.10f, -1.0f, ts, ti, exclu, 0, true);
exclu[0] = Math::Point(237.0f/256.0f, 176.0f/256.0f);
exclu[1] = Math::Point(256.0f/256.0f, 220.0f/256.0f); // blue canister
exclu[2] = Math::Point(106.0f/256.0f, 150.0f/256.0f);
exclu[3] = Math::Point(130.0f/256.0f, 214.0f/256.0f); // safe location
exclu[4] = Math::Point(0.0f, 0.0f);
exclu[5] = Math::Point(0.0f, 0.0f); // terminator
m_engine->ChangeTextureColor("textures/objects/subm.png", m_colorRefBot, m_colorNewBot, colorRef2, colorNew2, 0.10f, -1.0f, ts, ti, exclu, 0, true);
exclu[0] = Math::Point(128.0f/256.0f, 160.0f/256.0f);
exclu[1] = Math::Point(256.0f/256.0f, 256.0f/256.0f); // SatCom
exclu[2] = Math::Point(0.0f, 0.0f);
exclu[3] = Math::Point(0.0f, 0.0f); // terminator
m_engine->ChangeTextureColor("textures/objects/ant.png", m_colorRefAlien, m_colorNewAlien, colorRef2, colorNew2, 0.50f, -1.0f, ts, ti, exclu);
m_engine->ChangeTextureColor("textures/objects/mother.png", m_colorRefAlien, m_colorNewAlien, colorRef2, colorNew2, 0.50f, -1.0f, ts, ti);
m_engine->ChangeTextureColor("textures/objects/plant.png", m_colorRefGreen, m_colorNewGreen, colorRef2, colorNew2, 0.50f, -1.0f, ts, ti);
// PARTIPLOUF0 and PARTIDROP :
ts = Math::Point(0.500f, 0.500f);
ti = Math::Point(0.875f, 0.750f);
m_engine->ChangeTextureColor("textures/effect00.png", m_colorRefWater, m_colorNewWater, colorRef2, colorNew2, 0.20f, -1.0f, ts, ti, 0, m_colorShiftWater, true);
// PARTIFLIC :
ts = Math::Point(0.00f, 0.75f);
ti = Math::Point(0.25f, 1.00f);
m_engine->ChangeTextureColor("textures/effect02.png", m_colorRefWater, m_colorNewWater, colorRef2, colorNew2, 0.20f, -1.0f, ts, ti, 0, m_colorShiftWater, true);
}
//! Updates the number of unnecessary objects
bool CRobotMain::TestGadgetQuantity(int rank)
{
static int table10[10] = {0,1,0,0,0,0,0,0,0,0};
static int table20[10] = {0,1,0,0,0,1,0,0,0,0};
static int table30[10] = {0,1,0,1,0,1,0,0,0,0};
static int table40[10] = {0,1,0,1,0,1,0,1,0,0};
static int table50[10] = {0,1,0,1,0,1,0,1,0,1};
static int table60[10] = {0,1,0,1,1,1,0,1,0,1};
static int table70[10] = {0,1,0,1,1,1,0,1,1,1};
static int table80[10] = {0,1,1,1,1,1,0,1,1,1};
static int table90[10] = {0,1,1,1,1,1,1,1,1,1};
float percent = m_engine->GetGadgetQuantity();
if (percent == 0.0f) return false;
if (percent == 1.0f) return true;
int *table;
if (percent <= 0.15f) table = table10;
else if (percent <= 0.25f) table = table20;
else if (percent <= 0.35f) table = table30;
else if (percent <= 0.45f) table = table40;
else if (percent <= 0.55f) table = table50;
else if (percent <= 0.65f) table = table60;
else if (percent <= 0.75f) table = table70;
else if (percent <= 0.85f) table = table80;
else table = table90;
return table[rank%10];
}
//! Calculates the distance to the nearest object
float CRobotMain::SearchNearestObject(Math::Vector center, CObject *exclu)
{
CInstanceManager* iMan = CInstanceManager::GetInstancePointer();
float min = 100000.0f;
for (int i = 0; i < 1000000; i++)
{
CObject* obj = static_cast<CObject*>(iMan->SearchInstance(CLASS_OBJECT, i));
if (obj == nullptr) break;
if (!obj->GetActif()) continue; // inactive?
if (obj->GetTruck() != nullptr) continue; // object carries?
if (obj == exclu) continue;
ObjectType type = obj->GetType();
if (type == OBJECT_BASE)
{
Math::Vector oPos = obj->GetPosition(0);
if (oPos.x != center.x ||
oPos.z != center.z)
{
float dist = Math::Distance(center, oPos)-80.0f;
if (dist < 0.0f) dist = 0.0f;
min = Math::Min(min, dist);
continue;
}
}
if (type == OBJECT_STATION ||
type == OBJECT_REPAIR ||
type == OBJECT_DESTROYER)
{
Math::Vector oPos = obj->GetPosition(0);
float dist = Math::Distance(center, oPos)-8.0f;
if (dist < 0.0f) dist = 0.0f;
min = Math::Min(min, dist);
}
int j = 0;
Math::Vector oPos;
float oRadius;
while (obj->GetCrashSphere(j++, oPos, oRadius))
{
float dist = Math::Distance(center, oPos)-oRadius;
if (dist < 0.0f) dist = 0.0f;
min = Math::Min(min, dist);
}
}
return min;
}
//! Calculates a free space
bool CRobotMain::FreeSpace(Math::Vector &center, float minRadius, float maxRadius,
float space, CObject *exclu)
{
if (minRadius < maxRadius) // from internal to external?
{
for (float radius = minRadius; radius <= maxRadius; radius += space)
{
float ia = space/radius;
for (float angle = 0.0f; angle < Math::PI*2.0f; angle += ia)
{
Math::Point p;
p.x = center.x+radius;
p.y = center.z;
p = Math::RotatePoint(Math::Point(center.x, center.z), angle, p);
Math::Vector pos;
pos.x = p.x;
pos.z = p.y;
pos.y = 0.0f;
m_terrain->AdjustToFloor(pos, true);
float dist = SearchNearestObject(pos, exclu);
if (dist >= space)
{
float flat = m_terrain->GetFlatZoneRadius(pos, dist/2.0f);
if (flat >= dist/2.0f)
{
center = pos;
return true;
}
}
}
}
}
else // from external to internal?
{
for (float radius=maxRadius; radius >= minRadius; radius -= space)
{
float ia = space/radius;
for (float angle=0.0f ; angle<Math::PI*2.0f ; angle+=ia )
{
Math::Point p;
p.x = center.x+radius;
p.y = center.z;
p = Math::RotatePoint(Math::Point(center.x, center.z), angle, p);
Math::Vector pos;
pos.x = p.x;
pos.z = p.y;
pos.y = 0.0f;
m_terrain->AdjustToFloor(pos, true);
float dist = SearchNearestObject(pos, exclu);
if (dist >= space)
{
float flat = m_terrain->GetFlatZoneRadius(pos, dist/2.0f);
if (flat >= dist/2.0f)
{
center = pos;
return true;
}
}
}
}
}
return false;
}
//! Calculates the maximum radius of a free space
float CRobotMain::GetFlatZoneRadius(Math::Vector center, float maxRadius,
CObject *exclu)
{
float dist = SearchNearestObject(center, exclu);
if (dist == 0.0f) return 0.0f;
if (dist < maxRadius)
maxRadius = dist;
return m_terrain->GetFlatZoneRadius(center, maxRadius);
}
//! Hides buildable area when a cube of metal is taken up
void CRobotMain::HideDropZone(CObject* metal)
{
if (m_showLimit[1].used &&
m_showLimit[1].link == metal)
{
FlushShowLimit(1);
}
if (m_showLimit[2].used &&
m_showLimit[2].link == metal)
{
FlushShowLimit(2);
}
}
//! Shows the buildable area when a cube of metal is deposited
void CRobotMain::ShowDropZone(CObject* metal, CObject* truck)
{
if (metal == nullptr) return;
Math::Vector center = metal->GetPosition(0);
CInstanceManager* iMan = CInstanceManager::GetInstancePointer();
// Calculates the maximum radius possible depending on other items.
float oMax = 30.0f; // radius to build the biggest building
float tMax;
for (int i = 0; i < 1000000; i++)
{
CObject* obj = static_cast<CObject*>(iMan->SearchInstance(CLASS_OBJECT, i));
if (obj == nullptr) break;
if (!obj->GetActif()) continue; // inactive?
if (obj->GetTruck() != nullptr) continue; // object carried?
if (obj == metal) continue;
if (obj == truck) continue;
Math::Vector oPos;
float oRadius;
ObjectType type = obj->GetType();
if (type == OBJECT_BASE)
{
oPos = obj->GetPosition(0);
float dist = Math::Distance(center, oPos)-80.0f;
oMax = Math::Min(oMax, dist);
}
else
{
int j = 0;
while (obj->GetCrashSphere(j++, oPos, oRadius))
{
float dist = Math::Distance(center, oPos)-oRadius;
oMax = Math::Min(oMax, dist);
}
}
if ( type == OBJECT_DERRICK ||
type == OBJECT_FACTORY ||
type == OBJECT_STATION ||
type == OBJECT_CONVERT ||
type == OBJECT_REPAIR ||
type == OBJECT_DESTROYER||
type == OBJECT_TOWER ||
type == OBJECT_RESEARCH ||
type == OBJECT_RADAR ||
type == OBJECT_ENERGY ||
type == OBJECT_LABO ||
type == OBJECT_NUCLEAR ||
type == OBJECT_START ||
type == OBJECT_END ||
type == OBJECT_INFO ||
type == OBJECT_PARA ||
type == OBJECT_SAFE ||
type == OBJECT_HUSTON ) // building?
{
int j = 0;
while (obj->GetCrashSphere(j++, oPos, oRadius))
{
float dist = Math::Distance(center, oPos)-oRadius-BUILDMARGIN;
oMax = Math::Min(oMax, dist);
}
}
}
// Calculates the maximum possible radius depending on terrain.
if (oMax >= 2.0f)
tMax = m_terrain->GetFlatZoneRadius(center, 30.0f);
else
tMax = 0.0f;
float radius = Math::Min(oMax, tMax);
if (radius >= 2.0f)
SetShowLimit(1, Gfx::PARTILIMIT2, metal, center, radius, 10.0f);
}
//! Erases the boundaries shown
void CRobotMain::FlushShowLimit(int i)
{
if (m_showLimit[i].link != 0)
{
m_showLimit[i].link->StopShowLimit();
}
for (int j = 0; j < m_showLimit[i].total; j++)
{
if (m_showLimit[i].parti[j] == 0) continue;
m_particle->DeleteParticle(m_showLimit[i].parti[j]);
m_showLimit[i].parti[j] = 0;
}
m_showLimit[i].total = 0;
m_showLimit[i].link = 0;
m_showLimit[i].used = false;
}
//! Specifies the boundaries to show
void CRobotMain::SetShowLimit(int i, Gfx::ParticleType parti, CObject *obj,
Math::Vector pos, float radius, float duration)
{
FlushShowLimit(i); // erases the current boundaries
if (radius <= 0.0f) return;
Math::Point dim;
float dist;
if (radius <= 50.0f)
{
dim = Math::Point(0.3f, 0.3f);
dist = 2.5f;
}
else
{
dim = Math::Point(1.5f, 1.5f);
dist = 10.0f;
}
m_showLimit[i].used = true;
m_showLimit[i].link = obj;
m_showLimit[i].pos = pos;
m_showLimit[i].radius = radius;
m_showLimit[i].duration = duration;
m_showLimit[i].total = static_cast<int>((radius*2.0f*Math::PI)/dist);
if (m_showLimit[i].total > MAXSHOWPARTI) m_showLimit[i].total = MAXSHOWPARTI;
m_showLimit[i].time = 0.0f;
for (int j = 0; j < m_showLimit[i].total; j++)
{
m_showLimit[i].parti[j] = m_particle->CreateParticle(pos, Math::Vector(0.0f, 0.0f, 0.0f), dim, parti, duration);
}
}
//! Adjusts the boundaries to show
void CRobotMain::AdjustShowLimit(int i, Math::Vector pos)
{
m_showLimit[i].pos = pos;
}
//! Mount the boundaries of the selected object
void CRobotMain::StartShowLimit()
{
CObject* obj = GetSelect();
if (obj == nullptr) return;
obj->StartShowLimit();
}
//! Advances the boundaries shown
void CRobotMain::FrameShowLimit(float rTime)
{
if (m_engine->GetPause()) return;
for (int i = 0; i < MAXSHOWLIMIT; i++)
{
if (!m_showLimit[i].used) continue;
m_showLimit[i].time += rTime;
if (m_showLimit[i].time >= m_showLimit[i].duration)
{
FlushShowLimit(i);
continue;
}
float factor;
if (m_showLimit[i].time < 1.0f)
factor = m_showLimit[i].time;
else if (m_showLimit[i].time > m_showLimit[i].duration-1.0f)
factor = m_showLimit[i].duration-m_showLimit[i].time;
else
factor = 1.0f;
float speed = 0.4f-m_showLimit[i].radius*0.001f;
if (speed < 0.1f) speed = 0.1f;
float angle = m_showLimit[i].time*speed;
for (int j = 0; j < m_showLimit[i].total; j++)
{
if (m_showLimit[i].parti[j] == 0) continue;
Math::Point center;
center.x = m_showLimit[i].pos.x;
center.y = m_showLimit[i].pos.z;
Math::Point rotate;
rotate.x = center.x+m_showLimit[i].radius*factor;
rotate.y = center.y;
rotate = Math::RotatePoint(center, angle, rotate);
Math::Vector pos;
pos.x = rotate.x;
pos.z = rotate.y;
pos.y = 0.0f;
m_terrain->AdjustToFloor(pos, true);
if (m_showLimit[i].radius <= 50.0f) pos.y += 0.5f;
else pos.y += 2.0f;
m_particle->SetPosition(m_showLimit[i].parti[j], pos);
angle += (2.0f*Math::PI)/m_showLimit[i].total;
}
}
}
//! Compiles all scripts of robots
void CRobotMain::CompileScript(bool soluce)
{
int nbError = 0;
int lastError = 0;
CInstanceManager* iMan = CInstanceManager::GetInstancePointer();
do
{
lastError = nbError;
nbError = 0;
for (int i = 0; i < 1000000; i++)
{
CObject* obj = static_cast<CObject*>(iMan->SearchInstance(CLASS_OBJECT, i));
if (obj == nullptr) break;
if (obj->GetTruck() != nullptr) continue;
CBrain* brain = obj->GetBrain();
if (brain == nullptr) continue;
for (int j = 0; j < 10; j++)
{
if (brain->GetCompile(j)) continue;
std::string name = brain->GetScriptName(j);
if (name[0] != 0)
{
name = "ai/"+name;
if(! brain->ReadProgram(j, const_cast<char*>(name.c_str()))) {
CLogger::GetInstancePointer()->Error("Unable to read script from file \"%s\"\n", name.c_str());
}
if (!brain->GetCompile(j)) nbError++;
}
}
LoadOneScript(obj, nbError);
}
}
while (nbError > 0 && nbError != lastError);
// Load all solutions.
if (soluce)
{
for (int i = 0; i < 1000000; i++)
{
CObject* obj = static_cast<CObject*>(iMan->SearchInstance(CLASS_OBJECT, i));
if (obj == 0) break;
if (obj->GetTruck() != 0) continue;
CBrain* brain = obj->GetBrain();
if (brain == 0) continue;
char* name = brain->GetSoluceName();
if (name[0] != 0)
{
brain->ReadSoluce(name); // load solution
}
}
}
// Start all programs according to the command "run".
for (int i = 0; i < 1000000; i++)
{
CObject* obj = static_cast<CObject*>(iMan->SearchInstance(CLASS_OBJECT, i));
if (obj == nullptr) break;
if (obj->GetTruck() != nullptr) continue;
CBrain* brain = obj->GetBrain();
if (brain == nullptr) continue;
int run = brain->GetScriptRun();
if (run != -1)
{
brain->RunProgram(run); // starts the program
}
}
}
//! Load all programs of the robot
void CRobotMain::LoadOneScript(CObject *obj, int &nbError)
{
CBrain* brain = obj->GetBrain();
if (brain == nullptr) return;
if (!IsSelectable(obj)) return;
ObjectType type = obj->GetType();
if (type == OBJECT_HUMAN) return;
int objRank = obj->GetDefRank();
if (objRank == -1) return;
char* name = m_dialog->GetSceneName();
int rank = m_dialog->GetSceneRank();
for (int i = 0; i < BRAINMAXSCRIPT; i++)
{
if (brain->GetCompile(i)) continue;
char filename[MAX_FNAME];
sprintf(filename, "%s/%s/%c%.3d%.3d%.1d.txt",
GetSavegameDir(), m_gamerName.c_str(), name[0], rank, objRank, i);
brain->ReadProgram(i, filename);
if (!brain->GetCompile(i)) nbError++;
}
}
//! Load all programs of the robot
void CRobotMain::LoadFileScript(CObject *obj, const char* filename, int objRank,
int &nbError)
{
if (objRank == -1) return;
CBrain* brain = obj->GetBrain();
if (brain == nullptr) return;
ObjectType type = obj->GetType();
if (type == OBJECT_HUMAN) return;
std::string dirname = filename;
dirname = dirname.substr(0, dirname.find_last_of("/"));
char fn[MAX_FNAME]; //TODO: Refactor to std::string
for (int i = 0; i < BRAINMAXSCRIPT; i++)
{
sprintf(fn, "%s/prog%.3d%.1d.txt", dirname.c_str(), objRank, i);
brain->ReadProgram(i, fn);
if (!brain->GetCompile(i)) nbError++;
}
}
//! Saves all programs of all the robots
void CRobotMain::SaveAllScript()
{
CInstanceManager* iMan = CInstanceManager::GetInstancePointer();
for (int i = 0; i < 1000000; i++)
{
CObject* obj = static_cast<CObject*>(iMan->SearchInstance(CLASS_OBJECT, i));
if (obj == nullptr) break;
SaveOneScript(obj);
}
}
//! Saves all programs of the robot.
//! If a program does not exist, the corresponding file is destroyed.
void CRobotMain::SaveOneScript(CObject *obj)
{
CBrain* brain = obj->GetBrain();
if (brain == nullptr) return;
if (!IsSelectable(obj)) return;
ObjectType type = obj->GetType();
if (type == OBJECT_HUMAN) return;
int objRank = obj->GetDefRank();
if (objRank == -1) return;
char* name = m_dialog->GetSceneName();
int rank = m_dialog->GetSceneRank();
for (int i = 0; i < BRAINMAXSCRIPT; i++)
{
char filename[MAX_FNAME];
sprintf(filename, "%s/%s/%c%.3d%.3d%.1d.txt",
GetSavegameDir(), m_gamerName.c_str(), name[0], rank, objRank, i);
brain->WriteProgram(i, filename);
}
}
//! Saves all programs of the robot.
//! If a program does not exist, the corresponding file is destroyed.
void CRobotMain::SaveFileScript(CObject *obj, const char* filename, int objRank)
{
if (objRank == -1) return;
CBrain* brain = obj->GetBrain();
if (brain == nullptr) return;
ObjectType type = obj->GetType();
if (type == OBJECT_HUMAN) return;
std::string dirname = filename;
dirname = dirname.substr(0, dirname.find_last_of("/"));
char fn[MAX_FNAME]; //TODO: Refactor to std::string
for (int i = 0; i < BRAINMAXSCRIPT; i++)
{
sprintf(fn, "%s/prog%.3d%.1d.txt", dirname.c_str(), objRank, i);
brain->WriteProgram(i, fn);
}
}
//! Saves the stack of the program in execution of a robot
bool CRobotMain::SaveFileStack(CObject *obj, FILE *file, int objRank)
{
if (objRank == -1) return true;
CBrain* brain = obj->GetBrain();
if (brain == nullptr) return true;
ObjectType type = obj->GetType();
if (type == OBJECT_HUMAN) return true;
return brain->WriteStack(file);
}
//! Resumes the execution stack of the program in a robot
bool CRobotMain::ReadFileStack(CObject *obj, FILE *file, int objRank)
{
if (objRank == -1) return true;
CBrain* brain = obj->GetBrain();
if (brain == nullptr) return true;
ObjectType type = obj->GetType();
if (type == OBJECT_HUMAN) return true;
return brain->ReadStack(file);
}
//! Empty the list
bool CRobotMain::FlushNewScriptName()
{
for (int i = 0; i < MAXNEWSCRIPTNAME; i++)
m_newScriptName[i].used = false;
return true;
}
//! Adds a script name
bool CRobotMain::AddNewScriptName(ObjectType type, char *name)
{
for (int i = 0; i < MAXNEWSCRIPTNAME; i++)
{
if (!m_newScriptName[i].used)
{
m_newScriptName[i].used = true;
m_newScriptName[i].type = type;
strcpy(m_newScriptName[i].name, name);
return true;
}
}
return false;
}
//! Seeks a script name for a given type
char* CRobotMain::GetNewScriptName(ObjectType type, int rank)
{
for (int i = 0; i < MAXNEWSCRIPTNAME; i++)
{
if (m_newScriptName[i].used &&
(m_newScriptName[i].type == type ||
m_newScriptName[i].type == OBJECT_NULL))
{
if (rank == 0) return m_newScriptName[i].name;
else rank --;
}
}
return 0;
}
//! Seeks if an object occupies in a spot, to prevent a backup of the game
bool CRobotMain::IsBusy()
{
if (m_CompteurFileOpen > 0) return true;
CInstanceManager* iMan = CInstanceManager::GetInstancePointer();
for (int i = 0; i < 1000000; i++)
{
CObject* obj = static_cast<CObject*>(iMan->SearchInstance(CLASS_OBJECT, i));
if (obj == nullptr) break;
CBrain* brain = obj->GetBrain();
if (brain != nullptr)
{
if (brain->IsBusy()) return true;
}
}
return false;
}
//! Writes an object into the backup file
void CRobotMain::IOWriteObject(CLevelParserLine* line, CObject* obj)
{
if (obj->GetType() == OBJECT_FIX) return;
line->AddParam("type", new CLevelParserParam(obj->GetType()));
line->AddParam("id", new CLevelParserParam(obj->GetID()));
line->AddParam("pos", new CLevelParserParam(obj->GetPosition(0)/g_unit));
line->AddParam("angle", new CLevelParserParam(obj->GetAngle(0)/(Math::PI/180.0f)));
line->AddParam("zoom", new CLevelParserParam(obj->GetZoom(0)));
Math::Vector pos;
for (int i = 1; i < OBJECTMAXPART; i++)
{
if (obj->GetObjectRank(i) == -1) continue;
pos = obj->GetPosition(i);
if (pos.x != 0.0f || pos.y != 0.0f || pos.z != 0.0f)
{
pos /= g_unit;
line->AddParam("p"+boost::lexical_cast<std::string>(i), new CLevelParserParam(pos));
}
pos = obj->GetAngle(i);
if (pos.x != 0.0f || pos.y != 0.0f || pos.z != 0.0f)
{
pos /= (Math::PI/180.0f);
line->AddParam("a"+boost::lexical_cast<std::string>(i), new CLevelParserParam(pos));
}
pos = obj->GetZoom(i);
if (pos.x != 1.0f || pos.y != 1.0f || pos.z != 1.0f)
{
line->AddParam("z"+boost::lexical_cast<std::string>(i), new CLevelParserParam(pos));
}
}
line->AddParam("trainer", new CLevelParserParam(obj->GetTrainer()));
line->AddParam("ignoreBuildCheck", new CLevelParserParam(obj->GetIgnoreBuildCheck()));
line->AddParam("option", new CLevelParserParam(obj->GetOption()));
if (obj == m_infoObject)
line->AddParam("select", new CLevelParserParam(1));
obj->Write(line);
if(obj->GetType() == OBJECT_BASE)
line->AddParam("run", new CLevelParserParam(3)); // stops and open (PARAM_FIXSCENE)
CBrain* brain = obj->GetBrain();
if (brain != nullptr)
{
int run = brain->GetProgram();
if (run != -1)
{
line->AddParam("run", new CLevelParserParam(run+1));
}
}
}
//! Saves the current game
bool CRobotMain::IOWriteScene(const char *filename, const char *filecbot, char *info)
{
CLevelParser* level = new CLevelParser(filename);
CLevelParserLine* line;
line = new CLevelParserLine("Title");
line->AddParam("text", new CLevelParserParam(std::string(info)));
level->AddLine(line);
//TODO: Do we need that? It's not used anyway
line = new CLevelParserLine("Version");
line->AddParam("maj", new CLevelParserParam(0));
line->AddParam("min", new CLevelParserParam(1));
level->AddLine(line);
line = new CLevelParserLine("Created");
line->AddParam("date", new CLevelParserParam(GetCurrentTimestamp()));
level->AddLine(line);
char* name = m_dialog->GetSceneName();
line = new CLevelParserLine("Mission");
line->AddParam("base", new CLevelParserParam(std::string(name)));
line->AddParam("rank", new CLevelParserParam(m_dialog->GetSceneRank()));
if (std::string(name) == "custom")
{
line->AddParam("dir", new CLevelParserParam(std::string(m_dialog->GetSceneDir())));
}
level->AddLine(line);
line = new CLevelParserLine("Map");
line->AddParam("zoom", new CLevelParserParam(m_map->GetZoomMap()));
level->AddLine(line);
line = new CLevelParserLine("DoneResearch");
line->AddParam("bits", new CLevelParserParam(static_cast<int>(g_researchDone)));
level->AddLine(line);
float sleep, delay, magnetic, progress;
if (m_lightning->GetStatus(sleep, delay, magnetic, progress))
{
line = new CLevelParserLine("BlitzMode");
line->AddParam("sleep", new CLevelParserParam(sleep));
line->AddParam("delay", new CLevelParserParam(delay));
line->AddParam("magnetic", new CLevelParserParam(magnetic/g_unit));
line->AddParam("progress", new CLevelParserParam(progress));
level->AddLine(line);
}
CInstanceManager* iMan = CInstanceManager::GetInstancePointer();
int objRank = 0;
for (int i = 0; i < 1000000; i++)
{
CObject* obj = static_cast<CObject*>(iMan->SearchInstance(CLASS_OBJECT, i));
if (obj == nullptr) break;
if (obj->GetType() == OBJECT_TOTO) continue;
if (obj->GetType() == OBJECT_FIX) continue;
if (obj->GetTruck() != nullptr) continue;
if (obj->GetBurn()) continue;
if (obj->GetDead()) continue;
if (obj->GetExplo()) continue;
CObject* power = obj->GetPower();
CObject* fret = obj->GetFret();
if (fret != nullptr){ // object transported?
line = new CLevelParserLine("CreateFret");
IOWriteObject(line, fret);
level->AddLine(line);
}
if (power != nullptr) { // battery transported?
line = new CLevelParserLine("CreatePower");
IOWriteObject(line, power);
level->AddLine(line);
}
line = new CLevelParserLine("CreateObject");
IOWriteObject(line, obj);
level->AddLine(line);
SaveFileScript(obj, filename, objRank++);
}
try {
level->Save();
} catch(CLevelParserException& e) {
CLogger::GetInstancePointer()->Error("Failed to save level state - %s\n", e.what());
delete level;
return false;
}
delete level;
// Writes the file of stacks of execution.
FILE* file = fOpen(filecbot, "wb");
if (file == NULL) return false;
long version = 1;
fWrite(&version, sizeof(long), 1, file); // version of COLOBOT
version = CBotProgram::GetVersion();
fWrite(&version, sizeof(long), 1, file); // version of CBOT
objRank = 0;
for (int i = 0; i < 1000000; i++)
{
CObject* obj = static_cast<CObject*>(iMan->SearchInstance(CLASS_OBJECT, i));
if (obj == nullptr) break;
if (obj->GetType() == OBJECT_TOTO) continue;
if (obj->GetType() == OBJECT_FIX) continue;
if (obj->GetTruck() != nullptr) continue;
if (obj->GetBurn()) continue;
if (obj->GetDead()) continue;
if (!SaveFileStack(obj, file, objRank++)) break;
}
CBotClass::SaveStaticState(file);
fClose(file);
m_delayWriteMessage = 4; // displays message in 3 frames
return true;
}
//! Resumes the game
CObject* CRobotMain::IOReadObject(CLevelParserLine *line, const char* filename, int objRank)
{
Math::Vector pos = line->GetParam("pos")->AsPoint()*g_unit;
Math::Vector dir = line->GetParam("angle")->AsPoint()*(Math::PI/180.0f);
Math::Vector zoom = line->GetParam("zoom")->AsPoint();
ObjectType type = line->GetParam("type")->AsObjectType();
int id = line->GetParam("id")->AsInt();
bool trainer = line->GetParam("trainer")->AsBool(false);
bool toy = line->GetParam("toy")->AsBool(false);
int option = line->GetParam("option")->AsInt(0);
CObject* obj = CObjectManager::GetInstancePointer()->CreateObject(pos, dir.y, type, 0.0f, 1.0f, 0.0f, trainer, toy, option);
obj->SetDefRank(objRank);
obj->SetPosition(0, pos);
obj->SetAngle(0, dir);
obj->SetIgnoreBuildCheck(line->GetParam("ignoreBuildCheck")->AsBool(false));
obj->SetID(id);
if (g_id < id) g_id = id;
if (zoom.x != 0.0f || zoom.y != 0.0f || zoom.z != 0.0f)
obj->SetZoom(0, zoom);
for (int i = 1; i < OBJECTMAXPART; i++)
{
if (obj->GetObjectRank(i) == -1) continue;
pos = line->GetParam(std::string("p")+boost::lexical_cast<std::string>(i))->AsPoint(Math::Vector());
if (pos.x != 0.0f || pos.y != 0.0f || pos.z != 0.0f)
{
obj->SetPosition(i, pos*g_unit);
}
dir = line->GetParam(std::string("a")+boost::lexical_cast<std::string>(i))->AsPoint(Math::Vector());
if (dir.x != 0.0f || dir.y != 0.0f || dir.z != 0.0f)
{
obj->SetAngle(i, dir*(Math::PI/180.0f));
}
zoom = line->GetParam(std::string("z")+boost::lexical_cast<std::string>(i))->AsPoint(Math::Vector());
if (zoom.x != 0.0f || zoom.y != 0.0f || zoom.z != 0.0f)
{
obj->SetZoom(i, zoom);
}
}
if (type == OBJECT_BASE) m_base = obj;
obj->Read(line);
int run = line->GetParam("run")->AsInt(-1);
if (run != -1)
{
CAuto* automat = obj->GetAuto();
if (automat != nullptr)
automat->Start(run); // starts the film
}
return obj;
}
//! Resumes some part of the game
CObject* CRobotMain::IOReadScene(const char *filename, const char *filecbot)
{
CLevelParser* level = new CLevelParser(filename);
level->Load();
m_base = nullptr;
CObject* fret = nullptr;
CObject* power = nullptr;
CObject* sel = nullptr;
int objRank = 0;
for(auto& line : level->GetLines())
{
if (line->GetCommand() == "Map")
m_map->ZoomMap(line->GetParam("zoom")->AsFloat());
if (line->GetCommand() == "DoneResearch")
g_researchDone = line->GetParam("bits")->AsInt();
if (line->GetCommand() == "BlitzMode")
{
float sleep = line->GetParam("sleep")->AsFloat();
float delay = line->GetParam("delay")->AsFloat();
float magnetic = line->GetParam("magnetic")->AsFloat()*g_unit;
float progress = line->GetParam("progress")->AsFloat();
m_lightning->SetStatus(sleep, delay, magnetic, progress);
}
if (line->GetCommand() == "CreateFret")
fret = IOReadObject(line, filename, -1);
if (line->GetCommand() == "CreatePower")
power = IOReadObject(line, filename, -1);
if (line->GetCommand() == "CreateObject")
{
CObject* obj = IOReadObject(line, filename, objRank++);
if (line->GetParam("select")->AsBool(false))
sel = obj;
if (fret != nullptr)
{
obj->SetFret(fret);
CTaskManip* task = new CTaskManip(obj);
task->Start(TMO_AUTO, TMA_GRAB); // holds the object!
delete task;
}
if (power != nullptr)
{
obj->SetPower(power);
power->SetTruck(obj);
}
fret = nullptr;
power = nullptr;
}
}
delete level;
CInstanceManager* iMan = CInstanceManager::GetInstancePointer();
// Compiles scripts.
int nbError = 0;
int lastError = 0;
do
{
lastError = nbError;
nbError = 0;
for (int i = 0; i < 1000000; i++)
{
CObject* obj = static_cast<CObject*>(iMan->SearchInstance(CLASS_OBJECT, i));
if (obj == nullptr) break;
if (obj->GetTruck() != nullptr) continue;
objRank = obj->GetDefRank();
if (objRank == -1) continue;
LoadFileScript(obj, filename, objRank, nbError);
}
}
while (nbError > 0 && nbError != lastError);
// Reads the file of stacks of execution.
FILE* file = fOpen(filecbot, "rb");
if (file != NULL)
{
long version;
fRead(&version, sizeof(long), 1, file); // version of COLOBOT
if (version == 1)
{
fRead(&version, sizeof(long), 1, file); // version of CBOT
if (version == CBotProgram::GetVersion())
{
objRank = 0;
for (int i = 0; i < 1000000; i++)
{
CObject* obj = static_cast<CObject*>(iMan->SearchInstance(CLASS_OBJECT, i));
if (obj == nullptr) break;
if (obj->GetType() == OBJECT_TOTO) continue;
if (obj->GetType() == OBJECT_FIX) continue;
if (obj->GetTruck() != nullptr) continue;
if (obj->GetBurn()) continue;
if (obj->GetDead()) continue;
if (!ReadFileStack(obj, file, objRank++)) break;
}
}
}
CBotClass::RestoreStaticState(file);
fClose(file);
}
return sel;
}
//! Writes the global parameters for free play
void CRobotMain::WriteFreeParam()
{
m_freeResearch |= g_researchDone;
m_freeBuild |= g_build;
if (m_gamerName == "") return;
COutputStream file;
file.open(std::string(GetSavegameDir())+"/"+m_gamerName+"/research.gam");
if(!file.is_open())
{
CLogger::GetInstancePointer()->Error("Unable to write free game unlock state\n");
return;
}
file << "research=" << m_freeResearch << " build=" << m_freeBuild << "\n";
file.close();
}
//! Reads the global parameters for free play
void CRobotMain::ReadFreeParam()
{
m_freeResearch = 0;
m_freeBuild = 0;
if (m_gamerName == "") return;
if(!CResourceManager::Exists(std::string(GetSavegameDir())+"/"+m_gamerName+"/research.gam"))
return;
CInputStream file;
file.open(std::string(GetSavegameDir())+"/"+m_gamerName+"/research.gam");
if(!file.is_open())
{
CLogger::GetInstancePointer()->Error("Unable to read free game unlock state\n");
return;
}
std::string line;
std::getline(file, line);
sscanf(line.c_str(), "research=%d build=%d\n", &m_freeResearch, &m_freeBuild);
file.close();
}
//! Resets all objects to their original position
void CRobotMain::ResetObject()
{
// TODO: ?
#if 0
CObject* obj;
CObject* truck;
CAuto* objAuto;
CBrain* brain;
CPyro* pyro;
ResetCap cap;
Math::Vector pos, angle;
int i;
CInstanceManager* iMan = CInstanceManager::GetInstancePointer();
// Removes all pyrotechnic effects in progress.
while ( true )
{
pyro = static_cast<CPyro*>(iMan->SearchInstance(CLASS_PYRO, 0));
if ( pyro == 0 ) break;
pyro->DeleteObject();
delete pyro;
}
// Removes all bullets in progress.
m_particle->DeleteParticle(PARTIGUN1);
m_particle->DeleteParticle(PARTIGUN2);
m_particle->DeleteParticle(PARTIGUN3);
m_particle->DeleteParticle(PARTIGUN4);
for ( i=0 ; i<1000000 ; i++ )
{
obj = static_cast<CObject*>(iMan->SearchInstance(CLASS_OBJECT, i));
if ( obj == 0 ) break;
cap = obj->GetResetCap();
if ( cap == RESET_NONE ) continue;
if ( cap == RESET_DELETE )
{
truck = obj->GetTruck();
if ( truck != 0 )
{
truck->SetFret(0);
obj->SetTruck(0);
}
obj->DeleteObject();
delete obj;
i --;
continue;
}
objAuto = obj->GetAuto();
if ( objAuto != 0 )
{
objAuto->Abort();
}
if ( obj->GetEnable() ) // object still active?
{
brain = obj->GetBrain();
if ( brain != 0 )
{
pos = obj->GetResetPosition();
angle = obj->GetResetAngle();
if ( pos == obj->GetPosition(0) &&
angle == obj->GetAngle(0) ) continue;
brain->StartTaskReset(pos, angle);
continue;
}
}
obj->SetEnable(true); // active again
pos = obj->GetResetPosition();
angle = obj->GetResetAngle();
if ( pos == obj->GetPosition(0) &&
angle == obj->GetAngle(0) ) continue;
pyro = new CPyro();
pyro->Create(PT_RESET, obj);
brain = obj->GetBrain();
if ( brain != 0 )
{
brain->RunProgram(obj->GetResetRun());
}
}
#else
m_resetCreate = true;
#endif
}
//! Resets all objects to their original position
void CRobotMain::ResetCreate()
{
SaveAllScript();
// Removes all bullets in progress.
m_particle->DeleteParticle(Gfx::PARTIGUN1);
m_particle->DeleteParticle(Gfx::PARTIGUN2);
m_particle->DeleteParticle(Gfx::PARTIGUN3);
m_particle->DeleteParticle(Gfx::PARTIGUN4);
DeselectAll(); // removes the control buttons
DeleteAllObjects(); // removes all the current 3D Scene
m_particle->FlushParticle();
m_terrain->FlushBuildingLevel();
CInstanceManager* iMan = CInstanceManager::GetInstancePointer();
iMan->Flush(CLASS_OBJECT);
iMan->Flush(CLASS_PHYSICS);
iMan->Flush(CLASS_BRAIN);
iMan->Flush(CLASS_PYRO);
CObjectManager::GetInstancePointer()->Flush();
m_camera->SetType(Gfx::CAM_TYPE_DIALOG);
try {
CreateScene(m_dialog->GetSceneSoluce(), false, true);
if (!GetNiceReset()) return;
for (int i = 0; i < 1000000; i++)
{
CObject* obj = static_cast<CObject*>(iMan->SearchInstance(CLASS_OBJECT, i));
if (obj == nullptr) break;
ResetCap cap = obj->GetResetCap();
if (cap == RESET_NONE) continue;
Gfx::CPyro* pyro = new Gfx::CPyro();
pyro->Create(Gfx::PT_RESET, obj);
}
}
catch(const CLevelParserException& e)
{
CLogger::GetInstancePointer()->Error("An error occured while trying to reset scene\n");
CLogger::GetInstancePointer()->Error("%s\n", e.what());
ChangePhase(PHASE_TERM);
}
}
//! Updates the audiotracks
void CRobotMain::UpdateAudio(bool frame)
{
CInstanceManager* iMan = CInstanceManager::GetInstancePointer();
for (int t = 0; t < m_audioChangeTotal; t++)
{
if (m_audioChange[t].changed) continue;
Math::Vector bPos = m_audioChange[t].pos;
bPos.y = 0.0f;
Math::Vector oPos;
int nb = 0;
for (int i = 0; i < 1000000; i++)
{
CObject* obj = static_cast<CObject*>(iMan->SearchInstance(CLASS_OBJECT, i));
if (obj == nullptr) break;
// Do not use GetActif () because an invisible worm (underground)
// should be regarded as existing here!
if (obj->GetLock()) continue;
if (obj->GetRuin()) continue;
if (!obj->GetEnable()) continue;
ObjectType type = obj->GetType();
if (type == OBJECT_SCRAP2 ||
type == OBJECT_SCRAP3 ||
type == OBJECT_SCRAP4 ||
type == OBJECT_SCRAP5) // wastes?
{
type = OBJECT_SCRAP1;
}
ToolType tool = CObject::GetToolFromObject(type);
DriveType drive = CObject::GetDriveFromObject(type);
if (m_audioChange[t].tool != TOOL_OTHER) if(tool != m_audioChange[t].tool) continue;
if (m_audioChange[t].drive != DRIVE_OTHER) if(drive != m_audioChange[t].drive) continue;
if (m_audioChange[t].tool == TOOL_OTHER && m_audioChange[t].drive == DRIVE_OTHER) if (type != m_audioChange[t].type) continue;
float energyLevel = -1;
CObject* power = obj->GetPower();
if (power != nullptr)
{
energyLevel = power->GetEnergy();
if (power->GetType() == OBJECT_ATOMIC) energyLevel *= 100;
}
if (energyLevel < m_audioChange[t].powermin || energyLevel > m_audioChange[t].powermax)
continue;
if (obj->GetTruck() == 0)
oPos = obj->GetPosition(0);
else
oPos = obj->GetTruck()->GetPosition(0);
oPos.y = 0.0f;
if (Math::DistanceProjected(oPos, bPos) <= m_audioChange[t].dist)
nb ++;
}
if (nb >= m_audioChange[t].min &&
nb <= m_audioChange[t].max)
{
CLogger::GetInstancePointer()->Info("Changing music to \"%s\"\n", m_audioChange[t].music);
m_sound->PlayMusic(std::string(m_audioChange[t].music), m_audioChange[t].repeat);
m_audioChange[t].changed = true;
}
}
}
void CRobotMain::SetEndMission(Error result, float delay)
{
if (m_controller != nullptr)
{
m_endTakeWinDelay = delay;
m_endTakeLostDelay = delay;
m_missionResult = result;
}
}
//! Checks if the mission is over
Error CRobotMain::CheckEndMission(bool frame)
{
if (m_controller != nullptr)
{
if (m_missionResult == INFO_LOST) //mission lost?
{
m_displayText->DisplayError(INFO_LOST, Math::Vector(0.0f,0.0f,0.0f));
m_missionTimerEnabled = m_missionTimerStarted = false;
m_winDelay = 0.0f;
if (m_lostDelay == 0) m_lostDelay = m_endTakeLostDelay;
m_displayText->SetEnable(false);
if(m_exitAfterMission)
m_eventQueue->AddEvent(Event(EVENT_QUIT));
}
if (m_missionResult == INFO_LOSTq) //mission lost?
{
m_missionTimerEnabled = m_missionTimerStarted = false;
m_winDelay = 0.0f;
if (m_lostDelay == 0) m_lostDelay = 0.1f;
m_displayText->SetEnable(false);
if(m_exitAfterMission)
m_eventQueue->AddEvent(Event(EVENT_QUIT));
}
if (frame && m_base != nullptr && m_base->GetSelectable()) return ERR_MISSION_NOTERM;
if (m_missionResult == ERR_OK) { //mission win?
m_displayText->DisplayError(INFO_WIN, Math::Vector(0.0f,0.0f,0.0f));
if(m_missionTimerEnabled && m_missionTimerStarted) {
CLogger::GetInstancePointer()->Info("Mission time: %s\n", TimeFormat(m_missionTimer).c_str());
m_displayText->DisplayText(("Time: "+TimeFormat(m_missionTimer)).c_str(), Math::Vector(0.0f,0.0f,0.0f));
}
m_missionTimerEnabled = m_missionTimerStarted = false;
if (m_winDelay == 0) m_winDelay = m_endTakeWinDelay;
m_lostDelay = 0.0f;
m_displayText->SetEnable(false);
if(m_exitAfterMission)
m_eventQueue->AddEvent(Event(EVENT_QUIT));
}
if (m_missionResult == ERR_MISSION_NOTERM) m_displayText->SetEnable(true);
return m_missionResult;
}
CInstanceManager* iMan = CInstanceManager::GetInstancePointer();
for (int t = 0; t < m_endTakeTotal; t++)
{
if (m_endTake[t].message[0] != 0) continue;
Math::Vector bPos = m_endTake[t].pos;
bPos.y = 0.0f;
Math::Vector oPos;
int nb = 0;
for (int i = 0; i < 1000000; i++)
{
CObject* obj = static_cast<CObject*>(iMan->SearchInstance(CLASS_OBJECT, i));
if (obj == nullptr) break;
// Do not use GetActif () because an invisible worm (underground)
// should be regarded as existing here!
if (obj->GetLock()) continue;
if (obj->GetRuin()) continue;
if (!obj->GetEnable()) continue;
ObjectType type = obj->GetType();
if (type == OBJECT_SCRAP2 ||
type == OBJECT_SCRAP3 ||
type == OBJECT_SCRAP4 ||
type == OBJECT_SCRAP5) // wastes?
{
type = OBJECT_SCRAP1;
}
ToolType tool = CObject::GetToolFromObject(type);
DriveType drive = CObject::GetDriveFromObject(type);
if (m_endTake[t].tool != TOOL_OTHER) if(tool != m_endTake[t].tool) continue;
if (m_endTake[t].drive != DRIVE_OTHER) if(drive != m_endTake[t].drive) continue;
if (m_endTake[t].tool == TOOL_OTHER && m_endTake[t].drive == DRIVE_OTHER) if (type != m_endTake[t].type) continue;
float energyLevel = -1;
CObject* power = obj->GetPower();
if (power != nullptr)
{
energyLevel = power->GetEnergy();
if (power->GetType() == OBJECT_ATOMIC) energyLevel *= 100;
}
if (energyLevel < m_endTake[t].powermin || energyLevel > m_endTake[t].powermax) continue;
if (obj->GetTruck() == 0)
oPos = obj->GetPosition(0);
else
oPos = obj->GetTruck()->GetPosition(0);
oPos.y = 0.0f;
if (Math::DistanceProjected(oPos, bPos) <= m_endTake[t].dist)
nb ++;
}
if (nb <= m_endTake[t].lost)
{
if (m_endTake[t].type == OBJECT_HUMAN)
{
if (m_lostDelay == 0.0f)
{
m_lostDelay = 0.1f; // lost immediately
m_winDelay = 0.0f;
}
m_missionTimerEnabled = m_missionTimerStarted = false;
m_displayText->SetEnable(false);
if(m_exitAfterMission)
m_eventQueue->AddEvent(Event(EVENT_QUIT));
return INFO_LOSTq;
}
else
{
if (m_lostDelay == 0.0f)
{
m_displayText->DisplayError(INFO_LOST, Math::Vector(0.0f,0.0f,0.0f));
m_lostDelay = m_endTakeLostDelay; // lost in 6 seconds
m_winDelay = 0.0f;
}
m_missionTimerEnabled = m_missionTimerStarted = false;
m_displayText->SetEnable(false);
if(m_exitAfterMission)
m_eventQueue->AddEvent(Event(EVENT_QUIT));
return INFO_LOST;
}
}
if (nb < m_endTake[t].min ||
nb > m_endTake[t].max ||
m_endTakeNever )
{
m_displayText->SetEnable(true);
return ERR_MISSION_NOTERM;
}
if (m_endTake[t].immediat)
{
if (m_winDelay == 0.0f)
{
m_winDelay = m_endTakeWinDelay; // wins in x seconds
m_lostDelay = 0.0f;
}
m_missionTimerEnabled = m_missionTimerStarted = false;
m_displayText->SetEnable(false);
if(m_exitAfterMission)
m_eventQueue->AddEvent(Event(EVENT_QUIT));
return ERR_OK; // mission ended
}
}
if (m_endTakeResearch != 0)
{
if (m_endTakeResearch != (m_endTakeResearch&g_researchDone))
{
m_displayText->SetEnable(true);
return ERR_MISSION_NOTERM;
}
}
if (m_endTakeWinDelay == -1.0f)
{
m_winDelay = 1.0f; // wins in one second
m_lostDelay = 0.0f;
m_missionTimerEnabled = m_missionTimerStarted = false;
m_displayText->SetEnable(false);
if(m_exitAfterMission)
m_eventQueue->AddEvent(Event(EVENT_QUIT));
return ERR_OK; // mission ended
}
if (frame && m_base != nullptr && m_base->GetSelectable()) return ERR_MISSION_NOTERM;
if (m_winDelay == 0.0f)
{
m_displayText->DisplayError(INFO_WIN, Math::Vector(0.0f,0.0f,0.0f));
if(m_missionTimerEnabled && m_missionTimerStarted) {
CLogger::GetInstancePointer()->Info("Mission time: %s\n", TimeFormat(m_missionTimer).c_str());
m_displayText->DisplayText(("Time: "+TimeFormat(m_missionTimer)).c_str(), Math::Vector(0.0f,0.0f,0.0f));
}
m_missionTimerEnabled = m_missionTimerStarted = false;
m_winDelay = m_endTakeWinDelay; // wins in two seconds
m_lostDelay = 0.0f;
}
if(m_exitAfterMission)
m_eventQueue->AddEvent(Event(EVENT_QUIT));
m_displayText->SetEnable(false);
return ERR_OK; // mission ended
}
//! Checks if the mission is finished after displaying a message
void CRobotMain::CheckEndMessage(const char* message)
{
for (int t = 0; t < m_endTakeTotal; t++)
{
if (m_endTake[t].message[0] == 0) continue;
if (strcmp(m_endTake[t].message, message) == 0)
{
m_displayText->DisplayError(INFO_WIN, Math::Vector(0.0f,0.0f,0.0f));
m_winDelay = m_endTakeWinDelay; // wins in 2 seconds
m_lostDelay = 0.0f;
}
}
}
//! Returns the number of instructions required
int CRobotMain::GetObligatoryToken()
{
return m_obligatoryTotal;
}
//! Returns the name of a required instruction
char* CRobotMain::GetObligatoryToken(int i)
{
return m_obligatoryToken[i];
}
//! Checks if an instruction is part of the obligatory list
int CRobotMain::IsObligatoryToken(const char* token)
{
for (int i = 0; i < m_obligatoryTotal; i++)
{
if (strcmp(token, m_obligatoryToken[i]) == 0)
return i;
}
return -1;
}
//! Checks if an instruction is not part of the banned list
bool CRobotMain::IsProhibitedToken(const char* token)
{
for (int i = 0; i < m_prohibitedTotal; i++)
{
if (strcmp(token, m_prohibitedToken[i]) == 0)
return false;
}
return true;
}
//! Indicates whether it is possible to control a driving robot
bool CRobotMain::GetTrainerPilot()
{
return m_trainerPilot;
}
//! Indicates whether the scene is fixed, without interaction
bool CRobotMain::GetFixScene()
{
return m_fixScene;
}
char* CRobotMain::GetTitle()
{
return m_title;
}
char* CRobotMain::GetResume()
{
return m_resume;
}
char* CRobotMain::GetScriptName()
{
return m_scriptName;
}
char* CRobotMain::GetScriptFile()
{
return m_scriptFile;
}
bool CRobotMain::GetGlint()
{
return m_dialog->GetGlint();
}
bool CRobotMain::GetSoluce4()
{
return m_dialog->GetSoluce4();
}
bool CRobotMain::GetMovies()
{
return m_dialog->GetMovies();
}
bool CRobotMain::GetNiceReset()
{
return m_dialog->GetNiceReset();
}
bool CRobotMain::GetHimselfDamage()
{
return m_dialog->GetHimselfDamage();
}
bool CRobotMain::GetShowSoluce()
{
return m_showSoluce;
}
bool CRobotMain::GetSceneSoluce()
{
if (m_infoFilename[SATCOM_SOLUCE][0] == 0) return false;
return m_dialog->GetSceneSoluce();
}
bool CRobotMain::GetShowAll()
{
return m_showAll;
}
bool CRobotMain::GetRadar()
{
if (m_cheatRadar)
return true;
CInstanceManager* iMan = CInstanceManager::GetInstancePointer();
for (int i = 0; i < 1000000; i++)
{
CObject* obj = static_cast<CObject*>(iMan->SearchInstance(CLASS_OBJECT, i));
if (obj == nullptr) break;
ObjectType type = obj->GetType();
if (type == OBJECT_RADAR && !obj->GetLock())
return true;
}
return false;
}
const char* CRobotMain::GetSavegameDir()
{
return m_dialog->GetSavegameDir().c_str();
}
const char* CRobotMain::GetPublicDir()
{
return m_dialog->GetPublicDir().c_str();
}
const char* CRobotMain::GetFilesDir()
{
return m_dialog->GetFilesDir().c_str();
}
bool CRobotMain::GetRetroMode()
{
return m_retroStyle;
}
//! Change the player's name
void CRobotMain::SetGamerName(const char *name)
{
m_gamerName = std::string(name);
SetGlobalGamerName(m_gamerName);
ReadFreeParam();
}
//! Gets the player's name
char* CRobotMain::GetGamerName()
{
return const_cast<char*>(m_gamerName.c_str());
}
//! Returns the representation to use for the player
int CRobotMain::GetGamerFace()
{
return m_dialog->GetGamerFace();
}
//! Returns the representation to use for the player
int CRobotMain::GetGamerGlasses()
{
return m_dialog->GetGamerGlasses();
}
//! Returns the mode with just the head
bool CRobotMain::GetGamerOnlyHead()
{
return m_dialog->GetGamerOnlyHead();
}
//! Returns the angle of presentation
float CRobotMain::GetPersoAngle()
{
return m_dialog->GetPersoAngle();
}
char* CRobotMain::GetSceneName()
{
return m_dialog->GetSceneName();
}
int CRobotMain::GetSceneRank()
{
return m_dialog->GetSceneRank();
}
void CRobotMain::BuildSceneName(std::string &filename, char *base, int rank, bool sceneFile)
{
m_dialog->BuildSceneName(filename, base, rank, sceneFile);
}
//! Changes on the pause mode
void CRobotMain::ChangePause(PauseType pause)
{
if(pause != PAUSE_NONE)
m_pause->SetPause(pause);
else
m_pause->ClearPause();
m_sound->MuteAll(m_pause->GetPause());
CreateShortcuts();
if (m_pause->GetPause()) HiliteClear();
}
//! Changes game speed
void CRobotMain::SetSpeed(float speed)
{
m_app->SetSimulationSpeed(speed);
UpdateSpeedLabel();
}
float CRobotMain::GetSpeed()
{
return m_app->GetSimulationSpeed();
}
void CRobotMain::UpdateSpeedLabel()
{
Ui::CButton* pb = static_cast<Ui::CButton*>(m_interface->SearchControl(EVENT_SPEED));
float speed = m_app->GetSimulationSpeed();
if (pb != nullptr)
{
if (speed == 1.0f)
{
pb->ClearState(Ui::STATE_VISIBLE);
}
else
{
char text[10];
sprintf(text, "x%.1f", speed);
pb->SetName(text);
pb->SetState(Ui::STATE_VISIBLE);
}
}
}
//! Creates interface shortcuts to the units
bool CRobotMain::CreateShortcuts()
{
if (m_phase != PHASE_SIMUL) return false;
if (!m_shortCut) return false;
return m_short->CreateShortcuts();
}
//! Updates the map
void CRobotMain::UpdateMap()
{
m_map->UpdateMap();
}
//! Indicates whether the mini-map is visible
bool CRobotMain::GetShowMap()
{
return m_map->GetShowMap() && m_mapShow;
}
//! Management of the lock mode for movies
void CRobotMain::SetMovieLock(bool lock)
{
m_movieLock = lock;
m_engine->SetMovieLock(m_movieLock);
CreateShortcuts();
m_map->ShowMap(!m_movieLock && m_mapShow);
if (m_movieLock) HiliteClear();
if (m_movieLock)
m_app->SetMouseMode(MOUSE_NONE);
else
m_app->SetMouseMode(MOUSE_ENGINE);
}
bool CRobotMain::GetMovieLock()
{
return m_movieLock;
}
bool CRobotMain::GetInfoLock()
{
return m_displayInfo != nullptr; // info in progress?
}
//! Management of the blocking of the call of SatCom
void CRobotMain::SetSatComLock(bool lock)
{
m_satComLock = lock;
}
bool CRobotMain::GetSatComLock()
{
return m_satComLock;
}
//! Management of the lock mode for the edition
void CRobotMain::SetEditLock(bool lock, bool edit)
{
m_editLock = lock;
CreateShortcuts();
// Do not remove the card if it contains a still image.
if (!lock || !m_map->GetFixImage())
m_map->ShowMap(!m_editLock && m_mapShow);
m_displayText->HideText(lock);
m_app->ResetKeyStates();
if (m_editLock)
HiliteClear();
else
m_editFull = false;
}
bool CRobotMain::GetEditLock()
{
return m_editLock;
}
//! Management of the fullscreen mode during editing
void CRobotMain::SetEditFull(bool full)
{
m_editFull = full;
}
bool CRobotMain::GetEditFull()
{
return m_editFull;
}
bool CRobotMain::GetFreePhoto()
{
return m_freePhoto;
}
//! Indicates whether mouse is on an friend object, on which we should not shoot
void CRobotMain::SetFriendAim(bool friendAim)
{
m_friendAim = friendAim;
}
bool CRobotMain::GetFriendAim()
{
return m_friendAim;
}
//! Management of the precision of drawing the ground
void CRobotMain::SetTracePrecision(float factor)
{
m_engine->SetTracePrecision(factor);
}
float CRobotMain::GetTracePrecision()
{
return m_engine->GetTracePrecision();
}
//! Starts music with a mission
void CRobotMain::StartMusic()
{
CLogger::GetInstancePointer()->Debug("Starting music...\n");
if (m_audioTrack != "")
{
m_sound->PlayMusic(m_audioTrack, m_audioRepeat, 0.0f);
}
}
//! Starts pause music
void CRobotMain::StartPauseMusic(PauseType pause)
{
switch(pause) {
case PAUSE_EDITOR:
if(m_editorTrack != "")
m_sound->PlayPauseMusic(m_editorTrack, m_editorRepeat);
break;
case PAUSE_SATCOM:
if(m_satcomTrack != "")
m_sound->PlayPauseMusic(m_satcomTrack, m_satcomRepeat);
break;
default:
// Don't change music
break;
}
}
//! Removes hilite and tooltip
void CRobotMain::ClearInterface()
{
HiliteClear(); // removes setting evidence
m_tooltipName.clear(); // really removes the tooltip
}
void CRobotMain::DisplayError(Error err, CObject* pObj, float time)
{
m_displayText->DisplayError(err, pObj, time);
}
void CRobotMain::DisplayError(Error err, Math::Vector goal, float height, float dist, float time)
{
m_displayText->DisplayError(err, goal, height, dist, time);
}
std::string& CRobotMain::GetUserLevelName(int id)
{
return m_dialog->GetUserLevelName(id);
}
void CRobotMain::StartMissionTimer()
{
if(m_missionTimerEnabled && !m_missionTimerStarted) {
CLogger::GetInstancePointer()->Info("Starting mission timer...\n");
m_missionTimerStarted = true;
}
}
void CRobotMain::SetAutosave(bool enable)
{
m_autosave = enable;
m_autosaveLast = m_gameTime;
AutosaveRotate(false);
}
bool CRobotMain::GetAutosave()
{
return m_autosave;
}
void CRobotMain::SetAutosaveInterval(int interval)
{
m_autosaveInterval = interval;
m_autosaveLast = m_gameTime;
}
int CRobotMain::GetAutosaveInterval()
{
return m_autosaveInterval;
}
void CRobotMain::SetAutosaveSlots(int slots)
{
m_autosaveSlots = slots;
AutosaveRotate(false);
}
int CRobotMain::GetAutosaveSlots()
{
return m_autosaveSlots;
}
int CRobotMain::AutosaveRotate(bool freeOne)
{
CLogger::GetInstancePointer()->Debug("Rotate autosaves...\n");
// Find autosave dirs
auto saveDirs = CResourceManager::ListDirectories(std::string(GetSavegameDir()) + "/" + GetGamerName());
std::map<int, std::string> autosaveDirs;
for(auto& dir : saveDirs)
{
try
{
const std::string autosavePrefix = "autosave";
if(dir.substr(0, autosavePrefix.length()) == "autosave")
{
int id = boost::lexical_cast<int>(dir.substr(autosavePrefix.length()));
autosaveDirs[id] = std::string(GetSavegameDir()) + "/" + GetGamerName() + "/" + dir;
}
}
catch(...)
{
CLogger::GetInstancePointer()->Info("Bad autosave found: %s\n", dir.c_str());
// skip
}
}
if(autosaveDirs.size() == 0) return 1;
// Remove all but last m_autosaveSlots
std::map<int, std::string> autosavesToKeep;
int last_id = autosaveDirs.rbegin()->first;
int count = 0;
int to_keep = m_autosaveSlots-(freeOne ? 1 : 0);
int new_last_id = Math::Min(autosaveDirs.size(), to_keep);
bool rotate = false;
for(int i = last_id; i > 0; i--)
{
if(autosaveDirs.count(i) > 0)
{
count++;
if(count > m_autosaveSlots-(freeOne ? 1 : 0) || !m_autosave)
{
CLogger::GetInstancePointer()->Trace("Remove %s\n", autosaveDirs[i].c_str());
CResourceManager::RemoveDirectory(autosaveDirs[i]);
rotate = true;
}
else
{
CLogger::GetInstancePointer()->Trace("Keep %s\n", autosaveDirs[i].c_str());
autosavesToKeep[new_last_id-count+1] = autosaveDirs[i];
}
}
}
// Rename autosaves that we kept
if(rotate) {
for(auto& save : autosavesToKeep) {
std::string newDir = std::string(GetSavegameDir()) + "/" + GetGamerName() + "/autosave" + boost::lexical_cast<std::string>(save.first);
CLogger::GetInstancePointer()->Trace("Rename %s -> %s\n", save.second.c_str(), newDir.c_str());
CResourceManager::Move(save.second, newDir);
}
}
return rotate ? count : count+1;
}
void CRobotMain::Autosave()
{
int id = AutosaveRotate(true);
CLogger::GetInstancePointer()->Info("Autosave!\n");
std::string dir = std::string(GetSavegameDir()) + "/" + GetGamerName() + "/autosave" + boost::lexical_cast<std::string>(id);
if (!CResourceManager::DirectoryExists(dir))
{
CResourceManager::CreateDirectory(dir);
}
std::string savegameFileName = dir + "/data.sav";
std::string fileCBot = CResourceManager::GetSaveLocation() + "/" + dir + "/cbot.run";
char timestr[100];
TimeToAscii(time(NULL), timestr);
IOWriteScene(savegameFileName.c_str(), fileCBot.c_str(), const_cast<char*>((std::string("[AUTOSAVE] ")+timestr).c_str()));
m_dialog->MakeSaveScreenshot(dir + "/screen.png");
}