1 /* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
2
3 #include "LuaUnsyncedCtrl.h"
4
5 #include "LuaInclude.h"
6 #include "LuaHandle.h"
7 #include "LuaHashString.h"
8 #include "LuaUtils.h"
9 #include "LuaTextures.h"
10
11 #include "ExternalAI/EngineOutHandler.h"
12 #include "ExternalAI/SkirmishAIHandler.h"
13 #include "Game/Camera.h"
14 #include "Game/CameraHandler.h"
15 #include "Game/Camera/CameraController.h"
16 #include "Game/Game.h"
17 #include "Game/GlobalUnsynced.h"
18 #include "Game/SelectedUnitsHandler.h"
19 #include "Game/Players/Player.h"
20 #include "Game/Players/PlayerHandler.h"
21 #include "Game/InMapDraw.h"
22 #include "Game/InMapDrawModel.h"
23 #include "Game/UI/CommandColors.h"
24 #include "Game/UI/CursorIcons.h"
25 #include "Game/UI/GuiHandler.h"
26 #include "Game/UI/InfoConsole.h"
27 #include "Game/UI/KeyCodes.h"
28 #include "Game/UI/KeySet.h"
29 #include "Game/UI/KeyBindings.h"
30 #include "Game/UI/MiniMap.h"
31 #include "Game/UI/MouseHandler.h"
32 #include "Map/MapInfo.h"
33 #include "Map/ReadMap.h"
34 #include "Map/BaseGroundDrawer.h"
35 #include "Map/BaseGroundTextures.h"
36 #include "Rendering/Env/ISky.h"
37 #include "Rendering/GL/myGL.h"
38 #include "Rendering/CommandDrawer.h"
39 #include "Rendering/IconHandler.h"
40 #include "Rendering/LineDrawer.h"
41 #include "Rendering/UnitDrawer.h"
42 #include "Rendering/Textures/Bitmap.h"
43 #include "Rendering/Textures/NamedTextures.h"
44 #include "Sim/Misc/TeamHandler.h"
45 #include "Sim/Projectiles/Projectile.h"
46 #include "Sim/Projectiles/ProjectileHandler.h"
47 #include "Sim/Units/Unit.h"
48 #include "Sim/Units/UnitDefHandler.h"
49 #include "Sim/Units/UnitHandler.h"
50 #include "Sim/Units/CommandAI/CommandAI.h"
51 #include "Sim/Units/Groups/Group.h"
52 #include "Sim/Units/Groups/GroupHandler.h"
53 #include "System/Config/ConfigHandler.h"
54 #include "System/EventHandler.h"
55 #include "System/GlobalConfig.h"
56 #include "System/Log/DefaultFilter.h"
57 #include "System/Log/ILog.h"
58 #include "Net/Protocol/NetProtocol.h"
59 #include "System/Net/PackPacket.h"
60 #include "System/Util.h"
61 #include "System/Sound/ISound.h"
62 #include "System/Sound/ISoundChannels.h"
63 #include "System/FileSystem/FileHandler.h"
64 #include "System/FileSystem/DataDirLocater.h"
65 #include "System/FileSystem/FileSystem.h"
66 #include "System/Platform/Watchdog.h"
67 #include "System/Platform/WindowManagerHelper.h"
68
69 #include <boost/cstdint.hpp>
70 #include "System/Platform/Misc.h"
71
72 #include "System/Sound/OpenAL/EFX.h"
73 #include "System/Sound/OpenAL/EFXPresets.h"
74
75 #include <map>
76 #include <set>
77 #include <cctype>
78 #include <cfloat>
79
80 #include <fstream>
81
82 #include <SDL_clipboard.h>
83 #include <SDL_mouse.h>
84
85 using std::min;
86 using std::max;
87
88 // MinGW defines this for a WINAPI function
89 #undef SendMessage
90 #undef CreateDirectory
91
92 const int CMD_INDEX_OFFSET = 1; // starting index for command descriptions
93
94
95 /******************************************************************************/
96 /******************************************************************************/
97
98 std::set<int> drawCmdQueueUnits;
99
100 /******************************************************************************/
101 /******************************************************************************/
102
PushEntries(lua_State * L)103 bool LuaUnsyncedCtrl::PushEntries(lua_State* L)
104 {
105 #define REGISTER_LUA_CFUNC(x) \
106 lua_pushstring(L, #x); \
107 lua_pushcfunction(L, x); \
108 lua_rawset(L, -3)
109
110 REGISTER_LUA_CFUNC(Echo);
111 REGISTER_LUA_CFUNC(Log);
112
113 REGISTER_LUA_CFUNC(SendMessage);
114 REGISTER_LUA_CFUNC(SendMessageToPlayer);
115 REGISTER_LUA_CFUNC(SendMessageToTeam);
116 REGISTER_LUA_CFUNC(SendMessageToAllyTeam);
117 REGISTER_LUA_CFUNC(SendMessageToSpectators);
118
119 REGISTER_LUA_CFUNC(LoadSoundDef);
120 REGISTER_LUA_CFUNC(PlaySoundFile);
121 REGISTER_LUA_CFUNC(PlaySoundStream);
122 REGISTER_LUA_CFUNC(StopSoundStream);
123 REGISTER_LUA_CFUNC(PauseSoundStream);
124 REGISTER_LUA_CFUNC(SetSoundStreamVolume);
125 REGISTER_LUA_CFUNC(SetSoundEffectParams);
126
127 REGISTER_LUA_CFUNC(SetCameraState);
128 REGISTER_LUA_CFUNC(SetCameraTarget);
129
130 REGISTER_LUA_CFUNC(SelectUnitMap);
131 REGISTER_LUA_CFUNC(SelectUnitArray);
132
133 REGISTER_LUA_CFUNC(AddWorldIcon);
134 REGISTER_LUA_CFUNC(AddWorldText);
135 REGISTER_LUA_CFUNC(AddWorldUnit);
136
137 REGISTER_LUA_CFUNC(DrawUnitCommands);
138
139 REGISTER_LUA_CFUNC(SetTeamColor);
140
141 REGISTER_LUA_CFUNC(AssignMouseCursor);
142 REGISTER_LUA_CFUNC(ReplaceMouseCursor);
143
144 REGISTER_LUA_CFUNC(SetCustomCommandDrawData);
145
146 REGISTER_LUA_CFUNC(SetDrawSky);
147 REGISTER_LUA_CFUNC(SetDrawWater);
148 REGISTER_LUA_CFUNC(SetDrawGround);
149 REGISTER_LUA_CFUNC(SetDrawGroundDeferred);
150 REGISTER_LUA_CFUNC(SetDrawModelsDeferred);
151
152 REGISTER_LUA_CFUNC(SetWaterParams);
153
154 REGISTER_LUA_CFUNC(AddMapLight);
155 REGISTER_LUA_CFUNC(AddModelLight);
156 REGISTER_LUA_CFUNC(UpdateMapLight);
157 REGISTER_LUA_CFUNC(UpdateModelLight);
158 REGISTER_LUA_CFUNC(SetMapLightTrackingState);
159 REGISTER_LUA_CFUNC(SetModelLightTrackingState);
160 REGISTER_LUA_CFUNC(SetMapSquareTexture);
161
162 REGISTER_LUA_CFUNC(SetUnitNoDraw);
163 REGISTER_LUA_CFUNC(SetUnitNoMinimap);
164 REGISTER_LUA_CFUNC(SetUnitNoSelect);
165 REGISTER_LUA_CFUNC(SetUnitLeaveTracks);
166
167 REGISTER_LUA_CFUNC(AddUnitIcon);
168 REGISTER_LUA_CFUNC(FreeUnitIcon);
169
170 REGISTER_LUA_CFUNC(ExtractModArchiveFile);
171
172 // moved from LuaUI
173
174 //FIXME REGISTER_LUA_CFUNC(SetShockFrontFactors);
175
176 REGISTER_LUA_CFUNC(GetConfigInt);
177 REGISTER_LUA_CFUNC(SetConfigInt);
178 REGISTER_LUA_CFUNC(GetConfigString);
179 REGISTER_LUA_CFUNC(SetConfigString);
180
181 REGISTER_LUA_CFUNC(CreateDir);
182
183 REGISTER_LUA_CFUNC(SendCommands);
184 REGISTER_LUA_CFUNC(GiveOrder);
185 REGISTER_LUA_CFUNC(GiveOrderToUnit);
186 REGISTER_LUA_CFUNC(GiveOrderToUnitMap);
187 REGISTER_LUA_CFUNC(GiveOrderToUnitArray);
188 REGISTER_LUA_CFUNC(GiveOrderArrayToUnitMap);
189 REGISTER_LUA_CFUNC(GiveOrderArrayToUnitArray);
190
191 REGISTER_LUA_CFUNC(SendLuaUIMsg);
192 REGISTER_LUA_CFUNC(SendLuaGaiaMsg);
193 REGISTER_LUA_CFUNC(SendLuaRulesMsg);
194
195 REGISTER_LUA_CFUNC(LoadCmdColorsConfig);
196 REGISTER_LUA_CFUNC(LoadCtrlPanelConfig);
197
198 REGISTER_LUA_CFUNC(SetActiveCommand);
199 REGISTER_LUA_CFUNC(ForceLayoutUpdate);
200
201 REGISTER_LUA_CFUNC(SetMouseCursor);
202 REGISTER_LUA_CFUNC(WarpMouse);
203
204 REGISTER_LUA_CFUNC(SetClipboard);
205
206 REGISTER_LUA_CFUNC(SetCameraOffset);
207
208 REGISTER_LUA_CFUNC(UpdateInfoTexture);
209 REGISTER_LUA_CFUNC(SetLosViewColors);
210
211 REGISTER_LUA_CFUNC(Restart);
212 REGISTER_LUA_CFUNC(SetWMIcon);
213 REGISTER_LUA_CFUNC(SetWMCaption);
214
215 REGISTER_LUA_CFUNC(SetUnitDefIcon);
216 REGISTER_LUA_CFUNC(SetUnitDefImage);
217
218 REGISTER_LUA_CFUNC(SetUnitGroup);
219
220 REGISTER_LUA_CFUNC(SetShareLevel);
221 REGISTER_LUA_CFUNC(ShareResources);
222
223 REGISTER_LUA_CFUNC(SetLastMessagePosition);
224
225 REGISTER_LUA_CFUNC(MarkerAddPoint);
226 REGISTER_LUA_CFUNC(MarkerAddLine);
227 REGISTER_LUA_CFUNC(MarkerErasePosition);
228
229 REGISTER_LUA_CFUNC(SetDrawSelectionInfo);
230
231 REGISTER_LUA_CFUNC(SetBuildSpacing);
232 REGISTER_LUA_CFUNC(SetBuildFacing);
233
234 REGISTER_LUA_CFUNC(SetSunParameters);
235 REGISTER_LUA_CFUNC(SetSunManualControl);
236 REGISTER_LUA_CFUNC(SetSunDirection);
237
238 REGISTER_LUA_CFUNC(SendSkirmishAIMessage);
239
240 REGISTER_LUA_CFUNC(SetLogSectionFilterLevel);
241
242 REGISTER_LUA_CFUNC(ClearWatchDogTimer);
243
244 return true;
245 }
246
247
248 /******************************************************************************/
249 /******************************************************************************/
250 //
251 // Parsing helpers
252 //
253
ParseRawProjectile(lua_State * L,const char * caller,int index,bool synced)254 static inline CProjectile* ParseRawProjectile(lua_State* L, const char* caller, int index, bool synced)
255 {
256 if (!lua_isnumber(L, index)) {
257 if (caller != NULL) {
258 luaL_error(L, "[%s] projectile ID parameter in %s() not a number\n", __FUNCTION__, caller);
259 }
260 return NULL;
261 }
262
263 const int projID = lua_toint(L, index);
264
265 const ProjectileMapValPair* pp = NULL;
266 if (synced) {
267 pp = projectileHandler->GetMapPairBySyncedID(projID);
268 } else {
269 pp = projectileHandler->GetMapPairByUnsyncedID(projID);
270 }
271
272 return (pp) ? pp->first : NULL;
273 }
274
ParseRawUnit(lua_State * L,const char * caller,int index)275 static inline CUnit* ParseRawUnit(lua_State* L, const char* caller, int index)
276 {
277 if (!lua_isnumber(L, index)) {
278 if (caller != NULL) {
279 luaL_error(L, "[%s] unit ID parameter in %s() not a number\n", __FUNCTION__, caller);
280 }
281 return NULL;
282 }
283
284 const int unitID = lua_toint(L, index);
285 if ((unitID < 0) || (static_cast<size_t>(unitID) >= unitHandler->MaxUnits())) {
286 luaL_error(L, "%s(): Bad unitID: %d\n", caller, unitID);
287 }
288
289 return unitHandler->units[unitID];
290 }
291
292
ParseAllyUnit(lua_State * L,const char * caller,int index)293 static inline CUnit* ParseAllyUnit(lua_State* L, const char* caller, int index)
294 {
295 CUnit* unit = ParseRawUnit(L, caller, index);
296 if (unit == NULL) {
297 return NULL;
298 }
299 if (CLuaHandle::GetHandleReadAllyTeam(L) < 0) {
300 return CLuaHandle::GetHandleFullRead(L) ? unit : NULL;
301 }
302 return (unit->allyteam == CLuaHandle::GetHandleReadAllyTeam(L)) ? unit : NULL;
303 }
304
305
ParseCtrlUnit(lua_State * L,const char * caller,int index)306 static inline CUnit* ParseCtrlUnit(lua_State* L,
307 const char* caller, int index)
308 {
309 CUnit* unit = ParseRawUnit(L, caller, index);
310 if (unit == NULL) {
311 return NULL;
312 }
313 return (CanControlTeam(L, unit->team) ? unit : NULL);
314 }
315
316
ParseSelectUnit(lua_State * L,const char * caller,int index)317 static inline CUnit* ParseSelectUnit(lua_State* L,
318 const char* caller, int index)
319 {
320 CUnit* unit = ParseRawUnit(L, caller, index);
321 if (unit == NULL || unit->noSelect) {
322 return NULL;
323 }
324 const int selectTeam = CLuaHandle::GetHandleSelectTeam(L);
325 if (selectTeam < 0) {
326 return (selectTeam == CEventClient::AllAccessTeam) ? unit : NULL;
327 }
328 if (selectTeam == unit->team) {
329 return unit;
330 }
331 return NULL;
332 }
333
334
335 /******************************************************************************/
336 /******************************************************************************/
337
DrawUnitCommandQueues()338 void LuaUnsyncedCtrl::DrawUnitCommandQueues()
339 {
340 if (drawCmdQueueUnits.empty()) {
341 return;
342 }
343
344 glDisable(GL_TEXTURE_2D);
345 glDisable(GL_DEPTH_TEST);
346
347 lineDrawer.Configure(cmdColors.UseColorRestarts(),
348 cmdColors.UseRestartColor(),
349 cmdColors.restart,
350 cmdColors.RestartAlpha());
351 lineDrawer.SetupLineStipple();
352
353 glEnable(GL_BLEND);
354 glBlendFunc((GLenum)cmdColors.QueuedBlendSrc(),
355 (GLenum)cmdColors.QueuedBlendDst());
356
357 glLineWidth(cmdColors.QueuedLineWidth());
358
359 std::set<int>::const_iterator ui;
360
361 for (ui = drawCmdQueueUnits.begin(); ui != drawCmdQueueUnits.end(); ++ui) {
362 const CUnit* unit = unitHandler->GetUnit(*ui);
363
364 if (unit == NULL || unit->commandAI == NULL) {
365 continue;
366 }
367
368 commandDrawer->Draw(unit->commandAI);
369 }
370
371 glLineWidth(1.0f);
372 glEnable(GL_DEPTH_TEST);
373 }
374
375
ClearUnitCommandQueues()376 void LuaUnsyncedCtrl::ClearUnitCommandQueues()
377 {
378 drawCmdQueueUnits.clear();
379 }
380
381
382 /******************************************************************************/
383 /******************************************************************************/
384 //
385 // The call-outs
386 //
387
Echo(lua_State * L)388 int LuaUnsyncedCtrl::Echo(lua_State* L)
389 {
390 return LuaUtils::Echo(L);
391 }
392
Log(lua_State * L)393 int LuaUnsyncedCtrl::Log(lua_State* L)
394 {
395 return LuaUtils::Log(L);
396 }
397
ParseMessage(lua_State * L,const string & msg)398 static string ParseMessage(lua_State* L, const string& msg)
399 {
400 string::size_type start = msg.find("<PLAYER");
401 if (start == string::npos) {
402 return msg;
403 }
404
405 const char* number = msg.c_str() + start + strlen("<PLAYER");
406 char* endPtr;
407 const int playerID = (int)strtol(number, &endPtr, 10);
408 if ((endPtr == number) || (*endPtr != '>')) {
409 luaL_error(L, "Bad message format: %s", msg.c_str());
410 }
411
412 if (!playerHandler->IsValidPlayer(playerID)) {
413 luaL_error(L, "Invalid message playerID: %c", playerID); //FIXME
414 }
415 const CPlayer* player = playerHandler->Player(playerID);
416 if ((player == NULL) || !player->active || player->name.empty()) {
417 luaL_error(L, "Invalid message playerID: %c", playerID);
418 }
419
420 const string head = msg.substr(0, start);
421 const string tail = msg.substr(endPtr - msg.c_str() + 1);
422
423 return head + player->name + ParseMessage(L, tail);
424 }
425
426
PrintMessage(lua_State * L,const string & msg)427 static void PrintMessage(lua_State* L, const string& msg)
428 {
429 LOG("%s", ParseMessage(L, msg).c_str());
430 }
431
432
SendMessage(lua_State * L)433 int LuaUnsyncedCtrl::SendMessage(lua_State* L)
434 {
435 PrintMessage(L, luaL_checksstring(L, 1));
436 return 0;
437 }
438
439
SendMessageToSpectators(lua_State * L)440 int LuaUnsyncedCtrl::SendMessageToSpectators(lua_State* L)
441 {
442 if (gu->spectating) {
443 PrintMessage(L, luaL_checksstring(L, 1));
444 }
445 return 0;
446 }
447
448
SendMessageToPlayer(lua_State * L)449 int LuaUnsyncedCtrl::SendMessageToPlayer(lua_State* L)
450 {
451 const int playerID = luaL_checkint(L, 1);
452 if (playerID == gu->myPlayerNum) {
453 PrintMessage(L, luaL_checksstring(L, 2));
454 }
455 return 0;
456 }
457
458
SendMessageToTeam(lua_State * L)459 int LuaUnsyncedCtrl::SendMessageToTeam(lua_State* L)
460 {
461 const int teamID = luaL_checkint(L, 1);
462 if (teamID == gu->myTeam) {
463 PrintMessage(L, luaL_checksstring(L, 2));
464 }
465 return 0;
466 }
467
468
SendMessageToAllyTeam(lua_State * L)469 int LuaUnsyncedCtrl::SendMessageToAllyTeam(lua_State* L)
470 {
471 const int allyTeamID = luaL_checkint(L, 1);
472 if (allyTeamID == gu->myAllyTeam) {
473 PrintMessage(L, luaL_checksstring(L, 2));
474 }
475 return 0;
476 }
477
478
479 /******************************************************************************/
480
LoadSoundDef(lua_State * L)481 int LuaUnsyncedCtrl::LoadSoundDef(lua_State* L)
482 {
483 const string soundFile = luaL_checksstring(L, 1);
484 bool success = sound->LoadSoundDefs(soundFile);
485
486 if (!CLuaHandle::GetHandleSynced(L)) {
487 lua_pushboolean(L, success);
488 return 1;
489 } else {
490 return 0;
491 }
492 }
493
PlaySoundFile(lua_State * L)494 int LuaUnsyncedCtrl::PlaySoundFile(lua_State* L)
495 {
496 const int args = lua_gettop(L);
497 bool success = false;
498 const string soundFile = luaL_checksstring(L, 1);
499 const unsigned int soundID = sound->GetSoundId(soundFile);
500 if (soundID > 0) {
501 float volume = luaL_optfloat(L, 2, 1.0f);
502 float3 pos;
503 float3 speed;
504 bool pos_given = false;
505 bool speed_given = false;
506
507 int index = 3;
508 if (args >= 5 && lua_isnumber(L, 3) && lua_isnumber(L, 4) && lua_isnumber(L, 5)) {
509 pos = float3(lua_tofloat(L, 3), lua_tofloat(L, 4), lua_tofloat(L, 5));
510 pos_given = true;
511 index += 3;
512
513 if (args >= 8 && lua_isnumber(L, 6) && lua_isnumber(L, 7) && lua_isnumber(L, 8))
514 {
515 speed = float3(lua_tofloat(L, 6), lua_tofloat(L, 7), lua_tofloat(L, 8));
516 speed_given = true;
517 index += 3;
518 }
519 }
520
521 //! last argument (with and without pos/speed arguments) is the optional `sfx channel`
522 IAudioChannel** channel = &Channels::General;
523 if (args >= index) {
524 if (lua_isstring(L, index)) {
525 string channelStr = lua_tostring(L, index);
526 StringToLowerInPlace(channelStr);
527
528 if (channelStr == "battle" || channelStr == "sfx") {
529 channel = &Channels::Battle;
530 }
531 else if (channelStr == "unitreply" || channelStr == "voice") {
532 channel = &Channels::UnitReply;
533 }
534 else if (channelStr == "userinterface" || channelStr == "ui") {
535 channel = &Channels::UserInterface;
536 }
537 } else if (lua_isnumber(L, index)) {
538 const int channelNum = lua_toint(L, index);
539
540 if (channelNum == 1) {
541 channel = &Channels::Battle;
542 }
543 else if (channelNum == 2) {
544 channel = &Channels::UnitReply;
545 }
546 else if (channelNum == 3) {
547 channel = &Channels::UserInterface;
548 }
549 }
550 }
551
552 if (pos_given) {
553 if (speed_given) {
554 channel[0]->PlaySample(soundID, pos, speed, volume);
555 } else {
556 channel[0]->PlaySample(soundID, pos, volume);
557 }
558 } else
559 channel[0]->PlaySample(soundID, volume);
560
561 success = true;
562 }
563
564 if (!CLuaHandle::GetHandleSynced(L)) {
565 lua_pushboolean(L, success);
566 return 1;
567 } else {
568 return 0;
569 }
570 }
571
572
PlaySoundStream(lua_State * L)573 int LuaUnsyncedCtrl::PlaySoundStream(lua_State* L)
574 {
575 const string soundFile = luaL_checksstring(L, 1);
576 const float volume = luaL_optnumber(L, 2, 1.0f);
577 bool enqueue = luaL_optboolean(L, 3, false);
578
579 Channels::BGMusic->StreamPlay(soundFile, volume, enqueue);
580
581 // .ogg files don't have sound ID's generated
582 // for them (yet), so we always succeed here
583 if (!CLuaHandle::GetHandleSynced(L)) {
584 lua_pushboolean(L, true);
585 return 1;
586 } else {
587 return 0;
588 }
589 }
590
StopSoundStream(lua_State *)591 int LuaUnsyncedCtrl::StopSoundStream(lua_State*)
592 {
593 Channels::BGMusic->StreamStop();
594 return 0;
595 }
PauseSoundStream(lua_State *)596 int LuaUnsyncedCtrl::PauseSoundStream(lua_State*)
597 {
598 Channels::BGMusic->StreamPause();
599 return 0;
600 }
SetSoundStreamVolume(lua_State * L)601 int LuaUnsyncedCtrl::SetSoundStreamVolume(lua_State* L)
602 {
603 Channels::BGMusic->SetVolume(luaL_checkfloat(L, 1));
604 return 0;
605 }
606
607
SetSoundEffectParams(lua_State * L)608 int LuaUnsyncedCtrl::SetSoundEffectParams(lua_State* L)
609 {
610 #if !defined(HEADLESS) && !defined(NO_SOUND)
611 if (!efx)
612 return 0;
613
614 //! only a preset name given?
615 if (lua_israwstring(L, 1)) {
616 const std::string presetname = lua_tostring(L, 1);
617 efx->SetPreset(presetname, false);
618 return 0;
619 }
620
621 if (!lua_istable(L, 1)) {
622 luaL_error(L, "Incorrect arguments to SetSoundEffectParams()");
623 }
624
625 //! first parse the 'preset' key (so all following params use it as base and override it)
626 lua_pushliteral(L, "preset");
627 lua_gettable(L, -2);
628 if (lua_israwstring(L, -1)) {
629 std::string presetname = lua_tostring(L, -1);
630 efx->SetPreset(presetname, false, false);
631 }
632 lua_pop(L, 1);
633
634
635 if (!efx->sfxProperties)
636 return 0;
637
638 EAXSfxProps* efxprops = efx->sfxProperties;
639
640
641 //! parse pass filter
642 lua_pushliteral(L, "passfilter");
643 lua_gettable(L, -2);
644 if (lua_istable(L, -1)) {
645 for (lua_pushnil(L); lua_next(L, -2) != 0; lua_pop(L, 1)) {
646 if (!lua_israwstring(L, -2))
647 continue;
648
649 const string key = StringToLower(lua_tostring(L, -2));
650 std::map<std::string, ALuint>::iterator it = nameToALFilterParam.find(key);
651
652 if (it == nameToALFilterParam.end())
653 continue;
654
655 ALuint param = it->second;
656
657 if (!lua_isnumber(L, -1))
658 continue;
659 if (alParamType[param] != EFXParamTypes::FLOAT)
660 continue;
661
662 efxprops->filter_properties_f[param] = lua_tofloat(L, -1);
663 }
664 }
665 lua_pop(L, 1);
666
667 //! parse EAX Reverb
668 lua_pushliteral(L, "reverb");
669 lua_gettable(L, -2);
670 if (lua_istable(L, -1)) {
671 for (lua_pushnil(L); lua_next(L, -2) != 0; lua_pop(L, 1)) {
672 if (!lua_israwstring(L, -2))
673 continue;
674
675 const string key = StringToLower(lua_tostring(L, -2));
676 std::map<std::string, ALuint>::iterator it = nameToALParam.find(key);
677
678 if (it == nameToALParam.end())
679 continue;
680
681 ALuint param = it->second;
682 if (lua_istable(L, -1)) {
683 if (alParamType[param] == EFXParamTypes::VECTOR) {
684 float3 v;
685
686 if (LuaUtils::ParseFloatArray(L, -1, &v[0], 3) >= 3) {
687 efxprops->properties_v[param] = v;
688 }
689 }
690 }
691 else if (lua_isnumber(L, -1)) {
692 if (alParamType[param] == EFXParamTypes::FLOAT) {
693 efxprops->properties_f[param] = lua_tofloat(L, -1);
694 }
695 }
696 else if (lua_isboolean(L, -1)) {
697 if (alParamType[param] == EFXParamTypes::BOOL) {
698 efxprops->properties_i[param] = lua_toboolean(L, -1);
699 }
700 }
701 }
702 }
703 lua_pop(L, 1);
704
705 //! commit effects
706 efx->CommitEffects();
707 #endif /// !defined(HEADLESS) && !defined(NO_SOUND)
708
709 return 0;
710 }
711
712
713 /******************************************************************************/
714 /******************************************************************************/
715
AddWorldIcon(lua_State * L)716 int LuaUnsyncedCtrl::AddWorldIcon(lua_State* L)
717 {
718 const int cmdID = luaL_checkint(L, 1);
719 const float3 pos(luaL_checkfloat(L, 2),
720 luaL_checkfloat(L, 3),
721 luaL_checkfloat(L, 4));
722 cursorIcons.AddIcon(cmdID, pos);
723 return 0;
724 }
725
726
AddWorldText(lua_State * L)727 int LuaUnsyncedCtrl::AddWorldText(lua_State* L)
728 {
729 const string text = luaL_checksstring(L, 1);
730 const float3 pos(luaL_checkfloat(L, 2),
731 luaL_checkfloat(L, 3),
732 luaL_checkfloat(L, 4));
733 cursorIcons.AddIconText(text, pos);
734 return 0;
735 }
736
737
AddWorldUnit(lua_State * L)738 int LuaUnsyncedCtrl::AddWorldUnit(lua_State* L)
739 {
740 const int unitDefID = luaL_checkint(L, 1);
741 if (!unitDefHandler->IsValidUnitDefID(unitDefID)) {
742 return 0;
743 }
744 const float3 pos(luaL_checkfloat(L, 2),
745 luaL_checkfloat(L, 3),
746 luaL_checkfloat(L, 4));
747 const int teamId = luaL_checkint(L, 5);
748 if (!teamHandler->IsValidTeam(teamId)) {
749 return 0;
750 }
751 const int facing = luaL_checkint(L, 6);
752 cursorIcons.AddBuildIcon(-unitDefID, pos, teamId, facing);
753 return 0;
754 }
755
756
DrawUnitCommands(lua_State * L)757 int LuaUnsyncedCtrl::DrawUnitCommands(lua_State* L)
758 {
759 if (lua_istable(L, 1)) {
760 const bool isMap = luaL_optboolean(L, 2, false);
761 const int unitArg = isMap ? -2 : -1;
762 const int table = 1;
763 for (lua_pushnil(L); lua_next(L, table) != 0; lua_pop(L, 1)) {
764 if (lua_israwnumber(L, -2)) {
765 CUnit* unit = ParseAllyUnit(L, __FUNCTION__, unitArg);
766 if (unit != NULL) {
767 drawCmdQueueUnits.insert(unit->id);
768 }
769 }
770 }
771 return 0;
772 }
773
774 CUnit* unit = ParseAllyUnit(L, __FUNCTION__, 1);
775 if (unit != NULL) {
776 drawCmdQueueUnits.insert(unit->id);
777 }
778 return 0;
779 }
780
781
782 /******************************************************************************/
783 /******************************************************************************/
784
SetCameraTarget(lua_State * L)785 int LuaUnsyncedCtrl::SetCameraTarget(lua_State* L)
786 {
787 if (mouse == NULL) {
788 return 0;
789 }
790
791 const float3 pos(luaL_checkfloat(L, 1),
792 luaL_checkfloat(L, 2),
793 luaL_checkfloat(L, 3));
794
795 const float transTime = luaL_optfloat(L, 4, 0.5f);
796
797 camHandler->CameraTransition(transTime);
798 camHandler->GetCurrentController().SetPos(pos);
799
800 return 0;
801 }
802
803
SetCameraState(lua_State * L)804 int LuaUnsyncedCtrl::SetCameraState(lua_State* L)
805 {
806 if (mouse == NULL) {
807 return 0;
808 }
809
810 if (!lua_istable(L, 1)) {
811 luaL_error(L, "Incorrect arguments to SetCameraState(table, camTime)");
812 }
813
814 const float camTime = luaL_checkfloat(L, 2);
815
816 CCameraController::StateMap camState;
817
818 const int table = 1;
819 for (lua_pushnil(L); lua_next(L, table) != 0; lua_pop(L, 1)) {
820 if (lua_israwstring(L, -2)) {
821 const string key = lua_tostring(L, -2);
822 if (lua_isnumber(L, -1)) {
823 camState[key] = lua_tofloat(L, -1);
824 }
825 else if (lua_isboolean(L, -1)) {
826 camState[key] = lua_toboolean(L, -1) ? +1.0f : -1.0f;
827 }
828 }
829 }
830
831 camHandler->CameraTransition(camTime);
832 lua_pushboolean(L, camHandler->SetState(camState));
833
834 if (!CLuaHandle::GetHandleSynced(L)) {
835 return 1;
836 } else {
837 return 0;
838 }
839 }
840
841
842 /******************************************************************************/
843 /******************************************************************************/
844
SelectUnitArray(lua_State * L)845 int LuaUnsyncedCtrl::SelectUnitArray(lua_State* L)
846 {
847 if (!lua_istable(L, 1)) {
848 luaL_error(L, "Incorrect arguments to SelectUnitArray()");
849 }
850
851 // clear the current units, unless the append flag is present
852 if (!luaL_optboolean(L, 2, false)) {
853 selectedUnitsHandler.ClearSelected();
854 }
855
856 const int table = 1;
857 for (lua_pushnil(L); lua_next(L, table) != 0; lua_pop(L, 1)) {
858 if (lua_israwnumber(L, -2) && lua_isnumber(L, -1)) { // avoid 'n'
859 CUnit* unit = ParseSelectUnit(L, __FUNCTION__, -1); // the value
860 if (unit != NULL) {
861 selectedUnitsHandler.AddUnit(unit);
862 }
863 }
864 }
865 return 0;
866 }
867
868
SelectUnitMap(lua_State * L)869 int LuaUnsyncedCtrl::SelectUnitMap(lua_State* L)
870 {
871 if (!lua_istable(L, 1)) {
872 luaL_error(L, "Incorrect arguments to SelectUnitMap()");
873 }
874
875 // clear the current units, unless the append flag is present
876 if (!luaL_optboolean(L, 2, false)) {
877 selectedUnitsHandler.ClearSelected();
878 }
879
880 const int table = 1;
881 for (lua_pushnil(L); lua_next(L, table) != 0; lua_pop(L, 1)) {
882 if (lua_israwnumber(L, -2)) {
883 CUnit* unit = ParseSelectUnit(L, __FUNCTION__, -2); // the key
884 if (unit != NULL) {
885 selectedUnitsHandler.AddUnit(unit);
886 }
887 }
888 }
889
890 return 0;
891 }
892
893
894 /******************************************************************************/
895
SetTeamColor(lua_State * L)896 int LuaUnsyncedCtrl::SetTeamColor(lua_State* L)
897 {
898 const int teamID = luaL_checkint(L, 1);
899 if (!teamHandler->IsValidTeam(teamID)) {
900 return 0;
901 }
902 CTeam* team = teamHandler->Team(teamID);
903 if (team == NULL) {
904 return 0;
905 }
906 const float r = max(0.0f, min(1.0f, luaL_checkfloat(L, 2)));
907 const float g = max(0.0f, min(1.0f, luaL_checkfloat(L, 3)));
908 const float b = max(0.0f, min(1.0f, luaL_checkfloat(L, 4)));
909 team->color[0] = (unsigned char)(r * 255.0f);
910 team->color[1] = (unsigned char)(g * 255.0f);
911 team->color[2] = (unsigned char)(b * 255.0f);
912 return 0;
913 }
914
915
916 /******************************************************************************/
917
AssignMouseCursor(lua_State * L)918 int LuaUnsyncedCtrl::AssignMouseCursor(lua_State* L)
919 {
920 const string cmdName = luaL_checksstring(L, 1);
921 const string fileName = luaL_checksstring(L, 2);
922
923 const bool overwrite = luaL_optboolean(L, 3, true);
924
925 CMouseCursor::HotSpot hotSpot = CMouseCursor::Center;
926 if (luaL_optboolean(L, 4, false)) {
927 hotSpot = CMouseCursor::TopLeft;
928 }
929
930 const bool worked = mouse->AssignMouseCursor(cmdName, fileName, hotSpot, overwrite);
931
932 if (!CLuaHandle::GetHandleSynced(L)) {
933 lua_pushboolean(L, worked);
934 return 1;
935 }
936
937 return 0;
938 }
939
940
ReplaceMouseCursor(lua_State * L)941 int LuaUnsyncedCtrl::ReplaceMouseCursor(lua_State* L)
942 {
943 const string oldName = luaL_checksstring(L, 1);
944 const string newName = luaL_checksstring(L, 2);
945
946 CMouseCursor::HotSpot hotSpot = CMouseCursor::Center;
947 if (luaL_optboolean(L, 3, false)) {
948 hotSpot = CMouseCursor::TopLeft;
949 }
950
951 const bool worked = mouse->ReplaceMouseCursor(oldName, newName, hotSpot);
952
953 if (!CLuaHandle::GetHandleSynced(L)) {
954 lua_pushboolean(L, worked);
955 return 1;
956 }
957
958 return 0;
959 }
960
961 /******************************************************************************/
962
SetCustomCommandDrawData(lua_State * L)963 int LuaUnsyncedCtrl::SetCustomCommandDrawData(lua_State* L)
964 {
965 const int cmdID = luaL_checkint(L, 1);
966
967 int iconID = 0;
968 if (lua_israwnumber(L, 2)) {
969 iconID = lua_toint(L, 2);
970 }
971 else if (lua_israwstring(L, 2)) {
972 iconID = cmdID;
973 const string icon = lua_tostring(L, 2);
974 cursorIcons.SetCustomType(cmdID, icon);
975 }
976 else if (lua_isnoneornil(L, 2)) {
977 cursorIcons.SetCustomType(cmdID, "");
978 cmdColors.ClearCustomCmdData(cmdID);
979 return 0;
980 }
981 else {
982 luaL_error(L, "Incorrect arguments to SetCustomCommandDrawData");
983 }
984
985 float color[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
986 /*const int size =*/ LuaUtils::ParseFloatArray(L, 3, color, 4);
987
988 const bool showArea = luaL_optboolean(L, 4, false);
989
990 cmdColors.SetCustomCmdData(cmdID, iconID, color, showArea);
991
992 return 0;
993 }
994
995
996 /******************************************************************************/
997 /******************************************************************************/
998
SetDrawSky(lua_State * L)999 int LuaUnsyncedCtrl::SetDrawSky(lua_State* L)
1000 {
1001 if (game == NULL) {
1002 return 0;
1003 }
1004 globalRendering->drawSky = !!luaL_checkboolean(L, 1);
1005 return 0;
1006 }
1007
1008
SetDrawWater(lua_State * L)1009 int LuaUnsyncedCtrl::SetDrawWater(lua_State* L)
1010 {
1011 if (game == NULL) {
1012 return 0;
1013 }
1014 globalRendering->drawWater = !!luaL_checkboolean(L, 1);
1015 return 0;
1016 }
1017
1018
SetDrawGround(lua_State * L)1019 int LuaUnsyncedCtrl::SetDrawGround(lua_State* L)
1020 {
1021 if (game == NULL) {
1022 return 0;
1023 }
1024 globalRendering->drawGround = !!luaL_checkboolean(L, 1);
1025 return 0;
1026 }
1027
1028
SetDrawGroundDeferred(lua_State * L)1029 int LuaUnsyncedCtrl::SetDrawGroundDeferred(lua_State* L)
1030 {
1031 readMap->GetGroundDrawer()->SetDrawDeferredPass(luaL_checkboolean(L, 1));
1032 lua_pushboolean(L, readMap->GetGroundDrawer()->DrawDeferred());
1033 return 1;
1034 }
1035
SetDrawModelsDeferred(lua_State * L)1036 int LuaUnsyncedCtrl::SetDrawModelsDeferred(lua_State* L)
1037 {
1038 unitDrawer->SetDrawDeferredPass(luaL_checkboolean(L, 1));
1039 lua_pushboolean(L, unitDrawer->DrawDeferred());
1040 return 1;
1041 }
1042
1043
1044 /******************************************************************************/
1045
SetWaterParams(lua_State * L)1046 int LuaUnsyncedCtrl::SetWaterParams(lua_State* L)
1047 {
1048 if (game == NULL) {
1049 return 0;
1050 }
1051 if (!gs->cheatEnabled) {
1052 LOG("SetWaterParams() needs cheating enabled");
1053 return 0;
1054 }
1055 if (!lua_istable(L, 1)) {
1056 luaL_error(L, "Incorrect arguments to SetWaterParams()");
1057 }
1058
1059 CMapInfo::water_t& w = const_cast<CMapInfo*>(mapInfo)->water;
1060 for (lua_pushnil(L); lua_next(L, 1) != 0; lua_pop(L, 1)) {
1061 if (lua_israwstring(L, -2)) {
1062 const string key = lua_tostring(L, -2);
1063 if (lua_istable(L, -1)) {
1064 float color[3];
1065 const int size = LuaUtils::ParseFloatArray(L, -1, color, 3);
1066 if (size >= 3) {
1067 if (key == "absorb") {
1068 w.absorb = color;
1069 } else if (key == "baseColor") {
1070 w.baseColor = color;
1071 } else if (key == "minColor") {
1072 w.minColor = color;
1073 } else if (key == "surfaceColor") {
1074 w.surfaceColor = color;
1075 } else if (key == "diffuseColor") {
1076 w.diffuseColor = color;
1077 } else if (key == "specularColor") {
1078 w.specularColor = color;
1079 } else if (key == "planeColor") {
1080 w.planeColor.x = color[0];
1081 w.planeColor.y = color[1];
1082 w.planeColor.z = color[2];
1083 }
1084 }
1085 }
1086 else if (lua_israwstring(L, -1)) {
1087 const std::string value = lua_tostring(L, -1);
1088 if (key == "texture") {
1089 w.texture = value;
1090 } else if (key == "foamTexture") {
1091 w.foamTexture = value;
1092 } else if (key == "normalTexture") {
1093 w.normalTexture = value;
1094 }
1095 }
1096 else if (lua_isnumber(L, -1)) {
1097 const float value = lua_tofloat(L, -1);
1098 if (key == "damage") {
1099 w.damage = value;
1100 } else if (key == "repeatX") {
1101 w.repeatX = value;
1102 } else if (key == "repeatY") {
1103 w.repeatY = value;
1104 } else if (key == "surfaceAlpha") {
1105 w.surfaceAlpha = value;
1106 } else if (key == "ambientFactor") {
1107 w.ambientFactor = value;
1108 } else if (key == "diffuseFactor") {
1109 w.diffuseFactor = value;
1110 } else if (key == "specularFactor") {
1111 w.specularFactor = value;
1112 } else if (key == "specularPower") {
1113 w.specularPower = value;
1114 } else if (key == "fresnelMin") {
1115 w.fresnelMin = value;
1116 } else if (key == "fresnelMax") {
1117 w.fresnelMax = value;
1118 } else if (key == "fresnelPower") {
1119 w.fresnelPower = value;
1120 } else if (key == "reflectionDistortion") {
1121 w.reflDistortion = value;
1122 } else if (key == "blurBase") {
1123 w.blurBase = value;
1124 } else if (key == "blurExponent") {
1125 w.blurExponent = value;
1126 } else if (key == "perlinStartFreq") {
1127 w.perlinStartFreq = value;
1128 } else if (key == "perlinLacunarity") {
1129 w.perlinLacunarity = value;
1130 } else if (key == "perlinAmplitude") {
1131 w.perlinAmplitude = value;
1132 } else if (key == "numTiles") {
1133 w.numTiles = (unsigned char)value;
1134 }
1135 }
1136 else if (lua_isboolean(L, -1)) {
1137 const bool value = lua_toboolean(L, -1);
1138 if (key == "shoreWaves") {
1139 w.shoreWaves = value;
1140 } else if (key == "forceRendering") {
1141 w.forceRendering = value;
1142 } else if (key == "hasWaterPlane") {
1143 w.hasWaterPlane = value;
1144 }
1145 }
1146 }
1147 }
1148
1149 return 0;
1150 }
1151
1152
1153
ParseLight(lua_State * L,GL::Light & light,const int tblIdx,const char * caller)1154 static bool ParseLight(lua_State* L, GL::Light& light, const int tblIdx, const char* caller)
1155 {
1156 if (!lua_istable(L, tblIdx)) {
1157 luaL_error(L, "[%s] argument %c must be a table!", caller, tblIdx);
1158 return false;
1159 }
1160
1161 for (lua_pushnil(L); lua_next(L, tblIdx) != 0; lua_pop(L, 1)) {
1162 if (lua_israwstring(L, -2)) {
1163 const std::string& key = lua_tostring(L, -2);
1164
1165 if (lua_istable(L, -1)) {
1166 float array[3] = {0.0f, 0.0f, 0.0f};
1167
1168 if (LuaUtils::ParseFloatArray(L, -1, array, 3) == 3) {
1169 if (key == "position") {
1170 light.SetPosition(array);
1171 } else if (key == "direction") {
1172 light.SetDirection(array);
1173 } else if (key == "ambientColor") {
1174 light.SetAmbientColor(array);
1175 } else if (key == "diffuseColor") {
1176 light.SetDiffuseColor(array);
1177 } else if (key == "specularColor") {
1178 light.SetSpecularColor(array);
1179 } else if (key == "intensityWeight") {
1180 light.SetIntensityWeight(array);
1181 } else if (key == "attenuation") {
1182 light.SetAttenuation(array);
1183 } else if (key == "ambientDecayRate") {
1184 light.SetAmbientDecayRate(array);
1185 } else if (key == "diffuseDecayRate") {
1186 light.SetDiffuseDecayRate(array);
1187 } else if (key == "specularDecayRate") {
1188 light.SetSpecularDecayRate(array);
1189 } else if (key == "decayFunctionType") {
1190 light.SetDecayFunctionType(array);
1191 }
1192 }
1193
1194 continue;
1195 }
1196
1197 if (lua_isnumber(L, -1)) {
1198 if (key == "radius") {
1199 light.SetRadius(std::max(1.0f, lua_tofloat(L, -1)));
1200 } else if (key == "fov") {
1201 light.SetFOV(std::max(0.0f, std::min(180.0f, lua_tofloat(L, -1))));
1202 } else if (key == "ttl") {
1203 light.SetTTL(lua_tofloat(L, -1));
1204 } else if (key == "priority") {
1205 light.SetPriority(lua_tofloat(L, -1));
1206 } else if (key == "ignoreLOS") {
1207 light.SetIgnoreLOS(lua_toboolean(L, -1));
1208 }
1209
1210 continue;
1211 }
1212 }
1213 }
1214
1215 return true;
1216 }
1217
1218
AddMapLight(lua_State * L)1219 int LuaUnsyncedCtrl::AddMapLight(lua_State* L)
1220 {
1221 if (CLuaHandle::GetHandleSynced(L) || !CLuaHandle::GetHandleFullRead(L)) {
1222 return 0;
1223 }
1224
1225 GL::LightHandler* lightHandler = readMap->GetGroundDrawer()->GetLightHandler();
1226 GL::Light light;
1227
1228 unsigned int lightHandle = -1U;
1229
1230 if (lightHandler != NULL) {
1231 if (ParseLight(L, light, 1, __FUNCTION__)) {
1232 lightHandle = lightHandler->AddLight(light);
1233 }
1234 }
1235
1236 lua_pushnumber(L, lightHandle);
1237 return 1;
1238 }
1239
AddModelLight(lua_State * L)1240 int LuaUnsyncedCtrl::AddModelLight(lua_State* L)
1241 {
1242 if (CLuaHandle::GetHandleSynced(L) || !CLuaHandle::GetHandleFullRead(L)) {
1243 return 0;
1244 }
1245
1246 GL::LightHandler* lightHandler = unitDrawer->GetLightHandler();
1247 GL::Light light;
1248
1249 unsigned int lightHandle = -1U;
1250
1251 if (lightHandler != NULL) {
1252 if (ParseLight(L, light, 1, __FUNCTION__)) {
1253 lightHandle = lightHandler->AddLight(light);
1254 }
1255 }
1256
1257 lua_pushnumber(L, lightHandle);
1258 return 1;
1259 }
1260
1261
UpdateMapLight(lua_State * L)1262 int LuaUnsyncedCtrl::UpdateMapLight(lua_State* L)
1263 {
1264 const unsigned int lightHandle = luaL_checkint(L, 1);
1265
1266 if (CLuaHandle::GetHandleSynced(L) || !CLuaHandle::GetHandleFullRead(L)) {
1267 return 0;
1268 }
1269
1270 GL::LightHandler* lightHandler = readMap->GetGroundDrawer()->GetLightHandler();
1271 GL::Light* light = (lightHandler != NULL)? lightHandler->GetLight(lightHandle): NULL;
1272
1273 bool ret = false;
1274
1275 if (light != NULL) {
1276 ret = ParseLight(L, *light, 2, __FUNCTION__);
1277 }
1278
1279 lua_pushboolean(L, ret);
1280 return 1;
1281 }
1282
UpdateModelLight(lua_State * L)1283 int LuaUnsyncedCtrl::UpdateModelLight(lua_State* L)
1284 {
1285 const unsigned int lightHandle = luaL_checkint(L, 1);
1286
1287 if (CLuaHandle::GetHandleSynced(L) || !CLuaHandle::GetHandleFullRead(L)) {
1288 return 0;
1289 }
1290
1291 GL::LightHandler* lightHandler = unitDrawer->GetLightHandler();
1292 GL::Light* light = (lightHandler != NULL)? lightHandler->GetLight(lightHandle): NULL;
1293 bool ret = false;
1294
1295 if (light != NULL) {
1296 ret = ParseLight(L, *light, 2, __FUNCTION__);
1297 }
1298
1299 lua_pushboolean(L, ret);
1300 return 1;
1301 }
1302
1303
AddLightTrackingTarget(lua_State * L,GL::Light * light,bool trackEnable,bool trackUnit,const char * caller)1304 static bool AddLightTrackingTarget(lua_State* L, GL::Light* light, bool trackEnable, bool trackUnit, const char* caller)
1305 {
1306 bool ret = false;
1307
1308 if (trackUnit) {
1309 // interpret argument #2 as a unit ID
1310 CUnit* unit = ParseAllyUnit(L, caller, 2);
1311
1312 if (unit != NULL) {
1313 if (trackEnable) {
1314 if (light->GetTrackPosition() == NULL) {
1315 light->AddDeathDependence(unit, DEPENDENCE_LIGHT);
1316 light->SetTrackPosition(&unit->drawPos);
1317 light->SetTrackDirection(&unit->speed); //! non-normalized
1318 ret = true;
1319 }
1320 } else {
1321 // assume <light> was tracking <unit>
1322 if (light->GetTrackPosition() == &unit->drawPos) {
1323 light->DeleteDeathDependence(unit, DEPENDENCE_LIGHT);
1324 light->SetTrackPosition(NULL);
1325 light->SetTrackDirection(NULL);
1326 ret = true;
1327 }
1328 }
1329 }
1330 } else {
1331 // interpret argument #2 as a projectile ID
1332 //
1333 // only track synced projectiles (LuaSynced
1334 // does not know about unsynced ID's anyway)
1335 CProjectile* proj = ParseRawProjectile(L, caller, 2, true);
1336
1337 if (proj != NULL) {
1338 if (trackEnable) {
1339 if (light->GetTrackPosition() == NULL) {
1340 light->AddDeathDependence(proj, DEPENDENCE_LIGHT);
1341 light->SetTrackPosition(&proj->drawPos);
1342 light->SetTrackDirection(&proj->dir);
1343 ret = true;
1344 }
1345 } else {
1346 // assume <light> was tracking <proj>
1347 if (light->GetTrackPosition() == &proj->drawPos) {
1348 light->DeleteDeathDependence(proj, DEPENDENCE_LIGHT);
1349 light->SetTrackPosition(NULL);
1350 light->SetTrackDirection(NULL);
1351 ret = true;
1352 }
1353 }
1354 }
1355 }
1356
1357 return ret;
1358 }
1359
1360 // set a map-illuminating light to start/stop tracking
1361 // the position of a moving object (unit or projectile)
SetMapLightTrackingState(lua_State * L)1362 int LuaUnsyncedCtrl::SetMapLightTrackingState(lua_State* L)
1363 {
1364 if (CLuaHandle::GetHandleSynced(L) || !CLuaHandle::GetHandleFullRead(L)) {
1365 return 0;
1366 }
1367 if (!lua_isnumber(L, 2)) {
1368 luaL_error(L, "[%s] 1st and 2nd arguments should be numbers, 3rd and 4th should be booleans", __FUNCTION__);
1369 return 0;
1370 }
1371
1372 const unsigned int lightHandle = luaL_checkint(L, 1);
1373 const bool trackEnable = luaL_optboolean(L, 3, true);
1374 const bool trackUnit = luaL_optboolean(L, 4, true);
1375
1376 GL::LightHandler* lightHandler = readMap->GetGroundDrawer()->GetLightHandler();
1377 GL::Light* light = (lightHandler != NULL)? lightHandler->GetLight(lightHandle): NULL;
1378
1379 bool ret = false;
1380
1381 if (light != NULL) {
1382 ret = AddLightTrackingTarget(L, light, trackEnable, trackUnit, __FUNCTION__);
1383 }
1384
1385 lua_pushboolean(L, ret);
1386 return 1;
1387 }
1388
1389 // set a model-illuminating light to start/stop tracking
1390 // the position of a moving object (unit or projectile)
SetModelLightTrackingState(lua_State * L)1391 int LuaUnsyncedCtrl::SetModelLightTrackingState(lua_State* L)
1392 {
1393 if (CLuaHandle::GetHandleSynced(L) || !CLuaHandle::GetHandleFullRead(L)) {
1394 return 0;
1395 }
1396 if (!lua_isnumber(L, 2)) {
1397 luaL_error(L, "[%s] 1st and 2nd arguments should be numbers, 3rd and 4th should be booleans", __FUNCTION__);
1398 return 0;
1399 }
1400
1401 const unsigned int lightHandle = luaL_checkint(L, 1);
1402 const bool trackEnable = luaL_optboolean(L, 3, true);
1403 const bool trackUnit = luaL_optboolean(L, 4, true);
1404
1405 GL::LightHandler* lightHandler = unitDrawer->GetLightHandler();
1406 GL::Light* light = (lightHandler != NULL)? lightHandler->GetLight(lightHandle): NULL;
1407 bool ret = false;
1408
1409 if (light != NULL) {
1410 ret = AddLightTrackingTarget(L, light, trackEnable, trackUnit, __FUNCTION__);
1411 }
1412
1413 lua_pushboolean(L, ret);
1414 return 1;
1415 }
1416
1417
1418 /******************************************************************************/
1419
SetMapSquareTexture(lua_State * L)1420 int LuaUnsyncedCtrl::SetMapSquareTexture(lua_State* L)
1421 {
1422 if (CLuaHandle::GetHandleSynced(L)) {
1423 return 0;
1424 }
1425
1426 const int texSquareX = luaL_checkint(L, 1);
1427 const int texSquareY = luaL_checkint(L, 2);
1428 const std::string& texName = luaL_checkstring(L, 3);
1429
1430 CBaseGroundDrawer* groundDrawer = readMap->GetGroundDrawer();
1431 CBaseGroundTextures* groundTextures = groundDrawer->GetGroundTextures();
1432
1433 if (groundTextures == NULL) {
1434 lua_pushboolean(L, false);
1435 return 1;
1436 }
1437 if (texName.empty()) {
1438 // restore default texture for this square
1439 lua_pushboolean(L, groundTextures->SetSquareLuaTexture(texSquareX, texSquareY, 0));
1440 return 1;
1441 }
1442
1443 // TODO: leaking ID's like this means we need to guard against texture deletion
1444 const LuaTextures& luaTextures = CLuaHandle::GetActiveTextures(L);
1445 const LuaTextures::Texture* luaTexture = luaTextures.GetInfo(texName);
1446 const CNamedTextures::TexInfo* namedTexture = CNamedTextures::GetInfo(texName);
1447
1448 if (luaTexture != NULL) {
1449 if (luaTexture->xsize != luaTexture->ysize) {
1450 // square textures only
1451 lua_pushboolean(L, false);
1452 return 1;
1453 }
1454
1455 lua_pushboolean(L, groundTextures->SetSquareLuaTexture(texSquareX, texSquareY, luaTexture->id));
1456 return 1;
1457 }
1458
1459 if (namedTexture != NULL) {
1460 if (namedTexture->xsize != namedTexture->ysize) {
1461 // square textures only
1462 lua_pushboolean(L, false);
1463 return 1;
1464 }
1465
1466 lua_pushboolean(L, groundTextures->SetSquareLuaTexture(texSquareX, texSquareY, namedTexture->id));
1467 return 1;
1468 }
1469
1470 lua_pushboolean(L, false);
1471 return 1;
1472 }
1473
1474 /******************************************************************************/
1475
SetUnitNoDraw(lua_State * L)1476 int LuaUnsyncedCtrl::SetUnitNoDraw(lua_State* L)
1477 {
1478 if (CLuaHandle::GetHandleUserMode(L)) {
1479 return 0;
1480 }
1481 CUnit* unit = ParseCtrlUnit(L, __FUNCTION__, 1);
1482 if (unit == NULL) {
1483 return 0;
1484 }
1485 unit->noDraw = luaL_checkboolean(L, 2);
1486 return 0;
1487 }
1488
1489
SetUnitNoMinimap(lua_State * L)1490 int LuaUnsyncedCtrl::SetUnitNoMinimap(lua_State* L)
1491 {
1492 if (CLuaHandle::GetHandleUserMode(L)) {
1493 return 0;
1494 }
1495 CUnit* unit = ParseCtrlUnit(L, __FUNCTION__, 1);
1496 if (unit == NULL) {
1497 return 0;
1498 }
1499 unit->noMinimap = luaL_checkboolean(L, 2);
1500 return 0;
1501 }
1502
1503
SetUnitNoSelect(lua_State * L)1504 int LuaUnsyncedCtrl::SetUnitNoSelect(lua_State* L)
1505 {
1506 if (CLuaHandle::GetHandleUserMode(L)) {
1507 return 0;
1508 }
1509 CUnit* unit = ParseCtrlUnit(L, __FUNCTION__, 1);
1510 if (unit == NULL) {
1511 return 0;
1512 }
1513 unit->noSelect = luaL_checkboolean(L, 2);
1514
1515 // deselect the unit if it's selected and shouldn't be
1516 if (unit->noSelect) {
1517 const CUnitSet& selUnits = selectedUnitsHandler.selectedUnits;
1518 if (selUnits.find(unit) != selUnits.end()) {
1519 selectedUnitsHandler.RemoveUnit(unit);
1520 }
1521 }
1522 return 0;
1523 }
1524
1525
SetUnitLeaveTracks(lua_State * L)1526 int LuaUnsyncedCtrl::SetUnitLeaveTracks(lua_State* L)
1527 {
1528 CUnit* unit = ParseCtrlUnit(L, __FUNCTION__, 1);
1529 if (unit == NULL) {
1530 return 0;
1531 }
1532
1533 unit->leaveTracks = lua_toboolean(L, 2);
1534 return 0;
1535 }
1536
1537
1538 /******************************************************************************/
1539
AddUnitIcon(lua_State * L)1540 int LuaUnsyncedCtrl::AddUnitIcon(lua_State* L)
1541 {
1542 if (CLuaHandle::GetHandleSynced(L)) {
1543 return 0;
1544 }
1545 const string iconName = luaL_checkstring(L, 1);
1546 const string texName = luaL_checkstring(L, 2);
1547 const float size = luaL_optnumber(L, 3, 1.0f);
1548 const float dist = luaL_optnumber(L, 4, 1.0f);
1549 const bool radAdjust = luaL_optboolean(L, 5, false);
1550 lua_pushboolean(L, icon::iconHandler->AddIcon(iconName, texName,
1551 size, dist, radAdjust));
1552 return 1;
1553 }
1554
1555
FreeUnitIcon(lua_State * L)1556 int LuaUnsyncedCtrl::FreeUnitIcon(lua_State* L)
1557 {
1558 if (CLuaHandle::GetHandleSynced(L)) {
1559 return 0;
1560 }
1561 const string iconName = luaL_checkstring(L, 1);
1562 lua_pushboolean(L, icon::iconHandler->FreeIcon(iconName));
1563 return 1;
1564 }
1565
1566
1567 /******************************************************************************/
1568
1569 // TODO: move this to LuaVFS?
ExtractModArchiveFile(lua_State * L)1570 int LuaUnsyncedCtrl::ExtractModArchiveFile(lua_State* L)
1571 {
1572 if (!CLuaHandle::CheckModUICtrl(L)) {
1573 return 0;
1574 }
1575
1576 const string path = luaL_checkstring(L, 1);
1577
1578 CFileHandler fhVFS(path, SPRING_VFS_MOD);
1579 CFileHandler fhRAW(path, SPRING_VFS_RAW);
1580
1581 if (!fhVFS.FileExists()) {
1582 luaL_error(L, "file \"%s\" not found in mod archive", path.c_str());
1583 return 0;
1584 }
1585
1586 if (fhRAW.FileExists()) {
1587 luaL_error(L, "cannot extract file \"%s\": already exists", path.c_str());
1588 return 0;
1589 }
1590
1591
1592 string dname = FileSystem::GetDirectory(path);
1593 string fname = FileSystem::GetFilename(path);
1594
1595 #ifdef WIN32
1596 const size_t s = dname.size();
1597 // get rid of any trailing slashes (CreateDirectory()
1598 // fails on at least XP and Vista if they are present,
1599 // ie. it creates the dir but actually returns false)
1600 if ((s > 0) && ((dname[s - 1] == '/') || (dname[s - 1] == '\\'))) {
1601 dname = dname.substr(0, s - 1);
1602 }
1603 #endif
1604
1605 if (!dname.empty() && !FileSystem::CreateDirectory(dname)) {
1606 luaL_error(L, "Could not create directory \"%s\" for file \"%s\"",
1607 dname.c_str(), fname.c_str());
1608 }
1609
1610 const int numBytes = fhVFS.FileSize();
1611 char* buffer = new char[numBytes];
1612
1613 fhVFS.Read(buffer, numBytes);
1614
1615 std::fstream fstr(path.c_str(), std::ios::out | std::ios::binary);
1616 fstr.write((const char*) buffer, numBytes);
1617 fstr.close();
1618
1619 if (!dname.empty()) {
1620 LOG("Extracted file \"%s\" to directory \"%s\"",
1621 fname.c_str(), dname.c_str());
1622 } else {
1623 LOG("Extracted file \"%s\"", fname.c_str());
1624 }
1625
1626 delete[] buffer;
1627
1628 lua_pushboolean(L, true);
1629 return 1;
1630 }
1631
1632
1633 /******************************************************************************/
1634 /******************************************************************************/
1635 //
1636 // moved from LuaUI
1637 //
1638 /******************************************************************************/
1639 /******************************************************************************/
1640
1641
SendCommands(lua_State * L)1642 int LuaUnsyncedCtrl::SendCommands(lua_State* L)
1643 {
1644 if (!CLuaHandle::CheckModUICtrl(L)) {
1645 return 0;
1646 }
1647 if ((guihandler == NULL) || gs->noHelperAIs) {
1648 return 0;
1649 }
1650
1651 vector<string> cmds;
1652
1653 if (lua_istable(L, 1)) { // old style -- table
1654 const int table = 1;
1655 for (lua_pushnil(L); lua_next(L, table) != 0; lua_pop(L, 1)) {
1656 if (lua_israwstring(L, -1)) {
1657 string action = lua_tostring(L, -1);
1658 if (action[0] != '@') {
1659 action = "@@" + action;
1660 }
1661 cmds.push_back(action);
1662 }
1663 }
1664 }
1665 else if (lua_israwstring(L, 1)) { // new style -- function parameters
1666 for (int i = 1; lua_israwstring(L, i); i++) {
1667 string action = lua_tostring(L, i);
1668 if (action[0] != '@') {
1669 action = "@@" + action;
1670 }
1671 cmds.push_back(action);
1672 }
1673 }
1674 else {
1675 luaL_error(L, "Incorrect arguments to SendCommands()");
1676 }
1677
1678 lua_settop(L, 0); // pop the input arguments
1679
1680 configHandler->EnableWriting(globalConfig->luaWritableConfigFile);
1681 guihandler->RunCustomCommands(cmds, false);
1682 configHandler->EnableWriting(true);
1683
1684 return 0;
1685 }
1686
1687
1688 /******************************************************************************/
1689
SetActiveCommandByIndex(lua_State * L)1690 static int SetActiveCommandByIndex(lua_State* L)
1691 {
1692 if (!CLuaHandle::CheckModUICtrl(L)) {
1693 return 0;
1694 }
1695 if (guihandler == NULL) {
1696 return 0;
1697 }
1698 const int args = lua_gettop(L); // number of arguments
1699 const int cmdIndex = lua_toint(L, 1) - CMD_INDEX_OFFSET;
1700 int button = luaL_optint(L, 2, 1); // LMB
1701
1702 if (args <= 2) {
1703 const bool rmb = (button == SDL_BUTTON_LEFT) ? false : true;
1704 const bool success = guihandler->SetActiveCommand(cmdIndex, rmb);
1705 lua_pushboolean(L, success);
1706 return 1;
1707 }
1708
1709 const bool lmb = luaL_checkboolean(L, 3);
1710 const bool rmb = luaL_checkboolean(L, 4);
1711 const bool alt = luaL_checkboolean(L, 5);
1712 const bool ctrl = luaL_checkboolean(L, 6);
1713 const bool meta = luaL_checkboolean(L, 7);
1714 const bool shift = luaL_checkboolean(L, 8);
1715
1716 const bool success = guihandler->SetActiveCommand(cmdIndex, button, lmb, rmb,
1717 alt, ctrl, meta, shift);
1718 lua_pushboolean(L, success);
1719 return 1;
1720 }
1721
1722
SetActiveCommandByAction(lua_State * L)1723 static int SetActiveCommandByAction(lua_State* L)
1724 {
1725 if (!CLuaHandle::CheckModUICtrl(L)) {
1726 return 0;
1727 }
1728 if (guihandler == NULL) {
1729 return 0;
1730 }
1731 const int args = lua_gettop(L); // number of arguments
1732 const string text = lua_tostring(L, 1);
1733 const Action action(text);
1734 CKeySet ks;
1735 if (args >= 2) {
1736 const string ksText = lua_tostring(L, 2);
1737 ks.Parse(ksText);
1738 }
1739 const bool success = guihandler->SetActiveCommand(action, ks, 0);
1740 lua_pushboolean(L, success);
1741 return 1;
1742 }
1743
1744
SetActiveCommand(lua_State * L)1745 int LuaUnsyncedCtrl::SetActiveCommand(lua_State* L)
1746 {
1747 if (!CLuaHandle::CheckModUICtrl(L)) {
1748 return 0;
1749 }
1750 if (guihandler == NULL) {
1751 return 0;
1752 }
1753 const int args = lua_gettop(L); // number of arguments
1754 if (args < 1) {
1755 luaL_error(L, "Incorrect arguments to SetActiveCommand()");
1756 }
1757 if (lua_isnumber(L, 1)) {
1758 return SetActiveCommandByIndex(L);
1759 }
1760 if (lua_isstring(L, 1)) {
1761 return SetActiveCommandByAction(L);
1762 }
1763 luaL_error(L, "Incorrect arguments to SetActiveCommand()");
1764 return 0;
1765 }
1766
1767
LoadCmdColorsConfig(lua_State * L)1768 int LuaUnsyncedCtrl::LoadCmdColorsConfig(lua_State* L)
1769 {
1770 if (!CLuaHandle::CheckModUICtrl(L)) {
1771 return 0;
1772 }
1773 const string cfg = luaL_checkstring(L, 1);
1774 cmdColors.LoadConfigFromString(cfg);
1775 return 0;
1776 }
1777
1778
LoadCtrlPanelConfig(lua_State * L)1779 int LuaUnsyncedCtrl::LoadCtrlPanelConfig(lua_State* L)
1780 {
1781 if (!CLuaHandle::CheckModUICtrl(L)) {
1782 return 0;
1783 }
1784 if (guihandler == NULL) {
1785 return 0;
1786 }
1787 const string cfg = luaL_checkstring(L, 1);
1788 guihandler->ReloadConfigFromString(cfg);
1789 return 0;
1790 }
1791
1792
ForceLayoutUpdate(lua_State * L)1793 int LuaUnsyncedCtrl::ForceLayoutUpdate(lua_State* L)
1794 {
1795 if (!CLuaHandle::CheckModUICtrl(L)) {
1796 return 0;
1797 }
1798 if (guihandler == NULL) {
1799 return 0;
1800 }
1801 guihandler->ForceLayoutUpdate();
1802 return 0;
1803 }
1804
1805
1806 /******************************************************************************/
1807
WarpMouse(lua_State * L)1808 int LuaUnsyncedCtrl::WarpMouse(lua_State* L)
1809 {
1810 if (!CLuaHandle::CheckModUICtrl(L)) {
1811 return 0;
1812 }
1813 const int x = luaL_checkint(L, 1);
1814 const int y = globalRendering->viewSizeY - luaL_checkint(L, 2) - 1;
1815 mouse->WarpMouse(x, y);
1816 return 0;
1817 }
1818
1819
SetMouseCursor(lua_State * L)1820 int LuaUnsyncedCtrl::SetMouseCursor(lua_State* L)
1821 {
1822 if (!CLuaHandle::CheckModUICtrl(L)) {
1823 return 0;
1824 }
1825
1826 const std::string& cursorName = luaL_checkstring(L, 1);
1827 const float cursorScale = luaL_optfloat(L, 2, 1.0f);
1828
1829 mouse->ChangeCursor(cursorName, cursorScale);
1830
1831 return 0;
1832 }
1833
1834 /******************************************************************************/
1835
SetClipboard(lua_State * L)1836 int LuaUnsyncedCtrl::SetClipboard(lua_State* L)
1837 {
1838 if (!CLuaHandle::CheckModUICtrl(L)) {
1839 return 0;
1840 }
1841
1842 SDL_SetClipboardText(luaL_checkstring(L, 1));
1843 return 0;
1844 }
1845
1846 /******************************************************************************/
1847
SetCameraOffset(lua_State * L)1848 int LuaUnsyncedCtrl::SetCameraOffset(lua_State* L)
1849 {
1850 if (!CLuaHandle::CheckModUICtrl(L)) {
1851 return 0;
1852 }
1853 if (camera == NULL) {
1854 return 0;
1855 }
1856
1857 camera->posOffset.x = luaL_optfloat(L, 1, 0.0f);
1858 camera->posOffset.y = luaL_optfloat(L, 2, 0.0f);
1859 camera->posOffset.z = luaL_optfloat(L, 3, 0.0f);
1860 camera->tiltOffset.x = luaL_optfloat(L, 4, 0.0f);
1861 camera->tiltOffset.y = luaL_optfloat(L, 5, 0.0f);
1862 camera->tiltOffset.z = luaL_optfloat(L, 6, 0.0f);
1863
1864 return 0;
1865 }
1866
1867
1868 /******************************************************************************/
1869
UpdateInfoTexture(lua_State * L)1870 int LuaUnsyncedCtrl::UpdateInfoTexture(lua_State* L)
1871 {
1872 const int rawMode = CBaseGroundDrawer::BaseGroundDrawMode(luaL_checkint(L, 1));
1873 const int texMode = Clamp(rawMode, int(CBaseGroundDrawer::drawLos), int(CBaseGroundDrawer::drawPathCost));
1874
1875 CBaseGroundDrawer* gd = readMap->GetGroundDrawer();
1876
1877 if (gd->GetDrawMode() == CBaseGroundDrawer::drawNormal) {
1878 // allow background updates only when no infotex is active
1879 lua_pushboolean(L, gd->UpdateExtraTexture(texMode));
1880 } else {
1881 lua_pushboolean(L, false);
1882 }
1883
1884 return 1;
1885 }
1886
SetLosViewColors(lua_State * L)1887 int LuaUnsyncedCtrl::SetLosViewColors(lua_State* L)
1888 {
1889 float red[4];
1890 float green[4];
1891 float blue[4];
1892 if ((LuaUtils::ParseFloatArray(L, 1, red, 4) != 4) ||
1893 (LuaUtils::ParseFloatArray(L, 2, green, 4) != 4) ||
1894 (LuaUtils::ParseFloatArray(L, 3, blue, 4) != 4)) {
1895 luaL_error(L, "Incorrect arguments to SetLosViewColors()");
1896 }
1897 const int scale = CBaseGroundDrawer::losColorScale;
1898
1899 CBaseGroundDrawer* gd = readMap->GetGroundDrawer();
1900 gd->alwaysColor[0] = (int)(scale * red[0]);
1901 gd->alwaysColor[1] = (int)(scale * green[0]);
1902 gd->alwaysColor[2] = (int)(scale * blue[0]);
1903 gd->losColor[0] = (int)(scale * red[1]);
1904 gd->losColor[1] = (int)(scale * green[1]);
1905 gd->losColor[2] = (int)(scale * blue[1]);
1906 gd->radarColor[0] = (int)(scale * red[2]);
1907 gd->radarColor[1] = (int)(scale * green[2]);
1908 gd->radarColor[2] = (int)(scale * blue[2]);
1909 gd->jamColor[0] = (int)(scale * red[3]);
1910 gd->jamColor[1] = (int)(scale * green[3]);
1911 gd->jamColor[2] = (int)(scale * blue[3]);
1912 return 0;
1913 }
1914
1915
1916 /******************************************************************************/
1917 /******************************************************************************/
1918
1919 #define SET_IN_OVERLAY_WARNING \
1920 if (lua_isboolean(L, 3)) { \
1921 static bool shown = false; \
1922 if (!shown) { \
1923 LOG_L(L_WARNING, "%s: third parameter \"setInOverlay\" is deprecated", __FUNCTION__); \
1924 shown = true; \
1925 } \
1926 }
1927
GetConfigInt(lua_State * L)1928 int LuaUnsyncedCtrl::GetConfigInt(lua_State* L)
1929 {
1930 if (!CLuaHandle::CheckModUICtrl(L)) {
1931 // FIXME: why not put this in UnsyncedRead without the ModUICtrl restriction?
1932 lua_pushnumber(L, 0);
1933 return 1;
1934 }
1935 const string name = luaL_checkstring(L, 1);
1936 const int def = luaL_optint(L, 2, 0);
1937 SET_IN_OVERLAY_WARNING;
1938 const int value = configHandler->IsSet(name) ? configHandler->GetInt(name) : def;
1939 lua_pushnumber(L, value);
1940 return 1;
1941 }
1942
SetConfigInt(lua_State * L)1943 int LuaUnsyncedCtrl::SetConfigInt(lua_State* L)
1944 {
1945 if (!CLuaHandle::CheckModUICtrl(L)) {
1946 return 0;
1947 }
1948 const string name = luaL_checkstring(L, 1);
1949 const int value = luaL_checkint(L, 2);
1950 const bool useOverlay = luaL_optboolean(L, 3, false);
1951 // don't allow to change a read-only variable
1952 if (configHandler->IsReadOnly(name)) {
1953 LOG_L(L_ERROR, "tried to set readonly (int) %s = %d", name.c_str(), value);
1954 return 0;
1955 }
1956 configHandler->EnableWriting(globalConfig->luaWritableConfigFile);
1957 configHandler->Set(name, value, useOverlay);
1958 configHandler->EnableWriting(true);
1959 return 0;
1960 }
1961
GetConfigString(lua_State * L)1962 int LuaUnsyncedCtrl::GetConfigString(lua_State* L)
1963 {
1964 if (!CLuaHandle::CheckModUICtrl(L)) {
1965 // FIXME: why not put this in UnsyncedRead without the ModUICtrl restriction?
1966 lua_pushstring(L, "");
1967 return 1;
1968 }
1969 const string name = luaL_checkstring(L, 1);
1970 const string def = luaL_optstring(L, 2, "");
1971 SET_IN_OVERLAY_WARNING;
1972 const string value = configHandler->IsSet(name) ? configHandler->GetString(name) : def;
1973 lua_pushsstring(L, value);
1974 return 1;
1975 }
1976
1977
SetConfigString(lua_State * L)1978 int LuaUnsyncedCtrl::SetConfigString(lua_State* L)
1979 {
1980 if (!CLuaHandle::CheckModUICtrl(L)) {
1981 return 0;
1982 }
1983 const string name = luaL_checkstring(L, 1);
1984 const string value = luaL_checkstring(L, 2);
1985 const bool useOverlay = luaL_optboolean(L, 3, false);
1986 // don't allow to change a read-only variable
1987 if (configHandler->IsReadOnly(name)) {
1988 LOG_L(L_ERROR, "tried to set readonly (string) %s = %s", name.c_str(), value.c_str());
1989 return 0;
1990 }
1991 configHandler->EnableWriting(globalConfig->luaWritableConfigFile);
1992 configHandler->SetString(name, value, useOverlay);
1993 configHandler->EnableWriting(true);
1994 return 0;
1995 }
1996
1997
1998 /******************************************************************************/
1999
CreateDir(lua_State * L)2000 int LuaUnsyncedCtrl::CreateDir(lua_State* L)
2001 {
2002 if (!CLuaHandle::CheckModUICtrl(L)) {
2003 return 0;
2004 }
2005 const string dir = luaL_checkstring(L, 1);
2006
2007 // keep directories within the Spring directory
2008 if ((dir[0] == '/') || (dir[0] == '\\') ||
2009 (strstr(dir.c_str(), "..") != NULL) ||
2010 ((dir.size() > 0) && (dir[1] == ':'))) {
2011 luaL_error(L, "Invalid CreateDir() access: %s", dir.c_str());
2012 }
2013 const bool success = FileSystem::CreateDirectory(dir);
2014 lua_pushboolean(L, success);
2015 return 1;
2016 }
2017
2018
2019 /******************************************************************************/
2020
Restart(lua_State * L)2021 int LuaUnsyncedCtrl::Restart(lua_State* L)
2022 {
2023 const std::string springArguments = luaL_checkstring(L, 1);
2024 const std::string scriptContents = luaL_checkstring(L, 2);
2025
2026 const std::string springFullName = Platform::GetProcessExecutableFile();
2027 const std::string scriptFullName = dataDirLocater.GetWriteDirPath() + "script.txt";
2028
2029 std::vector<std::string> processArgs;
2030
2031 // arguments to Spring binary given by Lua code, if any
2032 if (!springArguments.empty()) {
2033 processArgs.push_back(springArguments);
2034 }
2035
2036 if (!scriptContents.empty()) {
2037 // create file 'script.txt' with contents given by Lua code
2038 std::ofstream scriptFile(scriptFullName.c_str());
2039
2040 scriptFile.write(scriptContents.c_str(), scriptContents.size());
2041 scriptFile.close();
2042
2043 processArgs.push_back(scriptFullName);
2044 }
2045
2046 LOG("[Spring.%s] Spring \"%s\" should be restarting", __FUNCTION__, springFullName.c_str());
2047
2048 #ifdef _WIN32
2049 // else OpenAL crashes when using execvp
2050 ISound::Shutdown();
2051 #endif
2052
2053 Platform::ExecuteProcess(springFullName, processArgs);
2054
2055 // not reached on success
2056 lua_pushboolean(L, false);
2057 return 1;
2058 }
2059
SetWMIcon(lua_State * L)2060 int LuaUnsyncedCtrl::SetWMIcon(lua_State* L)
2061 {
2062 const std::string iconFileName = luaL_checksstring(L, 1);
2063
2064 CBitmap iconTexture;
2065 const bool loaded = iconTexture.Load(iconFileName);
2066 if (loaded) {
2067 WindowManagerHelper::SetIcon(&iconTexture);
2068 } else {
2069 luaL_error(L, "Failed to load image from file \"%s\"", iconFileName.c_str());
2070 }
2071
2072 return 0;
2073 }
2074
SetWMCaption(lua_State * L)2075 int LuaUnsyncedCtrl::SetWMCaption(lua_State* L)
2076 {
2077 const std::string title = luaL_checksstring(L, 1);
2078 WindowManagerHelper::SetCaption(title);
2079 return 0;
2080 }
2081
2082 /******************************************************************************/
2083
SetUnitDefIcon(lua_State * L)2084 int LuaUnsyncedCtrl::SetUnitDefIcon(lua_State* L)
2085 {
2086 if (!CLuaHandle::CheckModUICtrl(L)) {
2087 return 0;
2088 }
2089
2090 const int unitDefID = luaL_checkint(L, 1);
2091 const UnitDef* ud = unitDefHandler->GetUnitDefByID(unitDefID);
2092 if (ud == NULL) {
2093 return 0;
2094 }
2095
2096 ud->iconType = icon::iconHandler->GetIcon(luaL_checksstring(L, 2));
2097
2098 // set decoys to the same icon
2099 std::map<int, std::set<int> >::const_iterator fit;
2100
2101 if (ud->decoyDef) {
2102 ud->decoyDef->iconType = ud->iconType;
2103 fit = unitDefHandler->decoyMap.find(ud->decoyDef->id);
2104 } else {
2105 fit = unitDefHandler->decoyMap.find(ud->id);
2106 }
2107 if (fit != unitDefHandler->decoyMap.end()) {
2108 const std::set<int>& decoySet = fit->second;
2109 std::set<int>::const_iterator dit;
2110 for (dit = decoySet.begin(); dit != decoySet.end(); ++dit) {
2111 const UnitDef* decoyDef = unitDefHandler->GetUnitDefByID(*dit);
2112 decoyDef->iconType = ud->iconType;
2113 }
2114 }
2115
2116 return 0;
2117 }
2118
2119
SetUnitDefImage(lua_State * L)2120 int LuaUnsyncedCtrl::SetUnitDefImage(lua_State* L)
2121 {
2122 if (!CLuaHandle::CheckModUICtrl(L)) {
2123 return 0;
2124 }
2125
2126 const int unitDefID = luaL_checkint(L, 1);
2127 const UnitDef* ud = unitDefHandler->GetUnitDefByID(unitDefID);
2128 if (ud == NULL) {
2129 return 0;
2130 }
2131
2132 if (lua_isnoneornil(L, 2)) {
2133 // reset to default texture
2134 unitDefHandler->SetUnitDefImage(ud, ud->buildPicName);
2135 return 0;
2136 }
2137
2138 if (!lua_israwstring(L, 2)) {
2139 return 0;
2140 }
2141 const string texName = lua_tostring(L, 2);
2142
2143 if (texName[0] == LuaTextures::prefix) { // '!'
2144 LuaTextures& textures = CLuaHandle::GetActiveTextures(L);
2145 const LuaTextures::Texture* tex = textures.GetInfo(texName);
2146 if (tex == NULL) {
2147 return 0;
2148 }
2149 unitDefHandler->SetUnitDefImage(ud, tex->id, tex->xsize, tex->ysize);
2150 } else {
2151 unitDefHandler->SetUnitDefImage(ud, texName);
2152 }
2153 return 0;
2154 }
2155
2156
2157 /******************************************************************************/
2158
SetUnitGroup(lua_State * L)2159 int LuaUnsyncedCtrl::SetUnitGroup(lua_State* L)
2160 {
2161 if (!CLuaHandle::CheckModUICtrl(L)) {
2162 return 0;
2163 }
2164 if (gs->noHelperAIs) {
2165 return 0;
2166 }
2167
2168 CUnit* unit = ParseRawUnit(L, __FUNCTION__, 1);
2169 if (unit == NULL) {
2170 return 0;
2171 }
2172 const int groupID = luaL_checkint(L, 2);
2173
2174 if (groupID == -1) {
2175 unit->SetGroup(NULL);
2176 return 0;
2177 }
2178
2179 const vector<CGroup*>& groups = grouphandlers[gu->myTeam]->groups;
2180 if ((groupID < 0) || (groupID >= (int)groups.size())) {
2181 return 0;
2182 }
2183
2184 CGroup* group = groups[groupID];
2185 if (group != NULL) {
2186 unit->SetGroup(group);
2187 }
2188 return 0;
2189 }
2190
2191
2192 /******************************************************************************/
2193
ParseUnitMap(lua_State * L,const char * caller,int table,vector<int> & unitIDs)2194 static void ParseUnitMap(lua_State* L, const char* caller,
2195 int table, vector<int>& unitIDs)
2196 {
2197 if (!lua_istable(L, table)) {
2198 luaL_error(L, "%s(): error parsing unit map", caller);
2199 }
2200 for (lua_pushnil(L); lua_next(L, table) != 0; lua_pop(L, 1)) {
2201 if (lua_israwnumber(L, -2)) {
2202 CUnit* unit = ParseCtrlUnit(L, __FUNCTION__, -2); // the key
2203 if (unit != NULL && !unit->noSelect) {
2204 unitIDs.push_back(unit->id);
2205 }
2206 }
2207 }
2208 }
2209
2210
ParseUnitArray(lua_State * L,const char * caller,int table,vector<int> & unitIDs)2211 static void ParseUnitArray(lua_State* L, const char* caller,
2212 int table, vector<int>& unitIDs)
2213 {
2214 if (!lua_istable(L, table)) {
2215 luaL_error(L, "%s(): error parsing unit array", caller);
2216 }
2217 for (lua_pushnil(L); lua_next(L, table) != 0; lua_pop(L, 1)) {
2218 if (lua_israwnumber(L, -2) && lua_isnumber(L, -1)) { // avoid 'n'
2219 CUnit* unit = ParseCtrlUnit(L, __FUNCTION__, -1); // the value
2220 if (unit != NULL && !unit->noSelect) {
2221 unitIDs.push_back(unit->id);
2222 }
2223 }
2224 }
2225 return;
2226 }
2227
2228
2229 /******************************************************************************/
2230
CanGiveOrders(const lua_State * L)2231 static bool CanGiveOrders(const lua_State *L)
2232 {
2233 if (gs->frameNum <= 0) {
2234 return false;
2235 }
2236 if (gs->noHelperAIs) {
2237 return false;
2238 }
2239 if (gs->godMode) {
2240 return true;
2241 }
2242 if (gu->spectating) {
2243 return false;
2244 }
2245 const int ctrlTeam = CLuaHandle::GetHandleCtrlTeam(L);
2246 // FIXME ? (correct? warning / error?)
2247 if ((ctrlTeam != gu->myTeam) || (ctrlTeam < 0)) {
2248 return false;
2249 }
2250 return true;
2251 }
2252
2253
GiveOrder(lua_State * L)2254 int LuaUnsyncedCtrl::GiveOrder(lua_State* L)
2255 {
2256 if (!CLuaHandle::CheckModUICtrl(L)) {
2257 return 0;
2258 }
2259 if (!CanGiveOrders(L)) {
2260 return 1;
2261 }
2262
2263 Command cmd = LuaUtils::ParseCommand(L, __FUNCTION__, 1);
2264
2265 selectedUnitsHandler.GiveCommand(cmd);
2266
2267 lua_pushboolean(L, true);
2268
2269 return 1;
2270 }
2271
2272
GiveOrderToUnit(lua_State * L)2273 int LuaUnsyncedCtrl::GiveOrderToUnit(lua_State* L)
2274 {
2275 if (!CLuaHandle::CheckModUICtrl(L)) {
2276 return 0;
2277 }
2278 if (!CanGiveOrders(L)) {
2279 lua_pushboolean(L, false);
2280 return 1;
2281 }
2282
2283 CUnit* unit = ParseCtrlUnit(L, __FUNCTION__, 1);
2284 if (unit == NULL || unit->noSelect) {
2285 lua_pushboolean(L, false);
2286 return 1;
2287 }
2288
2289 Command cmd = LuaUtils::ParseCommand(L, __FUNCTION__, 2);
2290
2291 net->Send(CBaseNetProtocol::Get().SendAICommand(gu->myPlayerNum, skirmishAIHandler.GetCurrentAIID(), unit->id, cmd.GetID(), cmd.aiCommandId, cmd.options, cmd.params));
2292
2293 lua_pushboolean(L, true);
2294 return 1;
2295 }
2296
2297
GiveOrderToUnitMap(lua_State * L)2298 int LuaUnsyncedCtrl::GiveOrderToUnitMap(lua_State* L)
2299 {
2300 if (!CLuaHandle::CheckModUICtrl(L)) {
2301 return 0;
2302 }
2303 if (!CanGiveOrders(L)) {
2304 lua_pushboolean(L, false);
2305 return 1;
2306 }
2307
2308 // unitIDs
2309 vector<int> unitIDs;
2310 ParseUnitMap(L, __FUNCTION__, 1, unitIDs);
2311 const int count = (int)unitIDs.size();
2312
2313 if (count <= 0) {
2314 lua_pushboolean(L, false);
2315 return 1;
2316 }
2317
2318 Command cmd = LuaUtils::ParseCommand(L, __FUNCTION__, 2);
2319
2320 vector<Command> commands;
2321 commands.push_back(cmd);
2322 selectedUnitsHandler.SendCommandsToUnits(unitIDs, commands);
2323
2324 lua_pushboolean(L, true);
2325 return 1;
2326 }
2327
2328
GiveOrderToUnitArray(lua_State * L)2329 int LuaUnsyncedCtrl::GiveOrderToUnitArray(lua_State* L)
2330 {
2331 if (!CLuaHandle::CheckModUICtrl(L)) {
2332 return 0;
2333 }
2334 if (!CanGiveOrders(L)) {
2335 lua_pushboolean(L, false);
2336 return 1;
2337 }
2338
2339 // unitIDs
2340 vector<int> unitIDs;
2341 ParseUnitArray(L, __FUNCTION__, 1, unitIDs);
2342 const int count = (int)unitIDs.size();
2343
2344 if (count <= 0) {
2345 lua_pushboolean(L, false);
2346 return 1;
2347 }
2348
2349 Command cmd = LuaUtils::ParseCommand(L, __FUNCTION__, 2);
2350
2351 vector<Command> commands;
2352 commands.push_back(cmd);
2353 selectedUnitsHandler.SendCommandsToUnits(unitIDs, commands);
2354
2355 lua_pushboolean(L, true);
2356 return 1;
2357 }
2358
2359
GiveOrderArrayToUnitMap(lua_State * L)2360 int LuaUnsyncedCtrl::GiveOrderArrayToUnitMap(lua_State* L)
2361 {
2362 if (!CLuaHandle::CheckModUICtrl(L)) {
2363 return 0;
2364 }
2365 if (!CanGiveOrders(L)) {
2366 lua_pushboolean(L, false);
2367 return 1;
2368 }
2369
2370 // unitIDs
2371 vector<int> unitIDs;
2372 ParseUnitMap(L, __FUNCTION__, 1, unitIDs);
2373
2374 // commands
2375 vector<Command> commands;
2376 LuaUtils::ParseCommandArray(L, __FUNCTION__, 2, commands);
2377
2378 if (unitIDs.empty() || commands.empty()) {
2379 lua_pushboolean(L, false);
2380 return 1;
2381 }
2382
2383 selectedUnitsHandler.SendCommandsToUnits(unitIDs, commands);
2384
2385 lua_pushboolean(L, true);
2386 return 1;
2387 }
2388
2389
GiveOrderArrayToUnitArray(lua_State * L)2390 int LuaUnsyncedCtrl::GiveOrderArrayToUnitArray(lua_State* L)
2391 {
2392 if (!CLuaHandle::CheckModUICtrl(L)) {
2393 return 0;
2394 }
2395 if (!CanGiveOrders(L)) {
2396 lua_pushboolean(L, false);
2397 return 1;
2398 }
2399
2400 const int args = lua_gettop(L); // number of arguments
2401
2402 // unitIDs
2403 vector<int> unitIDs;
2404 ParseUnitArray(L, __FUNCTION__, 1, unitIDs);
2405
2406 // commands
2407 vector<Command> commands;
2408 LuaUtils::ParseCommandArray(L, __FUNCTION__, 2, commands);
2409
2410 bool pairwise = false;
2411 if (args >= 3)
2412 pairwise = lua_toboolean(L, 3);
2413
2414 if (unitIDs.empty() || commands.empty()) {
2415 lua_pushboolean(L, false);
2416 return 1;
2417 }
2418
2419 selectedUnitsHandler.SendCommandsToUnits(unitIDs, commands, pairwise);
2420
2421 lua_pushboolean(L, true);
2422 return 1;
2423 }
2424
2425
2426 /******************************************************************************/
2427
GetRawMsg(lua_State * L,const char * caller,int index)2428 static string GetRawMsg(lua_State* L, const char* caller, int index)
2429 {
2430 return luaL_checksstring(L, index);
2431 }
2432
2433
SendLuaUIMsg(lua_State * L)2434 int LuaUnsyncedCtrl::SendLuaUIMsg(lua_State* L)
2435 {
2436 if (!CLuaHandle::CheckModUICtrl(L)) {
2437 return 0;
2438 }
2439 const string msg = GetRawMsg(L, __FUNCTION__, 1);
2440 std::vector<boost::uint8_t> data(msg.size());
2441 std::copy(msg.begin(), msg.end(), data.begin());
2442 const string mode = luaL_optstring(L, 2, "");
2443 unsigned char modeNum = 0;
2444 if ((mode == "s") || (mode == "specs")) {
2445 modeNum = 's';
2446 }
2447 else if ((mode == "a") || (mode == "allies")) {
2448 modeNum = 'a';
2449 }
2450 else if (!mode.empty()) {
2451 luaL_error(L, "Unknown SendLuaUIMsg() mode");
2452 }
2453 try {
2454 net->Send(CBaseNetProtocol::Get().SendLuaMsg(gu->myPlayerNum, LUA_HANDLE_ORDER_UI, modeNum, data));
2455 } catch (const netcode::PackPacketException& ex) {
2456 luaL_error(L, "SendLuaUIMsg() packet error: %s", ex.what());
2457 }
2458 return 0;
2459 }
2460
2461
SendLuaGaiaMsg(lua_State * L)2462 int LuaUnsyncedCtrl::SendLuaGaiaMsg(lua_State* L)
2463 {
2464 if (!CLuaHandle::CheckModUICtrl(L)) {
2465 return 0;
2466 }
2467 const string msg = GetRawMsg(L, __FUNCTION__, 1);
2468 std::vector<boost::uint8_t> data(msg.size());
2469 std::copy(msg.begin(), msg.end(), data.begin());
2470 try {
2471 net->Send(CBaseNetProtocol::Get().SendLuaMsg(gu->myPlayerNum, LUA_HANDLE_ORDER_GAIA, 0, data));
2472 } catch (const netcode::PackPacketException& ex) {
2473 luaL_error(L, "SendLuaGaiaMsg() packet error: %s", ex.what());
2474 }
2475 return 0;
2476 }
2477
2478
SendLuaRulesMsg(lua_State * L)2479 int LuaUnsyncedCtrl::SendLuaRulesMsg(lua_State* L)
2480 {
2481 if (!CLuaHandle::CheckModUICtrl(L)) {
2482 return 0;
2483 }
2484 const string msg = GetRawMsg(L, __FUNCTION__, 1);
2485 std::vector<boost::uint8_t> data(msg.size());
2486 std::copy(msg.begin(), msg.end(), data.begin());
2487 try {
2488 net->Send(CBaseNetProtocol::Get().SendLuaMsg(gu->myPlayerNum, LUA_HANDLE_ORDER_RULES, 0, data));
2489 } catch (const netcode::PackPacketException& ex) {
2490 luaL_error(L, "SendLuaRulesMsg() packet error: %s", ex.what());
2491 }
2492 return 0;
2493 }
2494
2495
2496 /******************************************************************************/
2497
SetShareLevel(lua_State * L)2498 int LuaUnsyncedCtrl::SetShareLevel(lua_State* L)
2499 {
2500 if (!CLuaHandle::CheckModUICtrl(L)) {
2501 return 0;
2502 }
2503 if (gu->spectating || gs->noHelperAIs || (gs->frameNum <= 0)) {
2504 return 0;
2505 }
2506
2507 const string shareType = luaL_checksstring(L, 1);
2508 const float shareLevel = max(0.0f, min(1.0f, luaL_checkfloat(L, 2)));
2509
2510 if (shareType == "metal") {
2511 net->Send(CBaseNetProtocol::Get().SendSetShare(gu->myPlayerNum, gu->myTeam, shareLevel, teamHandler->Team(gu->myTeam)->energyShare));
2512 }
2513 else if (shareType == "energy") {
2514 net->Send(CBaseNetProtocol::Get().SendSetShare(gu->myPlayerNum, gu->myTeam, teamHandler->Team(gu->myTeam)->metalShare, shareLevel));
2515 }
2516 else {
2517 LOG_L(L_WARNING, "SetShareLevel() unknown resource: %s", shareType.c_str());
2518 }
2519 return 0;
2520 }
2521
2522
ShareResources(lua_State * L)2523 int LuaUnsyncedCtrl::ShareResources(lua_State* L)
2524 {
2525 if (!CLuaHandle::CheckModUICtrl(L)) {
2526 return 0;
2527 }
2528 if (gu->spectating || gs->noHelperAIs || (gs->frameNum <= 0)) {
2529 return 0;
2530 }
2531
2532 const int args = lua_gettop(L); // number of arguments
2533 if ((args < 2) || !lua_isnumber(L, 1) || !lua_isstring(L, 2) ||
2534 ((args >= 3) && !lua_isnumber(L, 3))) {
2535 luaL_error(L, "Incorrect arguments to ShareResources()");
2536 }
2537 const int teamID = lua_toint(L, 1);
2538 if (!teamHandler->IsValidTeam(teamID)) {
2539 return 0;
2540 }
2541 const CTeam* team = teamHandler->Team(teamID);
2542 if ((team == NULL) || team->isDead) {
2543 return 0;
2544 }
2545 const string& type = lua_tostring(L, 2);
2546 if (type == "units") {
2547 // update the selection, and clear the unit command queues
2548 Command c(CMD_STOP);
2549 selectedUnitsHandler.GiveCommand(c, false);
2550 net->Send(CBaseNetProtocol::Get().SendShare(gu->myPlayerNum, teamID, 1, 0.0f, 0.0f));
2551 selectedUnitsHandler.ClearSelected();
2552 }
2553 else if (args >= 3) {
2554 const float amount = lua_tofloat(L, 3);
2555 if (type == "metal") {
2556 net->Send(CBaseNetProtocol::Get().SendShare(gu->myPlayerNum, teamID, 0, amount, 0.0f));
2557 }
2558 else if (type == "energy") {
2559 net->Send(CBaseNetProtocol::Get().SendShare(gu->myPlayerNum, teamID, 0, 0.0f, amount));
2560 }
2561 }
2562 return 0;
2563 }
2564
2565
2566 /******************************************************************************/
2567 /******************************************************************************/
2568
2569
SetLastMessagePosition(lua_State * L)2570 int LuaUnsyncedCtrl::SetLastMessagePosition(lua_State* L)
2571 {
2572 const float3 pos(luaL_checkfloat(L, 1),
2573 luaL_checkfloat(L, 2),
2574 luaL_checkfloat(L, 3));
2575
2576 eventHandler.LastMessagePosition(pos);
2577
2578 return 0;
2579 }
2580
2581 /******************************************************************************/
2582 /******************************************************************************/
2583
MarkerAddPoint(lua_State * L)2584 int LuaUnsyncedCtrl::MarkerAddPoint(lua_State* L)
2585 {
2586 if (!CLuaHandle::CheckModUICtrl(L)) {
2587 return 0;
2588 }
2589 if (inMapDrawer == NULL) {
2590 return 0;
2591 }
2592 const float3 pos(luaL_checkfloat(L, 1),
2593 luaL_checkfloat(L, 2),
2594 luaL_checkfloat(L, 3));
2595 const string text = luaL_optstring(L, 4, "");
2596 const bool onlyLocal = (lua_isnumber(L, 5)) ? bool(luaL_optnumber(L, 5, 1)) : luaL_optboolean(L, 5, true);
2597
2598 if (onlyLocal) {
2599 inMapDrawerModel->AddPoint(pos, text, gu->myPlayerNum);
2600 } else {
2601 inMapDrawer->SendPoint(pos, text, true);
2602 }
2603
2604 return 0;
2605 }
2606
2607
MarkerAddLine(lua_State * L)2608 int LuaUnsyncedCtrl::MarkerAddLine(lua_State* L)
2609 {
2610 if (!CLuaHandle::CheckModUICtrl(L)) {
2611 return 0;
2612 }
2613 if (inMapDrawer == NULL) {
2614 return 0;
2615 }
2616 const float3 pos1(luaL_checkfloat(L, 1),
2617 luaL_checkfloat(L, 2),
2618 luaL_checkfloat(L, 3));
2619 const float3 pos2(luaL_checkfloat(L, 4),
2620 luaL_checkfloat(L, 5),
2621 luaL_checkfloat(L, 6));
2622 const bool onlyLocal = (lua_isnumber(L, 7)) ? bool(luaL_optnumber(L, 7, 0)) : luaL_optboolean(L, 7, false);
2623
2624 if (onlyLocal) {
2625 inMapDrawerModel->AddLine(pos1, pos2, gu->myPlayerNum);
2626 } else {
2627 inMapDrawer->SendLine(pos1, pos2, true);
2628 }
2629
2630 return 0;
2631 }
2632
2633
MarkerErasePosition(lua_State * L)2634 int LuaUnsyncedCtrl::MarkerErasePosition(lua_State* L)
2635 {
2636 if (!CLuaHandle::CheckModUICtrl(L)) {
2637 return 0;
2638 }
2639 if (inMapDrawer == NULL) {
2640 return 0;
2641 }
2642 const float3 pos(luaL_checkfloat(L, 1),
2643 luaL_checkfloat(L, 2),
2644 luaL_checkfloat(L, 3));
2645
2646 inMapDrawer->SendErase(pos);
2647
2648 return 0;
2649 }
2650
2651
2652 /******************************************************************************/
2653 /******************************************************************************/
2654
SetDrawSelectionInfo(lua_State * L)2655 int LuaUnsyncedCtrl::SetDrawSelectionInfo(lua_State* L)
2656 {
2657 if (!CLuaHandle::CheckModUICtrl(L)) {
2658 return 0;
2659 }
2660
2661 if (guihandler)
2662 guihandler->SetDrawSelectionInfo(luaL_checkboolean(L, 1));
2663
2664 return 0;
2665 }
2666
2667
2668 /******************************************************************************/
2669 /******************************************************************************/
2670
SetBuildSpacing(lua_State * L)2671 int LuaUnsyncedCtrl::SetBuildSpacing(lua_State* L)
2672 {
2673 if (!CLuaHandle::CheckModUICtrl(L)) {
2674 return 0;
2675 }
2676
2677 if (guihandler)
2678 guihandler->SetBuildSpacing(luaL_checkinteger(L, 1));
2679
2680 return 0;
2681 }
2682
SetBuildFacing(lua_State * L)2683 int LuaUnsyncedCtrl::SetBuildFacing(lua_State* L)
2684 {
2685 if (!CLuaHandle::CheckModUICtrl(L)) {
2686 return 0;
2687 }
2688
2689 if (guihandler)
2690 guihandler->SetBuildFacing(luaL_checkint(L, 1));
2691
2692 return 0;
2693 }
2694 /******************************************************************************/
2695 /******************************************************************************/
2696
2697
2698
SetSunParameters(lua_State * L)2699 int LuaUnsyncedCtrl::SetSunParameters(lua_State* L)
2700 {
2701 DynamicSkyLight* dynSkyLight = dynamic_cast<DynamicSkyLight*>(sky->GetLight());
2702
2703 if (dynSkyLight == NULL)
2704 return 0;
2705
2706 const float4 sunDir(luaL_checkfloat(L, 1), luaL_checkfloat(L, 2), luaL_checkfloat(L, 3), luaL_checkfloat(L, 4));
2707 const float startAngle = luaL_checkfloat(L, 5);
2708 const float orbitTime = luaL_checkfloat(L, 6);
2709
2710 dynSkyLight->SetLightParams(sunDir, startAngle, orbitTime);
2711 return 0;
2712 }
2713
SetSunManualControl(lua_State * L)2714 int LuaUnsyncedCtrl::SetSunManualControl(lua_State* L)
2715 {
2716 DynamicSkyLight* dynSkyLight = dynamic_cast<DynamicSkyLight*>(sky->GetLight());
2717
2718 if (dynSkyLight == NULL)
2719 return 0;
2720
2721 dynSkyLight->SetLuaControl(luaL_checkboolean(L, 1));
2722 return 0;
2723 }
2724
SetSunDirection(lua_State * L)2725 int LuaUnsyncedCtrl::SetSunDirection(lua_State* L)
2726 {
2727 DynamicSkyLight* dynSkyLight = dynamic_cast<DynamicSkyLight*>(sky->GetLight());
2728
2729 if (dynSkyLight == NULL)
2730 return 0;
2731 if (!dynSkyLight->GetLuaControl())
2732 return 0;
2733
2734 dynSkyLight->SetLightDir(float3(luaL_checkfloat(L, 1), luaL_checkfloat(L, 2), luaL_checkfloat(L, 3)));
2735 return 0;
2736 }
2737
2738
2739
2740 /******************************************************************************/
2741 /******************************************************************************/
2742
SendSkirmishAIMessage(lua_State * L)2743 int LuaUnsyncedCtrl::SendSkirmishAIMessage(lua_State* L) {
2744 if (CLuaHandle::GetHandleSynced(L)) {
2745 return 0;
2746 }
2747
2748 const int aiTeam = luaL_checkint(L, 1);
2749 const char* inData = luaL_checkstring(L, 2);
2750
2751 std::vector<const char*> outData;
2752
2753 luaL_checkstack(L, 2, __FUNCTION__);
2754 lua_pushboolean(L, eoh->SendLuaMessages(aiTeam, inData, outData));
2755
2756 // push the AI response(s)
2757 lua_createtable(L, outData.size(), 0);
2758 for (unsigned int n = 0; n < outData.size(); n++) {
2759 lua_pushstring(L, outData[n]);
2760 lua_rawseti(L, -2, n + 1);
2761 }
2762
2763 return 2;
2764 }
2765
2766 /******************************************************************************/
2767 /******************************************************************************/
2768
SetLogSectionFilterLevel(lua_State * L)2769 int LuaUnsyncedCtrl::SetLogSectionFilterLevel(lua_State* L) {
2770 int logLevel = LOG_LEVEL_INFO;
2771
2772 if (lua_israwnumber(L, 2)) {
2773 logLevel = lua_tonumber(L, 2);
2774 }
2775 if (lua_isstring(L, 2)) {
2776 const std::string& loglvlstr = StringToLower(lua_tostring(L, 2));
2777
2778 if (loglvlstr == "debug") {
2779 logLevel = LOG_LEVEL_DEBUG;
2780 }
2781 else if (loglvlstr == "info") {
2782 logLevel = LOG_LEVEL_INFO;
2783 }
2784 else if (loglvlstr == "warning") {
2785 logLevel = LOG_LEVEL_WARNING;
2786 }
2787 else if (loglvlstr == "error") {
2788 logLevel = LOG_LEVEL_ERROR;
2789 }
2790 else if (loglvlstr == "fatal") {
2791 logLevel = LOG_LEVEL_FATAL;
2792 }
2793 else {
2794 return luaL_error(L, "Incorrect arguments to Spring.SetLogSectionFilterLevel(logsection, loglevel)");
2795 }
2796 }
2797
2798 log_frontend_register_runtime_section(luaL_checkstring(L, 1), logLevel);
2799 return 0;
2800 }
2801
2802 /******************************************************************************/
2803 /******************************************************************************/
2804
ClearWatchDogTimer(lua_State * L)2805 int LuaUnsyncedCtrl::ClearWatchDogTimer(lua_State* L) {
2806 const int args = lua_gettop(L); // number of arguments
2807
2808 if (args == 0) {
2809 Watchdog::ClearTimer();
2810 } else {
2811 std::string threadname = "main";
2812 if (lua_isstring(L, 1))
2813 threadname = lua_tostring(L, 1);
2814 Watchdog::ClearTimer(threadname);
2815 }
2816
2817 return 0;
2818 }
2819