1 #include <i18n.h>
2 #include "gameGlobalInfo.h"
3 #include "preferenceManager.h"
4 #include "scienceDatabase.h"
5
6 P<GameGlobalInfo> gameGlobalInfo;
7
8 REGISTER_MULTIPLAYER_CLASS(GameGlobalInfo, "GameGlobalInfo")
GameGlobalInfo()9 GameGlobalInfo::GameGlobalInfo()
10 : MultiplayerObject("GameGlobalInfo")
11 {
12 assert(!gameGlobalInfo);
13
14 callsign_counter = 0;
15 victory_faction = -1;
16 gameGlobalInfo = this;
17
18 for(int n=0; n<max_player_ships; n++)
19 {
20 playerShipId[n] = -1;
21 registerMemberReplication(&playerShipId[n]);
22 }
23
24 global_message_timeout = 0.0;
25 player_warp_jump_drive_setting = PWJ_ShipDefault;
26 scanning_complexity = SC_Normal;
27 hacking_difficulty = 2;
28 hacking_games = HG_All;
29 use_beam_shield_frequencies = true;
30 use_system_damage = true;
31 allow_main_screen_tactical_radar = true;
32 allow_main_screen_long_range_radar = true;
33 gm_control_code = "";
34 elapsed_time = 0.0f;
35
36 intercept_all_comms_to_gm = false;
37
38 registerMemberReplication(&scanning_complexity);
39 registerMemberReplication(&hacking_difficulty);
40 registerMemberReplication(&hacking_games);
41 registerMemberReplication(&global_message);
42 registerMemberReplication(&global_message_timeout, 1.0);
43 registerMemberReplication(&banner_string);
44 registerMemberReplication(&victory_faction);
45 registerMemberReplication(&use_beam_shield_frequencies);
46 registerMemberReplication(&use_system_damage);
47 registerMemberReplication(&allow_main_screen_tactical_radar);
48 registerMemberReplication(&allow_main_screen_long_range_radar);
49 registerMemberReplication(&gm_control_code);
50 registerMemberReplication(&elapsed_time, 0.1);
51
52 for(unsigned int n=0; n<factionInfo.size(); n++)
53 reputation_points.push_back(0);
54 registerMemberReplication(&reputation_points, 1.0);
55 }
56
57 //due to a suspected compiler bug this deconstructor needs to be explicitly defined
~GameGlobalInfo()58 GameGlobalInfo::~GameGlobalInfo()
59 {
60 }
61
getPlayerShip(int index)62 P<PlayerSpaceship> GameGlobalInfo::getPlayerShip(int index)
63 {
64 assert(index >= 0 && index < max_player_ships);
65 if (game_server)
66 return game_server->getObjectById(playerShipId[index]);
67 return game_client->getObjectById(playerShipId[index]);
68 }
69
setPlayerShip(int index,P<PlayerSpaceship> ship)70 void GameGlobalInfo::setPlayerShip(int index, P<PlayerSpaceship> ship)
71 {
72 assert(index >= 0 && index < max_player_ships);
73 assert(game_server);
74
75 if (ship)
76 playerShipId[index] = ship->getMultiplayerId();
77 else
78 playerShipId[index] = -1;
79 }
80
findPlayerShip(P<PlayerSpaceship> ship)81 int GameGlobalInfo::findPlayerShip(P<PlayerSpaceship> ship)
82 {
83 for(int n=0; n<max_player_ships; n++)
84 if (getPlayerShip(n) == ship)
85 return n;
86 return -1;
87 }
88
insertPlayerShip(P<PlayerSpaceship> ship)89 int GameGlobalInfo::insertPlayerShip(P<PlayerSpaceship> ship)
90 {
91 for(int n=0; n<max_player_ships; n++)
92 {
93 if (!getPlayerShip(n))
94 {
95 setPlayerShip(n, ship);
96 return n;
97 }
98 }
99 return -1;
100 }
101
update(float delta)102 void GameGlobalInfo::update(float delta)
103 {
104 if (global_message_timeout > 0.0)
105 {
106 global_message_timeout -= delta;
107 }
108 if (my_player_info)
109 {
110 //Set the my_spaceship variable based on the my_player_info->ship_id
111 if ((my_spaceship && my_spaceship->getMultiplayerId() != my_player_info->ship_id) || (my_spaceship && my_player_info->ship_id == -1) || (!my_spaceship && my_player_info->ship_id != -1))
112 {
113 if (game_server)
114 my_spaceship = game_server->getObjectById(my_player_info->ship_id);
115 else
116 my_spaceship = game_client->getObjectById(my_player_info->ship_id);
117 }
118 }
119 elapsed_time += delta;
120 }
121
getNextShipCallsign()122 string GameGlobalInfo::getNextShipCallsign()
123 {
124 callsign_counter += 1;
125 switch(irandom(0, 9))
126 {
127 case 0: return "S" + string(callsign_counter);
128 case 1: return "NC" + string(callsign_counter);
129 case 2: return "CV" + string(callsign_counter);
130 case 3: return "SS" + string(callsign_counter);
131 case 4: return "VS" + string(callsign_counter);
132 case 5: return "BR" + string(callsign_counter);
133 case 6: return "CSS" + string(callsign_counter);
134 case 7: return "UTI" + string(callsign_counter);
135 case 8: return "VK" + string(callsign_counter);
136 case 9: return "CCN" + string(callsign_counter);
137 }
138 return "SS" + string(callsign_counter);
139 }
140
addScript(P<Script> script)141 void GameGlobalInfo::addScript(P<Script> script)
142 {
143 script_list.update();
144 script_list.push_back(script);
145 }
146
reset()147 void GameGlobalInfo::reset()
148 {
149 if (state_logger)
150 state_logger->destroy();
151
152 gm_callback_functions.clear();
153 gm_messages.clear();
154 on_gm_click = nullptr;
155
156 flushDatabaseData();
157
158 foreach(GameEntity, e, entityList)
159 e->destroy();
160 foreach(SpaceObject, o, space_object_list)
161 o->destroy();
162 if (engine->getObject("scenario"))
163 engine->getObject("scenario")->destroy();
164
165 foreach(Script, s, script_list)
166 {
167 s->destroy();
168 }
169 for(unsigned int n=0; n<reputation_points.size(); n++)
170 reputation_points[n] = 0;
171 elapsed_time = 0.0f;
172 callsign_counter = 0;
173 victory_faction = -1;
174 allow_new_player_ships = true;
175 }
176
startScenario(string filename)177 void GameGlobalInfo::startScenario(string filename)
178 {
179 reset();
180
181 i18n::reset();
182 i18n::load("locale/main." + PreferencesManager::get("language", "en") + ".po");
183 i18n::load("locale/" + filename.replace(".lua", "." + PreferencesManager::get("language", "en") + ".po"));
184
185 fillDefaultDatabaseData();
186
187 P<ScriptObject> scienceInfoScript = new ScriptObject("science_db.lua");
188 if (scienceInfoScript->getError() != "") exit(1);
189 scienceInfoScript->destroy();
190
191 P<ScriptObject> script = new ScriptObject();
192 script->run(filename);
193 engine->registerObject("scenario", script);
194
195 if (PreferencesManager::get("game_logs", "1").toInt())
196 {
197 state_logger = new GameStateLogger();
198 state_logger->start();
199 }
200 }
201
destroy()202 void GameGlobalInfo::destroy()
203 {
204 reset();
205 MultiplayerObject::destroy();
206 }
207
playerWarpJumpDriveToString(EPlayerWarpJumpDrive player_warp_jump_drive)208 string playerWarpJumpDriveToString(EPlayerWarpJumpDrive player_warp_jump_drive)
209 {
210 switch(player_warp_jump_drive)
211 {
212 case PWJ_ShipDefault:
213 return "Ship default";
214 case PWJ_WarpDrive:
215 return "Warp-drive";
216 case PWJ_JumpDrive:
217 return "Jump-drive";
218 case PWJ_WarpAndJumpDrive:
219 return "Both";
220 default:
221 return "?";
222 }
223 }
224
getSectorName(sf::Vector2f position)225 string getSectorName(sf::Vector2f position)
226 {
227 constexpr float sector_size = 20000;
228 int sector_x = floorf(position.x / sector_size) + 5;
229 int sector_y = floorf(position.y / sector_size) + 5;
230 string y;
231 string x;
232 if (sector_y >= 0)
233 y = string(char('A' + (sector_y)));
234 else
235 y = string(char('z' + sector_y / 26)) + string(char('z' + 1 + (sector_y % 26)));
236 if (sector_x >= 0)
237 x = string(sector_x);
238 else
239 x = string(100 + sector_x);
240 return y + x;
241 }
242
getSectorName(lua_State * L)243 int getSectorName(lua_State* L)
244 {
245 float x = luaL_checknumber(L, 1);
246 float y = luaL_checknumber(L, 2);
247 lua_pushstring(L, getSectorName(sf::Vector2f(x, y)).c_str());
248 return 1;
249 }
250 /// getSectorName(x, y)
251 /// Return the sector name for the point with coordinates (x, y). Compare SpaceObject:getSectorName().
252 REGISTER_SCRIPT_FUNCTION(getSectorName);
253
victory(lua_State * L)254 static int victory(lua_State* L)
255 {
256 gameGlobalInfo->setVictory(luaL_checkstring(L, 1));
257 if (engine->getObject("scenario"))
258 engine->getObject("scenario")->destroy();
259 engine->setGameSpeed(0.0);
260 return 0;
261 }
262 /// victory(string)
263 /// Called with a faction name as parameter, sets a certain faction as victor and ends the game.
264 /// (The GM can unpause the game, but the scenario with its update function is destroyed.)
265 REGISTER_SCRIPT_FUNCTION(victory);
266
globalMessage(lua_State * L)267 static int globalMessage(lua_State* L)
268 {
269 gameGlobalInfo->global_message = luaL_checkstring(L, 1);
270 gameGlobalInfo->global_message_timeout = 5.0;
271 return 0;
272 }
273 /// globalMessage(string)
274 /// Show a global message on the main screens of all active player ships.
275 /// The message is shown for 5 sec; new messages replace the old immediately.
276 REGISTER_SCRIPT_FUNCTION(globalMessage);
277
setBanner(lua_State * L)278 static int setBanner(lua_State* L)
279 {
280 gameGlobalInfo->banner_string = luaL_checkstring(L, 1);
281 return 0;
282 }
283 /// setBanner(string)
284 /// Show a scrolling banner containing this text on the cinematic and top down views.
285 REGISTER_SCRIPT_FUNCTION(setBanner);
286
getScenarioTime(lua_State * L)287 static int getScenarioTime(lua_State* L)
288 {
289 lua_pushnumber(L, gameGlobalInfo->elapsed_time);
290 return 1;
291 }
292 /// getScenarioTime()
293 /// Return the elapsed time of the scenario.
294 REGISTER_SCRIPT_FUNCTION(getScenarioTime);
295
getPlayerShip(lua_State * L)296 static int getPlayerShip(lua_State* L)
297 {
298 int index = luaL_checkinteger(L, 1);
299 if (index == -1)
300 {
301 for(index = 0; index<GameGlobalInfo::max_player_ships; index++)
302 {
303 P<PlayerSpaceship> ship = gameGlobalInfo->getPlayerShip(index);
304 if (ship)
305 return convert<P<PlayerSpaceship> >::returnType(L, ship);
306 }
307 return 0;
308 }
309 if (index < 1 || index > GameGlobalInfo::max_player_ships)
310 return 0;
311 P<PlayerSpaceship> ship = gameGlobalInfo->getPlayerShip(index - 1);
312 if (!ship)
313 return 0;
314 return convert<P<PlayerSpaceship> >::returnType(L, ship);
315 }
316 /// getPlayerShip(index)
317 /// Return the player's ship, use -1 to get the first active player ship.
318 REGISTER_SCRIPT_FUNCTION(getPlayerShip);
319
getActivePlayerShips(lua_State * L)320 static int getActivePlayerShips(lua_State* L)
321 {
322 PVector<PlayerSpaceship> ships;
323 ships.reserve(GameGlobalInfo::max_player_ships);
324 for (auto index = 0; index < GameGlobalInfo::max_player_ships; ++index)
325 {
326 auto ship = gameGlobalInfo->getPlayerShip(index);
327
328 if (ship)
329 {
330 ships.emplace_back(std::move(ship));
331 }
332 }
333
334 return convert<PVector<PlayerSpaceship>>::returnType(L, ships);
335 }
336 /// getActivePlayerShips()
337 /// Return a list of active player ships.
338 REGISTER_SCRIPT_FUNCTION(getActivePlayerShips);
339
getObjectsInRadius(lua_State * L)340 static int getObjectsInRadius(lua_State* L)
341 {
342 float x = luaL_checknumber(L, 1);
343 float y = luaL_checknumber(L, 2);
344 float r = luaL_checknumber(L, 3);
345
346 sf::Vector2f position(x, y);
347
348 PVector<SpaceObject> objects;
349 PVector<Collisionable> objectList = CollisionManager::queryArea(position - sf::Vector2f(r, r), position + sf::Vector2f(r, r));
350 foreach(Collisionable, obj, objectList)
351 {
352 P<SpaceObject> sobj = obj;
353 if (sobj && (sobj->getPosition() - position) < r)
354 objects.push_back(sobj);
355 }
356
357 return convert<PVector<SpaceObject> >::returnType(L, objects);
358 }
359 /// getObjectsInRadius(x, y, radius)
360 /// Return a list of all space objects at the x,y location within a certain radius.
361 REGISTER_SCRIPT_FUNCTION(getObjectsInRadius);
362
getAllObjects(lua_State * L)363 static int getAllObjects(lua_State* L)
364 {
365 return convert<PVector<SpaceObject> >::returnType(L, space_object_list);
366 }
367 /// getAllObjects()
368 /// Return a list of all space objects. (Use with care, this could return a very long list which could slow down the game when called every update)
369 REGISTER_SCRIPT_FUNCTION(getAllObjects);
370
getScenarioVariation(lua_State * L)371 static int getScenarioVariation(lua_State* L)
372 {
373 lua_pushstring(L, gameGlobalInfo->variation.c_str());
374 return 1;
375 }
376 /// getScenarioVariation()
377 /// Returns the currently used scenario variation.
378 REGISTER_SCRIPT_FUNCTION(getScenarioVariation);
379
getGameLanguage(lua_State * L)380 static int getGameLanguage(lua_State* L)
381 {
382 lua_pushstring(L, PreferencesManager::get("language", "en").c_str());
383 return 1;
384 }
385 /// getGameLanguage()
386 /// Returns the language as the string set in game preferences under language key
387 REGISTER_SCRIPT_FUNCTION(getGameLanguage);
388
389 /** Short lived object to do a scenario change on the update loop. See "setScenario" for details */
390 class ScenarioChanger : public Updatable
391 {
392 public:
ScenarioChanger(string script_name,string variation)393 ScenarioChanger(string script_name, string variation)
394 : script_name(script_name), variation(variation)
395 {
396 }
397
update(float delta)398 virtual void update(float delta)
399 {
400 gameGlobalInfo->variation = variation;
401 gameGlobalInfo->startScenario(script_name);
402 destroy();
403 }
404 private:
405 string script_name;
406 string variation;
407 };
408
setScenario(lua_State * L)409 static int setScenario(lua_State* L)
410 {
411 string script_name = luaL_checkstring(L, 1);
412 string variation = luaL_optstring(L, 2, "");
413 //This could be called from a currently active scenario script.
414 // Calling GameGlobalInfo::startScenario is unsafe at this point,
415 // as this will destroy the lua state that this function is running in.
416 //So use the ScenarioChanger object which will do the change in the update loop. Which is safe.
417 new ScenarioChanger(script_name, variation);
418 return 0;
419 }
420 /// setScenario(script_name, variation_name)
421 /// Change the current scenario to a different one.
422 REGISTER_SCRIPT_FUNCTION(setScenario);
423
shutdownGame(lua_State * L)424 static int shutdownGame(lua_State* L)
425 {
426 engine->shutdown();
427 return 0;
428 }
429 /// Shutdown the game.
430 /// Calling this function will close the game. Mainly usefull for a headless server setup.
431 REGISTER_SCRIPT_FUNCTION(shutdownGame);
432
pauseGame(lua_State * L)433 static int pauseGame(lua_State* L)
434 {
435 engine->setGameSpeed(0.0);
436 return 0;
437 }
438 /// Pause the game
439 /// Calling this function will pause the game. Mainly usefull for a headless server setup.
440 REGISTER_SCRIPT_FUNCTION(pauseGame);
441
unpauseGame(lua_State * L)442 static int unpauseGame(lua_State* L)
443 {
444 engine->setGameSpeed(1.0);
445 return 0;
446 }
447 /// Pause the game
448 /// Calling this function will pause the game. Mainly usefull for a headless server setup. As the scenario functions are not called when paused.
449 REGISTER_SCRIPT_FUNCTION(unpauseGame);
450
playSoundFile(lua_State * L)451 static int playSoundFile(lua_State* L)
452 {
453 soundManager->playSound(luaL_checkstring(L, 1));
454 return 0;
455 }
456 /// Play a sound file on the server. Will work with any file supported by SFML (.wav, .ogg, .flac)
457 /// Note that the sound is only played on the server. Not on any of the clients.
458 REGISTER_SCRIPT_FUNCTION(playSoundFile);
459
returnType(lua_State * L,EScanningComplexity complexity)460 template<> int convert<EScanningComplexity>::returnType(lua_State* L, EScanningComplexity complexity)
461 {
462 switch(complexity)
463 {
464 case SC_None:
465 lua_pushstring(L, "none");
466 return 1;
467 case SC_Simple:
468 lua_pushstring(L, "simple");
469 return 1;
470 case SC_Normal:
471 lua_pushstring(L, "normal");
472 return 1;
473 case SC_Advanced:
474 lua_pushstring(L, "advanced");
475 return 1;
476 default:
477 return 0;
478 }
479 }
480
getScanningComplexity(lua_State * L)481 static int getScanningComplexity(lua_State* L)
482 {
483 return convert<EScanningComplexity>::returnType(L, gameGlobalInfo->scanning_complexity);
484 }
485 /// Get the scanning complexity setting (returns an EScanningComplexity representation)
486 REGISTER_SCRIPT_FUNCTION(getScanningComplexity);
487
getHackingDifficulty(lua_State * L)488 static int getHackingDifficulty(lua_State* L)
489 {
490 lua_pushinteger(L, gameGlobalInfo->hacking_difficulty);
491 return 1;
492 }
493 /// Get the hacking difficulty setting (returns an integer between 0 and 3)
494 REGISTER_SCRIPT_FUNCTION(getHackingDifficulty);
495
returnType(lua_State * L,EHackingGames game)496 template<> int convert<EHackingGames>::returnType(lua_State* L, EHackingGames game)
497 {
498 switch(game)
499 {
500 case HG_Mine:
501 lua_pushstring(L, "mines");
502 return 1;
503 case HG_Lights:
504 lua_pushstring(L, "lights");
505 return 1;
506 case HG_All:
507 lua_pushstring(L, "all");
508 return 1;
509 default:
510 return 0;
511 }
512 }
513
getHackingGames(lua_State * L)514 static int getHackingGames(lua_State* L)
515 {
516 return convert<EHackingGames>::returnType(L, gameGlobalInfo->hacking_games);
517 }
518 /// Get the hacking games setting (returns an EHackingGames representation)
519 REGISTER_SCRIPT_FUNCTION(getHackingGames);
520
areBeamShieldFrequenciesUsed(lua_State * L)521 static int areBeamShieldFrequenciesUsed(lua_State* L)
522 {
523 lua_pushboolean(L, gameGlobalInfo->use_beam_shield_frequencies);
524 return 1;
525 }
526 /// returns if the "Beam/Shield Frequencies" setting is enabled
527 REGISTER_SCRIPT_FUNCTION(areBeamShieldFrequenciesUsed);
528
isPerSystemDamageUsed(lua_State * L)529 static int isPerSystemDamageUsed(lua_State* L)
530 {
531 lua_pushboolean(L, gameGlobalInfo->use_system_damage);
532 return 1;
533 }
534 /// returns if the "Per-System Damage" setting is enabled
535 REGISTER_SCRIPT_FUNCTION(isPerSystemDamageUsed);
536
isTacticalRadarAllowed(lua_State * L)537 static int isTacticalRadarAllowed(lua_State* L)
538 {
539 lua_pushboolean(L, gameGlobalInfo->allow_main_screen_tactical_radar);
540 return 1;
541 }
542 /// returns if the "Tactical Radar" setting is enabled
543 REGISTER_SCRIPT_FUNCTION(isTacticalRadarAllowed);
544
isLongRangeRadarAllowed(lua_State * L)545 static int isLongRangeRadarAllowed(lua_State* L)
546 {
547 lua_pushboolean(L, gameGlobalInfo->allow_main_screen_long_range_radar);
548 return 1;
549 }
550 /// returns if the "Long Range Radar" setting is enabled
551 REGISTER_SCRIPT_FUNCTION(isLongRangeRadarAllowed);
552
onNewPlayerShip(lua_State * L)553 static int onNewPlayerShip(lua_State* L)
554 {
555 int idx = 1;
556 convert<ScriptSimpleCallback>::param(L, idx, gameGlobalInfo->on_new_player_ship);
557 return 0;
558 }
559 /// Register a callback function that is called when a new ship is created on the ship selection screen.
560 REGISTER_SCRIPT_FUNCTION(onNewPlayerShip);
561
allowNewPlayerShips(lua_State * L)562 static int allowNewPlayerShips(lua_State* L)
563 {
564 gameGlobalInfo->allow_new_player_ships = lua_toboolean(L, 1);
565 return 0;
566 }
567 /// Set if the server is allowed to create new player ships from the ship creation screen.
568 /// allowNewPlayerShip(false) -- disallow new player ships to be created
569 REGISTER_SCRIPT_FUNCTION(allowNewPlayerShips);
570
getEEVersion(lua_State * L)571 static int getEEVersion(lua_State* L)
572 {
573 lua_pushinteger(L, VERSION_NUMBER);
574 return 1;
575 }
576 /// Get a string with the current version number, like "20191231"
577 REGISTER_SCRIPT_FUNCTION(getEEVersion);