1 /* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
2
3 #include "LuaUnsyncedRead.h"
4
5 #include "LuaInclude.h"
6 #include "LuaHandle.h"
7 #include "LuaHashString.h"
8 #include "LuaUtils.h"
9 #include "Game/Camera.h"
10 #include "Game/CameraHandler.h"
11 #include "Game/Game.h"
12 #include "Game/GameHelper.h"
13 #include "Game/GameSetup.h"
14 #include "Game/GlobalUnsynced.h"
15 #include "Game/Players/Player.h"
16 #include "Game/Players/PlayerHandler.h"
17 #include "Net/GameServer.h"
18 #include "Game/GUI/PlayerRoster.h"
19 #include "Game/SelectedUnitsHandler.h"
20 #include "Game/TraceRay.h"
21 #include "Game/Camera/CameraController.h"
22 #include "Game/UI/GuiHandler.h"
23 #include "Game/UI/InfoConsole.h"
24 #include "Game/UI/KeyCodes.h"
25 #include "Game/UI/KeySet.h"
26 #include "Game/UI/KeyBindings.h"
27 #include "Game/UI/MiniMap.h"
28 #include "Game/UI/MouseHandler.h"
29 #include "Map/BaseGroundDrawer.h"
30 #include "Map/BaseGroundTextures.h"
31 #include "Map/Ground.h"
32 #include "Map/ReadMap.h"
33 #include "Rendering/GlobalRendering.h"
34 #include "Rendering/IconHandler.h"
35 #include "Rendering/ShadowHandler.h"
36 #include "Rendering/UnitDrawer.h"
37 #include "Rendering/Env/IWater.h"
38 #include "Sim/Features/Feature.h"
39 #include "Sim/Features/FeatureDef.h"
40 #include "Sim/Features/FeatureHandler.h"
41 #include "Sim/Misc/TeamHandler.h"
42 #include "Sim/Misc/QuadField.h"
43 #include "Sim/Projectiles/Projectile.h"
44 #include "Sim/Units/Unit.h"
45 #include "Sim/Units/UnitHandler.h"
46 #include "Sim/Units/UnitTypes/TransportUnit.h"
47 #include "Sim/Units/Groups/Group.h"
48 #include "Sim/Units/Groups/GroupHandler.h"
49 #include "Net/Protocol/NetProtocol.h"
50 #include "System/Config/ConfigVariable.h"
51 #include "System/Input/KeyInput.h"
52 #include "System/FileSystem/FileHandler.h"
53 #include "System/FileSystem/VFSHandler.h"
54 #include "System/FileSystem/FileSystem.h"
55 #include "System/LoadSave/demofile.h"
56 #include "System/LoadSave/DemoReader.h"
57 #include "System/Log/DefaultFilter.h"
58 #include "System/Platform/SDL1_keysym.h"
59 #include "System/Sound/ISoundChannels.h"
60 #include "System/Misc/SpringTime.h"
61
62 #if !defined(HEADLESS) && !defined(NO_SOUND)
63 #include "System/Sound/OpenAL/EFX.h"
64 #include "System/Sound/OpenAL/EFXPresets.h"
65 #endif
66
67 #include <set>
68 #include <list>
69 #include <cctype>
70
71 #include <SDL_clipboard.h>
72 #include <SDL_keycode.h>
73 #include <SDL_mouse.h>
74
75 const int CMD_INDEX_OFFSET = 1; // starting index for command descriptions
76
77 /******************************************************************************/
78 /******************************************************************************/
79
PushEntries(lua_State * L)80 bool LuaUnsyncedRead::PushEntries(lua_State* L)
81 {
82 #define REGISTER_LUA_CFUNC(x) \
83 lua_pushstring(L, #x); \
84 lua_pushcfunction(L, x); \
85 lua_rawset(L, -3)
86
87 #define REGISTER_NAMED_LUA_CFUNC(x,name) \
88 lua_pushstring(L, #name); \
89 lua_pushcfunction(L, x); \
90 lua_rawset(L, -3)
91
92 REGISTER_LUA_CFUNC(IsReplay);
93 REGISTER_LUA_CFUNC(GetReplayLength);
94 REGISTER_LUA_CFUNC(GetModUICtrl);
95
96 REGISTER_LUA_CFUNC(GetDrawFrame);
97 REGISTER_LUA_CFUNC(GetFrameTimeOffset);
98 REGISTER_LUA_CFUNC(GetLastUpdateSeconds);
99 REGISTER_LUA_CFUNC(GetHasLag);
100
101 REGISTER_LUA_CFUNC(GetViewGeometry);
102 REGISTER_LUA_CFUNC(GetWindowGeometry);
103 REGISTER_LUA_CFUNC(GetScreenGeometry);
104 REGISTER_LUA_CFUNC(GetMiniMapGeometry);
105 REGISTER_LUA_CFUNC(GetMiniMapDualScreen);
106 REGISTER_LUA_CFUNC(IsAboveMiniMap);
107 REGISTER_LUA_CFUNC(IsGUIHidden);
108
109 REGISTER_LUA_CFUNC(IsAABBInView);
110 REGISTER_LUA_CFUNC(IsSphereInView);
111
112 REGISTER_LUA_CFUNC(IsUnitAllied);
113 REGISTER_LUA_CFUNC(IsUnitInView);
114 REGISTER_LUA_CFUNC(IsUnitVisible);
115 REGISTER_LUA_CFUNC(IsUnitIcon);
116 REGISTER_LUA_CFUNC(IsUnitSelected);
117
118 REGISTER_LUA_CFUNC(GetUnitLuaDraw);
119 REGISTER_LUA_CFUNC(GetUnitNoDraw);
120 REGISTER_LUA_CFUNC(GetUnitNoMinimap);
121 REGISTER_LUA_CFUNC(GetUnitNoSelect);
122 REGISTER_LUA_CFUNC(GetFeatureLuaDraw);
123
124 REGISTER_LUA_CFUNC(GetUnitTransformMatrix);
125 REGISTER_LUA_CFUNC(GetUnitViewPosition);
126
127 REGISTER_LUA_CFUNC(GetVisibleUnits);
128 REGISTER_LUA_CFUNC(GetVisibleFeatures);
129 REGISTER_LUA_CFUNC(GetVisibleProjectiles);
130
131 REGISTER_LUA_CFUNC(GetTeamColor);
132 REGISTER_LUA_CFUNC(GetTeamOrigColor);
133
134 REGISTER_LUA_CFUNC(GetLocalPlayerID);
135 REGISTER_LUA_CFUNC(GetLocalTeamID);
136 REGISTER_LUA_CFUNC(GetLocalAllyTeamID);
137
138 REGISTER_NAMED_LUA_CFUNC(GetLocalPlayerID, GetMyPlayerID);
139 REGISTER_NAMED_LUA_CFUNC(GetLocalTeamID, GetMyTeamID);
140 REGISTER_NAMED_LUA_CFUNC(GetLocalAllyTeamID, GetMyAllyTeamID);
141
142 REGISTER_LUA_CFUNC(GetSpectatingState);
143
144 REGISTER_LUA_CFUNC(GetSelectedUnits);
145 REGISTER_LUA_CFUNC(GetSelectedUnitsSorted);
146 REGISTER_LUA_CFUNC(GetSelectedUnitsCounts);
147 REGISTER_LUA_CFUNC(GetSelectedUnitsCount);
148
149 REGISTER_LUA_CFUNC(HaveShadows);
150 REGISTER_LUA_CFUNC(HaveAdvShading);
151 REGISTER_LUA_CFUNC(GetWaterMode);
152 REGISTER_LUA_CFUNC(GetMapDrawMode);
153 REGISTER_LUA_CFUNC(GetMapSquareTexture);
154
155 REGISTER_LUA_CFUNC(GetCameraNames);
156 REGISTER_LUA_CFUNC(GetCameraState);
157 REGISTER_LUA_CFUNC(GetCameraPosition);
158 REGISTER_LUA_CFUNC(GetCameraDirection);
159 REGISTER_LUA_CFUNC(GetCameraFOV);
160 REGISTER_LUA_CFUNC(GetCameraVectors);
161 REGISTER_LUA_CFUNC(WorldToScreenCoords);
162 REGISTER_LUA_CFUNC(TraceScreenRay);
163 REGISTER_LUA_CFUNC(GetPixelDir);
164
165 REGISTER_LUA_CFUNC(GetTimer);
166 REGISTER_LUA_CFUNC(DiffTimers);
167
168 REGISTER_LUA_CFUNC(GetSoundStreamTime);
169 REGISTER_LUA_CFUNC(GetSoundEffectParams);
170
171 REGISTER_LUA_CFUNC(GetFPS);
172 REGISTER_LUA_CFUNC(GetGameSpeed);
173
174 REGISTER_LUA_CFUNC(GetActiveCommand);
175 REGISTER_LUA_CFUNC(GetDefaultCommand);
176 REGISTER_LUA_CFUNC(GetActiveCmdDescs);
177 REGISTER_LUA_CFUNC(GetActiveCmdDesc);
178 REGISTER_LUA_CFUNC(GetCmdDescIndex);
179 REGISTER_LUA_CFUNC(GetBuildFacing);
180 REGISTER_LUA_CFUNC(GetBuildSpacing);
181 REGISTER_LUA_CFUNC(GetGatherMode);
182 REGISTER_LUA_CFUNC(GetActivePage);
183
184 REGISTER_LUA_CFUNC(GetMouseState);
185 REGISTER_LUA_CFUNC(GetMouseCursor);
186 REGISTER_LUA_CFUNC(GetMouseStartPosition);
187
188 REGISTER_LUA_CFUNC(GetKeyState);
189 REGISTER_LUA_CFUNC(GetModKeyState);
190 REGISTER_LUA_CFUNC(GetPressedKeys);
191 REGISTER_LUA_CFUNC(GetInvertQueueKey);
192
193 REGISTER_LUA_CFUNC(GetClipboard);
194
195 REGISTER_LUA_CFUNC(GetKeyCode);
196 REGISTER_LUA_CFUNC(GetKeySymbol);
197 REGISTER_LUA_CFUNC(GetKeyBindings);
198 REGISTER_LUA_CFUNC(GetActionHotKeys);
199
200 REGISTER_LUA_CFUNC(GetLastMessagePositions);
201 REGISTER_LUA_CFUNC(GetConsoleBuffer);
202 REGISTER_LUA_CFUNC(GetCurrentTooltip);
203
204 REGISTER_LUA_CFUNC(GetUnitGroup);
205 REGISTER_LUA_CFUNC(GetGroupList);
206 REGISTER_LUA_CFUNC(GetSelectedGroup);
207 REGISTER_LUA_CFUNC(GetGroupUnits);
208 REGISTER_LUA_CFUNC(GetGroupUnitsSorted);
209 REGISTER_LUA_CFUNC(GetGroupUnitsCounts);
210 REGISTER_LUA_CFUNC(GetGroupUnitsCount);
211
212 REGISTER_LUA_CFUNC(GetPlayerRoster);
213 REGISTER_LUA_CFUNC(GetPlayerTraffic);
214 REGISTER_LUA_CFUNC(GetPlayerStatistics);
215
216 REGISTER_LUA_CFUNC(GetDrawSelectionInfo);
217
218 REGISTER_LUA_CFUNC(GetConfigParams);
219 REGISTER_LUA_CFUNC(GetLogSections);
220
221 return true;
222 }
223
224
225 /******************************************************************************/
226 /******************************************************************************/
227 //
228 // Parsing helpers
229 //
230
ParseUnit(lua_State * L,const char * caller,int index)231 static inline CUnit* ParseUnit(lua_State* L, const char* caller, int index)
232 {
233 if (!lua_isnumber(L, index)) {
234 luaL_error(L, "%s(): Bad unitID", caller);
235 return NULL;
236 }
237 const int unitID = lua_toint(L, index);
238 if ((unitID < 0) || (static_cast<size_t>(unitID) >= unitHandler->MaxUnits())) {
239 luaL_error(L, "%s(): Bad unitID: %d\n", caller, unitID);
240 }
241 CUnit* unit = unitHandler->units[unitID];
242 if (unit == NULL) {
243 return NULL;
244 }
245 const int readAllyTeam = CLuaHandle::GetHandleReadAllyTeam(L);
246 if (readAllyTeam < 0) {
247 return CLuaHandle::GetHandleFullRead(L) ? unit : NULL;
248 }
249 if ((unit->losStatus[readAllyTeam] & (LOS_INLOS | LOS_INRADAR)) == 0) {
250 return NULL;
251 }
252 return unit;
253 }
254
ParseFeature(lua_State * L,const char * caller,int index)255 static inline CFeature* ParseFeature(lua_State* L, const char* caller, int index)
256 {
257 if (!lua_isnumber(L, index)) {
258 luaL_error(L, "%s(): Bad featureID", caller);
259 return NULL;
260 }
261 const int featureID = lua_toint(L, index);
262 CFeature* feature = featureHandler->GetFeature(featureID);
263
264 if (CLuaHandle::GetHandleFullRead(L)) { return feature; }
265
266 const int readAllyTeam = CLuaHandle::GetHandleReadAllyTeam(L);
267 if (readAllyTeam < 0) { return NULL; }
268 if (feature == NULL) { return NULL; }
269 if (feature->IsInLosForAllyTeam(readAllyTeam)) { return feature; }
270
271 return NULL;
272 }
273
274
275
276 /******************************************************************************/
277 /******************************************************************************/
278 //
279 // The call-outs
280 //
281
IsReplay(lua_State * L)282 int LuaUnsyncedRead::IsReplay(lua_State* L)
283 {
284 if (gameSetup && gameSetup->hostDemo) {
285 lua_pushboolean(L, true);
286 } else {
287 lua_pushboolean(L, false);
288 }
289 return 1;
290 }
291
292
GetReplayLength(lua_State * L)293 int LuaUnsyncedRead::GetReplayLength(lua_State* L)
294 {
295 if (gameServer && gameServer->GetDemoReader()) {
296 lua_pushnumber(L, gameServer->GetDemoReader()->GetFileHeader().gameTime);
297 return 1;
298 }
299 return 0;
300 }
301
302
GetModUICtrl(lua_State * L)303 int LuaUnsyncedRead::GetModUICtrl(lua_State* L)
304 {
305 lua_pushboolean(L, CLuaHandle::GetModUICtrl());
306 return 1;
307 }
308
309
310 /******************************************************************************/
311
GetViewGeometry(lua_State * L)312 int LuaUnsyncedRead::GetViewGeometry(lua_State* L)
313 {
314 lua_pushnumber(L, globalRendering->viewSizeX);
315 lua_pushnumber(L, globalRendering->viewSizeY);
316 lua_pushnumber(L, globalRendering->viewPosX);
317 lua_pushnumber(L, globalRendering->viewPosY);
318 return 4;
319 }
320
321
GetWindowGeometry(lua_State * L)322 int LuaUnsyncedRead::GetWindowGeometry(lua_State* L)
323 {
324 // origin BOTTOMLEFT
325 const int winPosY_bl = globalRendering->screenSizeY - globalRendering->winSizeY - globalRendering->winPosY;
326
327 lua_pushnumber(L, globalRendering->winSizeX);
328 lua_pushnumber(L, globalRendering->winSizeY);
329 lua_pushnumber(L, globalRendering->winPosX);
330 lua_pushnumber(L, winPosY_bl);
331 return 4;
332 }
333
334
GetScreenGeometry(lua_State * L)335 int LuaUnsyncedRead::GetScreenGeometry(lua_State* L)
336 {
337 lua_pushnumber(L, globalRendering->screenSizeX);
338 lua_pushnumber(L, globalRendering->screenSizeY);
339 lua_pushnumber(L, 0.0f);
340 lua_pushnumber(L, 0.0f);
341 return 4;
342 }
343
344
GetMiniMapGeometry(lua_State * L)345 int LuaUnsyncedRead::GetMiniMapGeometry(lua_State* L)
346 {
347 if (minimap == NULL) {
348 return 0;
349 }
350 lua_pushnumber(L, minimap->GetPosX());
351 lua_pushnumber(L, minimap->GetPosY());
352 lua_pushnumber(L, minimap->GetSizeX());
353 lua_pushnumber(L, minimap->GetSizeY());
354 lua_pushboolean(L, minimap->GetMinimized());
355 lua_pushboolean(L, minimap->GetMaximized());
356
357 return 6;
358 }
359
360
GetMiniMapDualScreen(lua_State * L)361 int LuaUnsyncedRead::GetMiniMapDualScreen(lua_State* L)
362 {
363 if (minimap == NULL) {
364 return 0;
365 }
366 if (!globalRendering->dualScreenMode) {
367 lua_pushboolean(L, false);
368 } else {
369 if (globalRendering->dualScreenMiniMapOnLeft) {
370 lua_pushliteral(L, "left");
371 } else {
372 lua_pushliteral(L, "right");
373 }
374 }
375 return 1;
376 }
377
378
IsAboveMiniMap(lua_State * L)379 int LuaUnsyncedRead::IsAboveMiniMap(lua_State* L)
380 {
381 if (minimap == NULL) {
382 return 0;
383 }
384
385 if (minimap->GetMinimized() || game->hideInterface) {
386 return false;
387 }
388
389 const int x = luaL_checkint(L, 1) + globalRendering->viewPosX;
390 const int y = luaL_checkint(L, 2);
391
392 const int x0 = minimap->GetPosX();
393 const int y0 = minimap->GetPosY();
394 const int x1 = x0 + minimap->GetSizeX();
395 const int y1 = y0 + minimap->GetSizeY();
396
397 lua_pushboolean(L, (x >= x0) && (x < x1) &&
398 (y >= y0) && (y < y1));
399
400 return 1;
401 }
402
403
404 /******************************************************************************/
405
GetDrawFrame(lua_State * L)406 int LuaUnsyncedRead::GetDrawFrame(lua_State* L)
407 {
408 lua_pushnumber(L, globalRendering->drawFrame & 0xFFFF);
409 lua_pushnumber(L, (globalRendering->drawFrame >> 16) & 0xFFFF);
410 return 2;
411 }
412
413
GetFrameTimeOffset(lua_State * L)414 int LuaUnsyncedRead::GetFrameTimeOffset(lua_State* L)
415 {
416 lua_pushnumber(L, globalRendering->timeOffset);
417 return 1;
418 }
419
420
GetLastUpdateSeconds(lua_State * L)421 int LuaUnsyncedRead::GetLastUpdateSeconds(lua_State* L)
422 {
423 lua_pushnumber(L, game->updateDeltaSeconds);
424 return 1;
425 }
426
GetHasLag(lua_State * L)427 int LuaUnsyncedRead::GetHasLag(lua_State* L)
428 {
429 lua_pushboolean(L, (game != NULL)? game->IsLagging(luaL_optfloat(L, 1, 500.0f)) : false);
430 return 1;
431 }
432
IsAABBInView(lua_State * L)433 int LuaUnsyncedRead::IsAABBInView(lua_State* L)
434 {
435 float3 mins = float3(luaL_checkfloat(L, 1),
436 luaL_checkfloat(L, 2),
437 luaL_checkfloat(L, 3));
438 float3 maxs = float3(luaL_checkfloat(L, 4),
439 luaL_checkfloat(L, 5),
440 luaL_checkfloat(L, 6));
441 lua_pushboolean(L, camera->InView(mins, maxs));
442 return 1;
443 }
444
445
IsSphereInView(lua_State * L)446 int LuaUnsyncedRead::IsSphereInView(lua_State* L)
447 {
448 const float3 pos(luaL_checkfloat(L, 1),
449 luaL_checkfloat(L, 2),
450 luaL_checkfloat(L, 3));
451 const float radius = lua_israwnumber(L, 4) ? lua_tofloat(L, 4) : 0.0f;
452
453 lua_pushboolean(L, camera->InView(pos, radius));
454 return 1;
455 }
456
457
IsUnitAllied(lua_State * L)458 int LuaUnsyncedRead::IsUnitAllied(lua_State* L)
459 {
460 CUnit* unit = ParseUnit(L, __FUNCTION__, 1);
461 if (unit == NULL) {
462 return 0;
463 }
464 if (CLuaHandle::GetHandleReadAllyTeam(L) < 0) {
465 lua_pushboolean(L, CLuaHandle::GetHandleFullRead(L));
466 } else {
467 lua_pushboolean(L, (unit->allyteam == CLuaHandle::GetHandleReadAllyTeam(L)));
468 }
469 return 1;
470 }
471
472
IsUnitInView(lua_State * L)473 int LuaUnsyncedRead::IsUnitInView(lua_State* L)
474 {
475 CUnit* unit = ParseUnit(L, __FUNCTION__, 1);
476 if (unit == NULL) {
477 return 0;
478 }
479 lua_pushboolean(L, camera->InView(unit->midPos, unit->radius));
480 return 1;
481 }
482
483
UnitIsIcon(const CUnit * unit)484 static bool UnitIsIcon(const CUnit* unit)
485 {
486 return (unitDrawer->DrawAsIcon(unit, (unit->pos - camera->GetPos()).SqLength()));
487 }
488
489
IsUnitVisible(lua_State * L)490 int LuaUnsyncedRead::IsUnitVisible(lua_State* L)
491 {
492 CUnit* unit = ParseUnit(L, __FUNCTION__, 1);
493 if (unit == NULL) {
494 return 0;
495 }
496 const float radius = luaL_optnumber(L, 2, unit->radius);
497 const bool checkIcon = lua_toboolean(L, 3);
498
499 const int readAllyTeam = CLuaHandle::GetHandleReadAllyTeam(L);
500
501 if (readAllyTeam < 0) {
502 if (!CLuaHandle::GetHandleFullRead(L)) {
503 lua_pushboolean(L, false);
504 } else {
505 lua_pushboolean(L,
506 (!checkIcon || !UnitIsIcon(unit)) &&
507 camera->InView(unit->midPos, radius));
508 }
509 }
510 else {
511 if ((unit->losStatus[readAllyTeam] & LOS_INLOS) == 0) {
512 lua_pushboolean(L, false);
513 } else {
514 lua_pushboolean(L,
515 (!checkIcon || !UnitIsIcon(unit)) &&
516 camera->InView(unit->midPos, radius));
517 }
518 }
519 return 1;
520 }
521
522
IsUnitIcon(lua_State * L)523 int LuaUnsyncedRead::IsUnitIcon(lua_State* L)
524 {
525 CUnit* unit = ParseUnit(L, __FUNCTION__, 1);
526 if (unit == NULL) {
527 return 0;
528 }
529 lua_pushboolean(L, UnitIsIcon(unit));
530 return 1;
531 }
532
533
IsUnitSelected(lua_State * L)534 int LuaUnsyncedRead::IsUnitSelected(lua_State* L)
535 {
536 CUnit* unit = ParseUnit(L, __FUNCTION__, 1);
537 if (unit == NULL) {
538 return 0;
539 }
540 const CUnitSet& selUnits = selectedUnitsHandler.selectedUnits;
541 lua_pushboolean(L, selUnits.find(unit) != selUnits.end());
542 return 1;
543 }
544
545
GetUnitLuaDraw(lua_State * L)546 int LuaUnsyncedRead::GetUnitLuaDraw(lua_State* L)
547 {
548 CUnit* unit = ParseUnit(L, __FUNCTION__, 1);
549 if (unit == NULL) {
550 return 0;
551 }
552 lua_pushboolean(L, unit->luaDraw);
553 return 1;
554 }
555
GetUnitNoDraw(lua_State * L)556 int LuaUnsyncedRead::GetUnitNoDraw(lua_State* L)
557 {
558 CUnit* unit = ParseUnit(L, __FUNCTION__, 1);
559 if (unit == NULL) {
560 return 0;
561 }
562 lua_pushboolean(L, unit->noDraw);
563 return 1;
564 }
565
GetUnitNoMinimap(lua_State * L)566 int LuaUnsyncedRead::GetUnitNoMinimap(lua_State* L)
567 {
568 CUnit* unit = ParseUnit(L, __FUNCTION__, 1);
569 if (unit == NULL) {
570 return 0;
571 }
572 lua_pushboolean(L, unit->noMinimap);
573 return 1;
574 }
575
GetUnitNoSelect(lua_State * L)576 int LuaUnsyncedRead::GetUnitNoSelect(lua_State* L)
577 {
578 CUnit* unit = ParseUnit(L, __FUNCTION__, 1);
579 if (unit == NULL) {
580 return 0;
581 }
582 lua_pushboolean(L, unit->noSelect);
583 return 1;
584 }
585
586
GetFeatureLuaDraw(lua_State * L)587 int LuaUnsyncedRead::GetFeatureLuaDraw(lua_State* L)
588 {
589 CFeature* feature = ParseFeature(L, __FUNCTION__, 1);
590 if (feature == NULL) {
591 return 0;
592 }
593 lua_pushboolean(L, feature->luaDraw);
594 return 1;
595 }
596
597
598
GetUnitTransformMatrix(lua_State * L)599 int LuaUnsyncedRead::GetUnitTransformMatrix(lua_State* L)
600 {
601 CUnit* unit = ParseUnit(L, __FUNCTION__, 1);
602 if (unit == NULL) {
603 return 0;
604 }
605
606 CMatrix44f m = unit->GetTransformMatrix(false, false);
607
608 if (luaL_optboolean(L, 2, false)) {
609 m = m.InvertAffine();
610 }
611
612 for (int i = 0; i < 16; i += 4) {
613 lua_pushnumber(L, m[i ]);
614 lua_pushnumber(L, m[i + 1]);
615 lua_pushnumber(L, m[i + 2]);
616 lua_pushnumber(L, m[i + 3]);
617 }
618
619 return 16;
620 }
621
GetUnitViewPosition(lua_State * L)622 int LuaUnsyncedRead::GetUnitViewPosition(lua_State* L)
623 {
624 CUnit* unit = ParseUnit(L, __FUNCTION__, 1);
625 if (unit == NULL) {
626 return 0;
627 }
628 const bool midPos = luaL_optboolean(L, 2, false);
629
630 float3& pos = midPos ? unit->drawMidPos : unit->drawPos;
631 lua_pushnumber(L, pos.x);
632 lua_pushnumber(L, pos.y);
633 lua_pushnumber(L, pos.z);
634 return 3;
635 }
636
637
638 /******************************************************************************/
639 /******************************************************************************/
640
641 // FIXME -- copied from LuaSyncedRead.cpp, commonize
642 enum UnitAllegiance {
643 AllUnits = -1,
644 MyUnits = -2,
645 AllyUnits = -3,
646 EnemyUnits = -4
647 };
648
649
650 // never instantiated directly
651 template<class T> class CWorldObjectQuadDrawer: public CReadMap::IQuadDrawer {
652 public:
653 typedef std::list<T*> ObjectList;
654 typedef std::vector< const ObjectList* > ObjectVector;
655
Reset()656 void Reset() {
657 objectLists.clear();
658 objectLists.reserve(64);
659
660 objectCount = 0;
661 }
662
GetQuadCount() const663 unsigned int GetQuadCount() const { return (objectLists.size()); }
GetObjectCount() const664 unsigned int GetObjectCount() const { return objectCount; }
665
GetObjectLists()666 const ObjectVector& GetObjectLists() { return objectLists; }
667
AddObjectList(const ObjectList * objects)668 void AddObjectList(const ObjectList* objects) {
669 if (objects->empty())
670 return;
671
672 objectLists.push_back(objects);
673 objectCount += objects->size();
674 }
675
676 protected:
677 // note: stores pointers to lists, not copies
678 // its size equals the number of visible quads
679 ObjectVector objectLists;
680
681 unsigned int objectCount;
682 };
683
684
685 class CVisUnitQuadDrawer: public CWorldObjectQuadDrawer<CUnit> {
686 public:
DrawQuad(int x,int y)687 void DrawQuad(int x, int y) {
688 const CQuadField::Quad& q = quadField->GetQuadAt(x, y);
689 const ObjectList* o = &q.units;
690
691 AddObjectList(o);
692 }
693 };
694
695 class CVisFeatureQuadDrawer: public CWorldObjectQuadDrawer<CFeature> {
696 public:
DrawQuad(int x,int y)697 void DrawQuad(int x, int y) {
698 const CQuadField::Quad& q = quadField->GetQuadAt(x, y);
699 const ObjectList* o = &q.features;
700
701 AddObjectList(o);
702 }
703 };
704
705 class CVisProjectileQuadDrawer: public CWorldObjectQuadDrawer<CProjectile> {
706 public:
DrawQuad(int x,int y)707 void DrawQuad(int x, int y) {
708 const CQuadField::Quad& q = quadField->GetQuadAt(x, y);
709 const ObjectList* o = &q.projectiles;
710
711 AddObjectList(o);
712 }
713 };
714
715
716
717
GetVisibleUnits(lua_State * L)718 int LuaUnsyncedRead::GetVisibleUnits(lua_State* L)
719 {
720 // arg 1 - teamID
721 int teamID = luaL_optint(L, 1, -1);
722 int allyTeamID = CLuaHandle::GetHandleReadAllyTeam(L);
723
724 if (teamID == MyUnits) {
725 const int scriptTeamID = CLuaHandle::GetHandleReadTeam(L);
726
727 if (scriptTeamID >= 0) {
728 teamID = scriptTeamID;
729 } else {
730 teamID = AllUnits;
731 }
732 }
733
734 if (teamID >= 0) {
735 if (!teamHandler->IsValidTeam(teamID))
736 return 0;
737
738 allyTeamID = teamHandler->AllyTeam(teamID);
739 }
740 if (allyTeamID < 0) {
741 if (!CLuaHandle::GetHandleFullRead(L)) {
742 return 0;
743 }
744 }
745
746 // arg 2 - unit radius
747 bool fixedRadius = false;
748 // arg 3 - noIcons
749 const bool noIcons = !luaL_optboolean(L, 3, true);
750
751 float testRadius = WORLDOBJECT_DEFAULT_DRAWRADIUS;
752 const float iconLength = unitDrawer->iconLength;
753
754 if (lua_israwnumber(L, 2)) {
755 testRadius = lua_tofloat(L, 2);
756 fixedRadius = (testRadius < 0.0f);
757 testRadius = std::max(testRadius, -testRadius);
758 }
759
760 vector<const CUnitSet*> unitSets;
761 vector<const CUnitSet*>::const_iterator setIt;
762
763 static CUnitSet visQuadUnits;
764 static CVisUnitQuadDrawer unitQuadIter;
765
766 unsigned int count = 0;
767
768 {
769 unitQuadIter.Reset();
770 readMap->GridVisibility(camera, CQuadField::BASE_QUAD_SIZE / SQUARE_SIZE, 1e9, &unitQuadIter, INT_MAX);
771
772 lua_createtable(L, unitQuadIter.GetObjectCount(), 0);
773
774 // setup the list of unit sets
775 //
776 // if we see nearly all features, it is just faster to
777 // check them all, instead of doing slow duplication checks
778 //
779 // FIXME? one-third != "nearly all"
780 //
781 if (unitQuadIter.GetObjectCount() > unitHandler->activeUnits.size() / 3) {
782 if (teamID >= 0) {
783 unitSets.push_back(&teamHandler->Team(teamID)->units);
784 } else {
785 for (int t = 0; t < teamHandler->ActiveTeams(); t++) {
786 if ((teamID == AllUnits) ||
787 ((teamID == AllyUnits) && (allyTeamID == teamHandler->AllyTeam(t))) ||
788 ((teamID == EnemyUnits) && (allyTeamID != teamHandler->AllyTeam(t))))
789 {
790 unitSets.push_back(&teamHandler->Team(t)->units);
791 }
792 }
793 }
794 } else {
795 // objects can exist in multiple quads, so we still need to do a duplication check
796 visQuadUnits.clear();
797
798 const CVisUnitQuadDrawer::ObjectVector& visUnits = unitQuadIter.GetObjectLists();
799
800 CVisUnitQuadDrawer::ObjectVector::const_iterator visUnitLists;
801 CVisUnitQuadDrawer::ObjectList::const_iterator unitIt;
802
803 for (visUnitLists = visUnits.begin(); visUnitLists != visUnits.end(); ++visUnitLists) {
804 for (unitIt = (*visUnitLists)->begin(); unitIt != (*visUnitLists)->end(); ++unitIt) {
805 CUnit* unit = *unitIt;
806
807 if ((teamID == AllUnits) ||
808 ((teamID >= 0) && (teamID == unit->team)) ||
809 ((teamID == AllyUnits) && (allyTeamID == unit->allyteam)) ||
810 ((teamID == EnemyUnits) && (allyTeamID != unit->allyteam)))
811 {
812 visQuadUnits.insert(unit);
813 }
814 }
815 }
816 unitSets.push_back(&visQuadUnits);
817 }
818 }
819
820 for (setIt = unitSets.begin(); setIt != unitSets.end(); ++setIt) {
821 const CUnitSet* unitSet = *setIt;
822
823 CUnitSet::const_iterator unitIt;
824
825 for (unitIt = unitSet->begin(); unitIt != unitSet->end(); ++unitIt) {
826 const CUnit* unit = *unitIt;
827
828 if (unit->noDraw)
829 continue;
830
831 if (allyTeamID >= 0 && !(unit->losStatus[allyTeamID] & LOS_INLOS))
832 continue;
833
834 if (noIcons) {
835 const float sqDist = (unit->pos - camera->GetPos()).SqLength();
836 const float iconDistSqrMult = unit->unitDef->iconType->GetDistanceSqr();
837 const float realIconLength = iconLength * iconDistSqrMult;
838
839 if (sqDist > realIconLength)
840 continue;
841 }
842
843 if (!camera->InView(unit->midPos, testRadius + (unit->drawRadius * !fixedRadius)))
844 continue;
845
846 // add the unit
847 count++;
848 lua_pushnumber(L, unit->id);
849 lua_rawseti(L, -2, count);
850 }
851 }
852
853 return 1;
854 }
855
856
GetVisibleFeatures(lua_State * L)857 int LuaUnsyncedRead::GetVisibleFeatures(lua_State* L)
858 {
859 // arg 1 - allyTeamID
860 int allyTeamID = luaL_optint(L, 1, -1);
861
862 if (allyTeamID >= 0) {
863 if (!teamHandler->ValidAllyTeam(allyTeamID)) {
864 return 0;
865 }
866 } else {
867 allyTeamID = -1;
868
869 if (!CLuaHandle::GetHandleFullRead(L)) {
870 allyTeamID = CLuaHandle::GetHandleReadAllyTeam(L);
871 }
872 }
873
874 // arg 2 - feature radius
875 bool fixedRadius = false;
876 bool scanAll = false;
877
878 float testRadius = WORLDOBJECT_DEFAULT_DRAWRADIUS;
879
880 if (lua_israwnumber(L, 2)) {
881 testRadius = lua_tofloat(L, 2);
882 fixedRadius = (testRadius < 0.0f);
883 testRadius = std::max(testRadius, -testRadius);
884 }
885
886 const bool noIcons = !luaL_optboolean(L, 3, true);
887 const bool noGeos = !luaL_optboolean(L, 4, true);
888
889 static CFeatureSet visQuadFeatures;
890 static CVisFeatureQuadDrawer featureQuadIter;
891
892 unsigned int count = 0;
893
894 {
895 featureQuadIter.Reset();
896 readMap->GridVisibility(camera, CQuadField::BASE_QUAD_SIZE / SQUARE_SIZE, 3000.0f * 2.0f, &featureQuadIter, INT_MAX);
897
898 lua_createtable(L, featureQuadIter.GetObjectCount(), 0);
899
900 // setup the list of features
901 //
902 // if we see nearly all features, it is just faster to
903 // check them all, instead of doing slow duplication checks
904 //
905 // FIXME? one-third != "nearly all"
906 //
907 if (!(scanAll = (featureQuadIter.GetObjectCount() > featureHandler->GetActiveFeatures().size() / 3))) {
908 visQuadFeatures.clear();
909
910 const CVisFeatureQuadDrawer::ObjectVector& visFeatures = featureQuadIter.GetObjectLists();
911
912 CVisFeatureQuadDrawer::ObjectVector::const_iterator featureListIt;
913 CVisFeatureQuadDrawer::ObjectList::const_iterator featureIt;
914
915 // features can exist in multiple quads, so we need to do a duplication check
916 for (featureListIt = visFeatures.begin(); featureListIt != visFeatures.end(); ++featureListIt) {
917 for (featureIt = (*featureListIt)->begin(); featureIt != (*featureListIt)->end(); ++featureIt) {
918 visQuadFeatures.insert(*featureIt);
919 }
920 }
921 }
922 }
923
924 const CFeatureSet& featureSet = (scanAll) ? featureHandler->GetActiveFeatures() : visQuadFeatures;
925
926 for (CFeatureSet::const_iterator featureIt = featureSet.begin(); featureIt != featureSet.end(); ++featureIt) {
927 const CFeature& f = **featureIt;
928
929 if (noGeos && f.def->geoThermal)
930 continue;
931
932 if (noIcons) {
933 const float sqDist = (f.pos - camera->GetPos()).SqLength2D();
934 const float farLength = f.sqRadius * unitDrawer->unitDrawDist * unitDrawer->unitDrawDist;
935
936 if (sqDist >= farLength) {
937 continue;
938 }
939 }
940
941 if (!gu->spectatingFullView && !f.IsInLosForAllyTeam(allyTeamID))
942 continue;
943
944 if (!camera->InView(f.midPos, testRadius + (f.drawRadius * !fixedRadius)))
945 continue;
946
947 // add the unit
948 count++;
949 lua_pushnumber(L, f.id);
950 lua_rawseti(L, -2, count);
951 }
952
953 return 1;
954 }
955
GetVisibleProjectiles(lua_State * L)956 int LuaUnsyncedRead::GetVisibleProjectiles(lua_State* L)
957 {
958 int allyTeamID = luaL_optint(L, 1, -1);
959
960 if (allyTeamID >= 0) {
961 if (!teamHandler->ValidAllyTeam(allyTeamID)) {
962 return 0;
963 }
964 } else {
965 allyTeamID = -1;
966
967 if (!CLuaHandle::GetHandleFullRead(L)) {
968 allyTeamID = CLuaHandle::GetHandleReadAllyTeam(L);
969 }
970 }
971
972 static CVisProjectileQuadDrawer projQuadIter;
973
974 /*const bool addSyncedProjectiles =*/ luaL_optboolean(L, 2, true);
975 const bool addWeaponProjectiles = luaL_optboolean(L, 3, true);
976 const bool addPieceProjectiles = luaL_optboolean(L, 4, true);
977
978 unsigned int count = 0;
979
980 {
981 projQuadIter.Reset();
982 readMap->GridVisibility(camera, CQuadField::BASE_QUAD_SIZE / SQUARE_SIZE, 1e9, &projQuadIter, INT_MAX);
983
984 lua_createtable(L, projQuadIter.GetObjectCount(), 0);
985
986 const CVisProjectileQuadDrawer::ObjectVector& visProjectiles = projQuadIter.GetObjectLists();
987 const CVisProjectileQuadDrawer::ObjectList* quadProjectiles = NULL;
988
989 CVisProjectileQuadDrawer::ObjectList::const_iterator it;
990
991 for (unsigned int n = 0; n < visProjectiles.size(); n++) {
992 quadProjectiles = visProjectiles[n];
993
994 for (it = quadProjectiles->begin(); it != quadProjectiles->end(); ++it) {
995 const CProjectile* pro = *it;
996
997 if (allyTeamID >= 0 && !losHandler->InLos(pro, allyTeamID))
998 continue;
999
1000 if (!camera->InView(pro->pos, pro->drawRadius))
1001 continue;
1002
1003 #if 1
1004 // filter out unsynced projectiles, the SyncedRead
1005 // projecile Get* functions accept only synced ID's
1006 // (specifically they interpret all ID's as synced)
1007 if (!pro->synced)
1008 continue;
1009 #else
1010 if (!addSyncedProjectiles && pro->synced)
1011 continue;
1012 #endif
1013 if (!addWeaponProjectiles && pro->weapon)
1014 continue;
1015 if (!addPieceProjectiles && pro->piece)
1016 continue;
1017
1018 count++;
1019 lua_pushnumber(L, pro->id);
1020 lua_rawseti(L, -2, count);
1021 }
1022 }
1023 }
1024
1025 return 1;
1026 }
1027
1028
1029 /******************************************************************************/
1030 /******************************************************************************/
1031
GetLocalPlayerID(lua_State * L)1032 int LuaUnsyncedRead::GetLocalPlayerID(lua_State* L)
1033 {
1034 lua_pushnumber(L, gu->myPlayerNum);
1035 return 1;
1036 }
1037
1038
GetLocalTeamID(lua_State * L)1039 int LuaUnsyncedRead::GetLocalTeamID(lua_State* L)
1040 {
1041 lua_pushnumber(L, gu->myTeam);
1042 return 1;
1043 }
1044
1045
GetLocalAllyTeamID(lua_State * L)1046 int LuaUnsyncedRead::GetLocalAllyTeamID(lua_State* L)
1047 {
1048 lua_pushnumber(L, gu->myAllyTeam);
1049 return 1;
1050 }
1051
1052
GetSpectatingState(lua_State * L)1053 int LuaUnsyncedRead::GetSpectatingState(lua_State* L)
1054 {
1055 lua_pushboolean(L, gu->spectating);
1056 lua_pushboolean(L, gu->spectatingFullView);
1057 lua_pushboolean(L, gu->spectatingFullSelect);
1058 return 3;
1059 }
1060
1061
1062 /******************************************************************************/
1063 /******************************************************************************/
1064
GetSelectedUnits(lua_State * L)1065 int LuaUnsyncedRead::GetSelectedUnits(lua_State* L)
1066 {
1067 unsigned int count = 0;
1068 const CUnitSet& selUnits = selectedUnitsHandler.selectedUnits;
1069
1070 // { [1] = number unitID, ... }
1071 lua_createtable(L, selUnits.size(), 0);
1072
1073 CUnitSet::const_iterator it;
1074 for (it = selUnits.begin(); it != selUnits.end(); ++it) {
1075 lua_pushnumber(L, (*it)->id);
1076 lua_rawseti(L, -2, ++count);
1077 }
1078 return 1;
1079 }
1080
1081
GetSelectedUnitsSorted(lua_State * L)1082 int LuaUnsyncedRead::GetSelectedUnitsSorted(lua_State* L)
1083 {
1084 map<int, vector<CUnit*> > unitDefMap;
1085 map<int, vector<CUnit*> >::const_iterator mit;
1086
1087 const CUnitSet& selUnits = selectedUnitsHandler.selectedUnits;
1088 CUnitSet::const_iterator it;
1089
1090 for (it = selUnits.begin(); it != selUnits.end(); ++it) {
1091 CUnit* unit = *it;
1092 unitDefMap[unit->unitDef->id].push_back(unit);
1093 }
1094
1095 // { [number unitDefID] = { [1] = [number unitID], ...}, ... }
1096 lua_createtable(L, 0, unitDefMap.size());
1097
1098 for (mit = unitDefMap.begin(); mit != unitDefMap.end(); ++mit) {
1099 const vector<CUnit*>& v = mit->second;
1100
1101 // inner array-table
1102 lua_createtable(L, v.size(), 0);
1103
1104 {
1105 for (unsigned int i = 0; i < v.size(); i++) {
1106 lua_pushnumber(L, v[i]->id);
1107 lua_rawseti(L, -2, i + 1);
1108 }
1109 }
1110
1111 // push the UnitDef index
1112 lua_rawseti(L, -2, mit->first);
1113 }
1114
1115 // UnitDef ID keys are not necessarily consecutive
1116 HSTR_PUSH_NUMBER(L, "n", unitDefMap.size());
1117 return 1;
1118 }
1119
1120
GetSelectedUnitsCounts(lua_State * L)1121 int LuaUnsyncedRead::GetSelectedUnitsCounts(lua_State* L)
1122 {
1123 map<int, int> countMap;
1124 map<int, int>::const_iterator mit;
1125
1126 const CUnitSet& selUnits = selectedUnitsHandler.selectedUnits;
1127 CUnitSet::const_iterator it;
1128
1129 // tally the types
1130 for (it = selUnits.begin(); it != selUnits.end(); ++it) {
1131 CUnit* unit = *it;
1132 map<int, int>::iterator mit = countMap.find(unit->unitDef->id);
1133
1134 if (mit == countMap.end()) {
1135 countMap[unit->unitDef->id] = 1;
1136 } else {
1137 mit->second++;
1138 }
1139 }
1140
1141 // { [number unitDefID] = number count, ... }
1142 lua_createtable(L, 0, countMap.size());
1143
1144 for (mit = countMap.begin(); mit != countMap.end(); ++mit) {
1145 lua_pushnumber(L, mit->second); // push the UnitDef unit count (value)
1146 lua_rawseti(L, -2, mit->first); // push the UnitDef index (key)
1147 }
1148
1149 // UnitDef ID keys are not necessarily consecutive
1150 HSTR_PUSH_NUMBER(L, "n", countMap.size());
1151 return 1;
1152 }
1153
1154
GetSelectedUnitsCount(lua_State * L)1155 int LuaUnsyncedRead::GetSelectedUnitsCount(lua_State* L)
1156 {
1157 lua_pushnumber(L, selectedUnitsHandler.selectedUnits.size());
1158 return 1;
1159 }
1160
1161
1162 /******************************************************************************/
1163 /******************************************************************************/
1164
IsGUIHidden(lua_State * L)1165 int LuaUnsyncedRead::IsGUIHidden(lua_State* L)
1166 {
1167 if (game == NULL) {
1168 return 0;
1169 }
1170 lua_pushboolean(L, game->hideInterface);
1171 return 1;
1172 }
1173
1174
HaveShadows(lua_State * L)1175 int LuaUnsyncedRead::HaveShadows(lua_State* L)
1176 {
1177 if (shadowHandler == NULL) {
1178 return 0;
1179 }
1180 lua_pushboolean(L, shadowHandler->shadowsLoaded);
1181 return 1;
1182 }
1183
1184
HaveAdvShading(lua_State * L)1185 int LuaUnsyncedRead::HaveAdvShading(lua_State* L)
1186 {
1187 if (unitDrawer == NULL) {
1188 return 0;
1189 }
1190 lua_pushboolean(L, unitDrawer->UseAdvShading());
1191 return 1;
1192 }
1193
1194
GetWaterMode(lua_State * L)1195 int LuaUnsyncedRead::GetWaterMode(lua_State* L)
1196 {
1197 if (water == NULL) {
1198 return 0;
1199 }
1200
1201 const int mode = water->GetID();
1202 const char* modeName = water->GetName();
1203
1204 lua_pushnumber(L, mode);
1205 lua_pushstring(L, modeName);
1206 return 2;
1207 }
1208
1209
GetMapDrawMode(lua_State * L)1210 int LuaUnsyncedRead::GetMapDrawMode(lua_State* L)
1211 {
1212 switch (readMap->GetGroundDrawer()->GetDrawMode()) {
1213 case CBaseGroundDrawer::drawNormal: { HSTR_PUSH(L, "normal" ); break; }
1214 case CBaseGroundDrawer::drawHeight: { HSTR_PUSH(L, "height" ); break; }
1215 case CBaseGroundDrawer::drawMetal: { HSTR_PUSH(L, "metal" ); break; }
1216 case CBaseGroundDrawer::drawLos: { HSTR_PUSH(L, "los" ); break; }
1217 case CBaseGroundDrawer::drawPathTrav: { HSTR_PUSH(L, "pathTraversability"); break; }
1218 case CBaseGroundDrawer::drawPathHeat: { HSTR_PUSH(L, "pathHeat" ); break; }
1219 case CBaseGroundDrawer::drawPathFlow: { HSTR_PUSH(L, "pathFlow" ); break; }
1220 case CBaseGroundDrawer::drawPathCost: { HSTR_PUSH(L, "pathCost" ); break; }
1221 }
1222 return 1;
1223 }
1224
1225
GetMapSquareTexture(lua_State * L)1226 int LuaUnsyncedRead::GetMapSquareTexture(lua_State* L)
1227 {
1228 if (CLuaHandle::GetHandleSynced(L)) {
1229 return 0;
1230 }
1231
1232 const int texSquareX = luaL_checkint(L, 1);
1233 const int texSquareY = luaL_checkint(L, 2);
1234 const int texMipLevel = luaL_checkint(L, 3);
1235 const std::string& texName = luaL_checkstring(L, 4);
1236
1237 CBaseGroundDrawer* groundDrawer = readMap->GetGroundDrawer();
1238 CBaseGroundTextures* groundTextures = groundDrawer->GetGroundTextures();
1239
1240 if (groundTextures == NULL) {
1241 lua_pushboolean(L, false);
1242 return 1;
1243 }
1244 if (texName.empty()) {
1245 lua_pushboolean(L, false);
1246 return 1;
1247 }
1248
1249 const LuaTextures& luaTextures = CLuaHandle::GetActiveTextures(L);
1250 const LuaTextures::Texture* luaTexture = luaTextures.GetInfo(texName);
1251
1252 if (luaTexture == NULL) {
1253 // not a valid texture (name)
1254 lua_pushboolean(L, false);
1255 return 1;
1256 }
1257
1258 const int tid = luaTexture->id;
1259 const int txs = luaTexture->xsize;
1260 const int tys = luaTexture->ysize;
1261
1262 if (txs != tys) {
1263 // square textures only
1264 lua_pushboolean(L, false);
1265 return 1;
1266 }
1267
1268 lua_pushboolean(L, groundTextures->GetSquareLuaTexture(texSquareX, texSquareY, tid, txs, tys, texMipLevel));
1269 return 1;
1270 }
1271
1272 /******************************************************************************/
1273
GetCameraNames(lua_State * L)1274 int LuaUnsyncedRead::GetCameraNames(lua_State* L)
1275 {
1276 lua_newtable(L);
1277 const std::vector<CCameraController*>& cc = camHandler->GetAvailableControllers();
1278 for (size_t i = 0; i < cc.size(); ++i) {
1279 lua_pushsstring(L, cc[i]->GetName());
1280 lua_pushnumber(L, i);
1281 lua_rawset(L, -3);
1282 }
1283
1284 return 1;
1285 }
1286
1287
GetCameraState(lua_State * L)1288 int LuaUnsyncedRead::GetCameraState(lua_State* L)
1289 {
1290 lua_newtable(L);
1291
1292 lua_pushliteral(L, "name");
1293 lua_pushsstring(L, camHandler->GetCurrentControllerName());
1294 lua_rawset(L, -3);
1295
1296 CCameraController::StateMap camState;
1297 CCameraController::StateMap::const_iterator it;
1298 camHandler->GetState(camState);
1299 for (it = camState.begin(); it != camState.end(); ++it) {
1300 lua_pushsstring(L, it->first);
1301 lua_pushnumber(L, it->second);
1302 lua_rawset(L, -3);
1303 }
1304
1305 return 1;
1306 }
1307
1308
GetCameraPosition(lua_State * L)1309 int LuaUnsyncedRead::GetCameraPosition(lua_State* L)
1310 {
1311 lua_pushnumber(L, camera->GetPos().x);
1312 lua_pushnumber(L, camera->GetPos().y);
1313 lua_pushnumber(L, camera->GetPos().z);
1314 return 3;
1315 }
1316
1317
GetCameraDirection(lua_State * L)1318 int LuaUnsyncedRead::GetCameraDirection(lua_State* L)
1319 {
1320 lua_pushnumber(L, camera->forward.x);
1321 lua_pushnumber(L, camera->forward.y);
1322 lua_pushnumber(L, camera->forward.z);
1323 return 3;
1324 }
1325
1326
GetCameraFOV(lua_State * L)1327 int LuaUnsyncedRead::GetCameraFOV(lua_State* L)
1328 {
1329 lua_pushnumber(L, camera->GetFov());
1330 return 1;
1331 }
1332
1333
GetCameraVectors(lua_State * L)1334 int LuaUnsyncedRead::GetCameraVectors(lua_State* L)
1335 {
1336 #define PACK_CAMERA_VECTOR(n) \
1337 HSTR_PUSH(L, #n); \
1338 lua_createtable(L, 3, 0); \
1339 lua_pushnumber(L, camera-> n .x); lua_rawseti(L, -2, 1); \
1340 lua_pushnumber(L, camera-> n .y); lua_rawseti(L, -2, 2); \
1341 lua_pushnumber(L, camera-> n .z); lua_rawseti(L, -2, 3); \
1342 lua_rawset(L, -3)
1343
1344 lua_newtable(L);
1345 PACK_CAMERA_VECTOR(forward);
1346 PACK_CAMERA_VECTOR(up);
1347 PACK_CAMERA_VECTOR(right);
1348 PACK_CAMERA_VECTOR(topFrustumSideDir);
1349 PACK_CAMERA_VECTOR(botFrustumSideDir);
1350 PACK_CAMERA_VECTOR(lftFrustumSideDir);
1351 PACK_CAMERA_VECTOR(rgtFrustumSideDir);
1352
1353 return 1;
1354 }
1355
1356
WorldToScreenCoords(lua_State * L)1357 int LuaUnsyncedRead::WorldToScreenCoords(lua_State* L)
1358 {
1359 const float3 worldPos(luaL_checkfloat(L, 1),
1360 luaL_checkfloat(L, 2),
1361 luaL_checkfloat(L, 3));
1362 const float3 winPos = camera->CalcWindowCoordinates(worldPos);
1363 lua_pushnumber(L, winPos.x);
1364 lua_pushnumber(L, winPos.y);
1365 lua_pushnumber(L, winPos.z);
1366 return 3;
1367 }
1368
1369
TraceScreenRay(lua_State * L)1370 int LuaUnsyncedRead::TraceScreenRay(lua_State* L)
1371 {
1372 // window coordinates
1373 const int mx = luaL_checkint(L, 1);
1374 const int my = luaL_checkint(L, 2);
1375 const bool onlyCoords = luaL_optboolean(L, 3, false);
1376 const bool useMiniMap = luaL_optboolean(L, 4, false);
1377 const bool includeSky = luaL_optboolean(L, 5, false);
1378 const bool ignoreWater = luaL_optboolean(L, 6, false);
1379
1380 const int wx = mx + globalRendering->viewPosX;
1381 const int wy = globalRendering->viewSizeY - 1 - my - globalRendering->viewPosY;
1382
1383 if (useMiniMap && (minimap != NULL) && !minimap->GetMinimized()) {
1384 const int px = minimap->GetPosX() - globalRendering->viewPosX; // for left dualscreen
1385 const int py = minimap->GetPosY();
1386 const int sx = minimap->GetSizeX();
1387 const int sy = minimap->GetSizeY();
1388 if ((mx >= px) && (mx < (px + sx)) &&
1389 (my >= py) && (my < (py + sy))) {
1390 const float3 pos = minimap->GetMapPosition(wx, wy);
1391 if (!onlyCoords) {
1392 const CUnit* unit = minimap->GetSelectUnit(pos);
1393 if (unit != NULL) {
1394 lua_pushliteral(L, "unit");
1395 lua_pushnumber(L, unit->id);
1396 return 2;
1397 }
1398 }
1399 const float posY = CGround::GetHeightReal(pos.x, pos.z, false);
1400 lua_pushliteral(L, "ground");
1401 lua_createtable(L, 3, 0);
1402 lua_pushnumber(L, pos.x); lua_rawseti(L, -2, 1);
1403 lua_pushnumber(L, posY); lua_rawseti(L, -2, 2);
1404 lua_pushnumber(L, pos.z); lua_rawseti(L, -2, 3);
1405 return 2;
1406 }
1407 }
1408
1409 if ((mx < 0) || (mx >= globalRendering->viewSizeX) ||
1410 (my < 0) || (my >= globalRendering->viewSizeY)) {
1411 return 0;
1412 }
1413
1414 CUnit* unit = NULL;
1415 CFeature* feature = NULL;
1416
1417 const float range = globalRendering->viewRange * 1.4f;
1418 const float badRange = range - 300.0f;
1419
1420 const float3& pos = camera->GetPos();
1421 const float3 dir = camera->CalcPixelDir(wx, wy);
1422
1423
1424 // FIXME const int origAllyTeam = gu->myAllyTeam;
1425 // gu->myAllyTeam = readAllyTeam;
1426 const float dist = TraceRay::GuiTraceRay(pos, dir, range, NULL, unit, feature, true, onlyCoords, ignoreWater);
1427 // gu->myAllyTeam = origAllyTeam;
1428
1429 if ((dist < 0.0f || dist > badRange) && unit == NULL && feature == NULL) {
1430 // ray went into the void (or started too far above terrain)
1431 if (includeSky) {
1432 lua_pushliteral(L, "sky");
1433 } else {
1434 return 0;
1435 }
1436 } else {
1437 if (!onlyCoords) {
1438 if (unit != NULL) {
1439 lua_pushliteral(L, "unit");
1440 lua_pushnumber(L, unit->id);
1441 return 2;
1442 }
1443
1444 if (feature != NULL) {
1445 lua_pushliteral(L, "feature");
1446 lua_pushnumber(L, feature->id);
1447 return 2;
1448 }
1449 }
1450
1451 lua_pushliteral(L, "ground");
1452 }
1453
1454 const float3 groundPos = pos + (dir * dist);
1455 lua_createtable(L, 3, 0);
1456 lua_pushnumber(L, groundPos.x); lua_rawseti(L, -2, 1);
1457 lua_pushnumber(L, groundPos.y); lua_rawseti(L, -2, 2);
1458 lua_pushnumber(L, groundPos.z); lua_rawseti(L, -2, 3);
1459
1460 return 2;
1461 }
1462
1463
GetPixelDir(lua_State * L)1464 int LuaUnsyncedRead::GetPixelDir(lua_State* L)
1465 {
1466 const int x = luaL_checkint(L, 1);
1467 const int y = luaL_checkint(L, 2);
1468 const float3 dir = camera->CalcPixelDir(x,y);
1469 lua_pushnumber(L, dir.x);
1470 lua_pushnumber(L, dir.y);
1471 lua_pushnumber(L, dir.z);
1472 return 3;
1473 }
1474
1475
1476
1477 /******************************************************************************/
1478
AddPlayerToRoster(lua_State * L,int playerID,bool includePathingFlag)1479 static void AddPlayerToRoster(lua_State* L, int playerID, bool includePathingFlag)
1480 {
1481 #define PUSH_ROSTER_ENTRY(type, val) \
1482 lua_push ## type(L, val); lua_rawseti(L, -2, index++);
1483
1484 const CPlayer* p = playerHandler->Player(playerID);
1485 int index = 1;
1486 lua_newtable(L);
1487 PUSH_ROSTER_ENTRY(string, p->name.c_str());
1488 PUSH_ROSTER_ENTRY(number, playerID);
1489 PUSH_ROSTER_ENTRY(number, p->team);
1490 PUSH_ROSTER_ENTRY(number, teamHandler->AllyTeam(p->team));
1491 PUSH_ROSTER_ENTRY(boolean, p->spectator);
1492 PUSH_ROSTER_ENTRY(number, p->cpuUsage);
1493 const float pingScale = (GAME_SPEED * gs->speedFactor);
1494
1495 if (!includePathingFlag || p->ping != PATHING_FLAG) {
1496 const float pingSecs = float(p->ping - 1) / pingScale;
1497 PUSH_ROSTER_ENTRY(number, pingSecs);
1498 } else {
1499 const float pingSecs = float(p->ping);
1500 PUSH_ROSTER_ENTRY(number, pingSecs);
1501 }
1502 }
1503
1504
GetTeamColor(lua_State * L)1505 int LuaUnsyncedRead::GetTeamColor(lua_State* L)
1506 {
1507 const int teamID = luaL_checkint(L, 1);
1508 if ((teamID < 0) || (teamID >= teamHandler->ActiveTeams())) {
1509 return 0;
1510 }
1511 const CTeam* team = teamHandler->Team(teamID);
1512 if (team == NULL) {
1513 return 0;
1514 }
1515
1516 lua_pushnumber(L, (float)team->color[0] / 255.0f);
1517 lua_pushnumber(L, (float)team->color[1] / 255.0f);
1518 lua_pushnumber(L, (float)team->color[2] / 255.0f);
1519 lua_pushnumber(L, (float)team->color[3] / 255.0f);
1520
1521 return 4;
1522 }
1523
1524
GetTeamOrigColor(lua_State * L)1525 int LuaUnsyncedRead::GetTeamOrigColor(lua_State* L)
1526 {
1527 const int teamID = luaL_checkint(L, 1);
1528 if ((teamID < 0) || (teamID >= teamHandler->ActiveTeams())) {
1529 return 0;
1530 }
1531 const CTeam* team = teamHandler->Team(teamID);
1532 if (team == NULL) {
1533 return 0;
1534 }
1535
1536 lua_pushnumber(L, (float)team->origColor[0] / 255.0f);
1537 lua_pushnumber(L, (float)team->origColor[1] / 255.0f);
1538 lua_pushnumber(L, (float)team->origColor[2] / 255.0f);
1539 lua_pushnumber(L, (float)team->origColor[3] / 255.0f);
1540
1541 return 4;
1542 }
1543
1544
1545 /******************************************************************************/
1546 /******************************************************************************/
1547
GetTimer(lua_State * L)1548 int LuaUnsyncedRead::GetTimer(lua_State* L)
1549 {
1550 // use time since Spring's epoch in MILLIseconds because that
1551 // is more likely to fit in a 32-bit pointer (on any platforms
1552 // where sizeof(void*) == 4) than time since ::chrono's epoch
1553 // (which can be arbitrarily large) and can be represented by
1554 // single-precision floats better
1555 //
1556 // 4e9millis == 4e6s == 46.3 days until overflow
1557 const spring_time time = spring_now();
1558 const boost::uint64_t millis = time.toMilliSecs<boost::uint64_t>();
1559
1560 ptrdiff_t p = 0;
1561
1562 if (sizeof(void*) == 8) {
1563 *reinterpret_cast<boost::uint64_t*>(&p) = millis;
1564 } else {
1565 *reinterpret_cast<boost::uint32_t*>(&p) = millis;
1566 }
1567
1568 lua_pushlightuserdata(L, reinterpret_cast<void*>(p));
1569 return 1;
1570 }
1571
1572
DiffTimers(lua_State * L)1573 int LuaUnsyncedRead::DiffTimers(lua_State* L)
1574 {
1575 if (!lua_islightuserdata(L, 1) || !lua_islightuserdata(L, 2)) {
1576 luaL_error(L, "Incorrect arguments to DiffTimers()");
1577 }
1578
1579 const void* p1 = lua_touserdata(L, 1);
1580 const void* p2 = lua_touserdata(L, 2);
1581
1582 const boost::uint64_t t1 = (sizeof(void*) == 8)?
1583 *reinterpret_cast<boost::uint64_t*>(&p1):
1584 *reinterpret_cast<boost::uint32_t*>(&p1);
1585 const boost::uint64_t t2 = (sizeof(void*) == 8)?
1586 *reinterpret_cast<boost::uint64_t*>(&p2):
1587 *reinterpret_cast<boost::uint32_t*>(&p2);
1588
1589 // t1 is supposed to be the most recent time-point
1590 assert(t1 >= t2);
1591
1592 const spring_time dt = spring_time::fromMilliSecs(t1 - t2);
1593
1594 if (luaL_optboolean(L, 3, false)) {
1595 lua_pushnumber(L, dt.toMilliSecsf());
1596 } else {
1597 lua_pushnumber(L, dt.toSecsf());
1598 }
1599
1600 return 1;
1601 }
1602
1603
1604 /******************************************************************************/
1605 /******************************************************************************/
1606
GetSoundStreamTime(lua_State * L)1607 int LuaUnsyncedRead::GetSoundStreamTime(lua_State* L)
1608 {
1609 lua_pushnumber(L, Channels::BGMusic->StreamGetPlayTime());
1610 lua_pushnumber(L, Channels::BGMusic->StreamGetTime());
1611 return 2;
1612 }
1613
1614
GetSoundEffectParams(lua_State * L)1615 int LuaUnsyncedRead::GetSoundEffectParams(lua_State* L)
1616 {
1617 #if defined(HEADLESS) || defined(NO_SOUND)
1618 return 0;
1619 #else
1620 if (!efx || !efx->sfxProperties)
1621 return 0;
1622
1623 EAXSfxProps* efxprops = efx->sfxProperties;
1624
1625 lua_createtable(L, 0, 2);
1626
1627 size_t n = efxprops->filter_properties_f.size();
1628 lua_pushliteral(L, "passfilter");
1629 lua_createtable(L, 0, n);
1630 lua_rawset(L, -3);
1631 for (std::map<ALuint, ALfloat>::iterator it = efxprops->filter_properties_f.begin(); it != efxprops->filter_properties_f.end(); ++it)
1632 {
1633 const ALuint param = it->first;
1634 std::map<ALuint, std::string>::iterator fit = alFilterParamToName.find(param);
1635 if (fit != alFilterParamToName.end()) {
1636 const std::string& name = fit->second;
1637 lua_pushsstring(L, name);
1638 lua_pushnumber(L, it->second);
1639 lua_rawset(L, -3);
1640 }
1641 }
1642
1643
1644 n = efxprops->properties_v.size() + efxprops->properties_f.size() + efxprops->properties_i.size();
1645 lua_pushliteral(L, "reverb");
1646 lua_createtable(L, 0, n);
1647 lua_rawset(L, -3);
1648 for (std::map<ALuint, ALfloat>::iterator it = efxprops->properties_f.begin(); it != efxprops->properties_f.end(); ++it)
1649 {
1650 const ALuint param = it->first;
1651 std::map<ALuint, std::string>::iterator fit = alParamToName.find(param);
1652 if (fit != alParamToName.end()) {
1653 const std::string& name = fit->second;
1654 lua_pushsstring(L, name);
1655 lua_pushnumber(L, it->second);
1656 lua_rawset(L, -3);
1657 }
1658 }
1659 for (std::map<ALuint, float3>::iterator it = efxprops->properties_v.begin(); it != efxprops->properties_v.end(); ++it)
1660 {
1661 const ALuint param = it->first;
1662 std::map<ALuint, std::string>::iterator fit = alParamToName.find(param);
1663 if (fit != alParamToName.end()) {
1664 const float3& v = it->second;
1665 const std::string& name = fit->second;
1666 lua_pushsstring(L, name);
1667 lua_createtable(L, 3, 0);
1668 lua_pushnumber(L, v.x);
1669 lua_rawseti(L, -2, 1);
1670 lua_pushnumber(L, v.y);
1671 lua_rawseti(L, -2, 2);
1672 lua_pushnumber(L, v.z);
1673 lua_rawseti(L, -2, 3);
1674 lua_rawset(L, -3);
1675 }
1676 }
1677 for (std::map<ALuint, ALint>::iterator it = efxprops->properties_i.begin(); it != efxprops->properties_i.end(); ++it)
1678 {
1679 const ALuint param = it->first;
1680 std::map<ALuint, std::string>::iterator fit = alParamToName.find(param);
1681 if (fit != alParamToName.end()) {
1682 const std::string& name = fit->second;
1683 lua_pushsstring(L, name);
1684 lua_pushboolean(L, it->second);
1685 lua_rawset(L, -3);
1686 }
1687 }
1688
1689 return 1;
1690 #endif // defined(HEADLESS) || defined(NO_SOUND)
1691 }
1692
1693
1694 /******************************************************************************/
1695 /******************************************************************************/
1696 //
1697 // moved from LuaUI
1698 //
1699 /******************************************************************************/
1700 /******************************************************************************/
1701
GetFPS(lua_State * L)1702 int LuaUnsyncedRead::GetFPS(lua_State* L)
1703 {
1704 if (globalRendering) {
1705 lua_pushnumber(L, (int)globalRendering->FPS);
1706 } else {
1707 lua_pushnumber(L, 0);
1708 }
1709 return 1;
1710 }
1711
1712
GetGameSpeed(lua_State * L)1713 int LuaUnsyncedRead::GetGameSpeed(lua_State* L)
1714 {
1715 lua_pushnumber(L, gs->wantedSpeedFactor);
1716 lua_pushnumber(L, gs->speedFactor);
1717 lua_pushboolean(L, gs->paused);
1718 return 3;
1719 }
1720
1721
1722 /******************************************************************************/
1723
GetActiveCommand(lua_State * L)1724 int LuaUnsyncedRead::GetActiveCommand(lua_State* L)
1725 {
1726 if (guihandler == NULL) {
1727 return 0;
1728 }
1729
1730 const vector<CommandDescription>& cmdDescs = guihandler->commands;
1731 const int cmdDescCount = (int)cmdDescs.size();
1732
1733 const int inCommand = guihandler->inCommand;
1734 lua_pushnumber(L, inCommand + CMD_INDEX_OFFSET);
1735 if ((inCommand < 0) || (inCommand >= cmdDescCount)) {
1736 return 1;
1737 }
1738 lua_pushnumber(L, cmdDescs[inCommand].id);
1739 lua_pushnumber(L, cmdDescs[inCommand].type);
1740 lua_pushsstring(L, cmdDescs[inCommand].name);
1741 return 4;
1742 }
1743
1744
GetDefaultCommand(lua_State * L)1745 int LuaUnsyncedRead::GetDefaultCommand(lua_State* L)
1746 {
1747 if (guihandler == NULL) {
1748 return 0;
1749 }
1750
1751 const int defCmd = guihandler->GetDefaultCommand(mouse->lastx, mouse->lasty);
1752
1753 const vector<CommandDescription>& cmdDescs = guihandler->commands;
1754 const int cmdDescCount = (int)cmdDescs.size();
1755
1756 lua_pushnumber(L, defCmd + CMD_INDEX_OFFSET);
1757 if ((defCmd < 0) || (defCmd >= cmdDescCount)) {
1758 return 1;
1759 }
1760 lua_pushnumber(L, cmdDescs[defCmd].id);
1761 lua_pushnumber(L, cmdDescs[defCmd].type);
1762 lua_pushsstring(L, cmdDescs[defCmd].name);
1763 return 4;
1764 }
1765
1766
GetActiveCmdDescs(lua_State * L)1767 int LuaUnsyncedRead::GetActiveCmdDescs(lua_State* L)
1768 {
1769 if (guihandler == NULL) {
1770 return 0;
1771 }
1772
1773 const vector<CommandDescription>& cmdDescs = guihandler->commands;
1774 const int cmdDescCount = (int)cmdDescs.size();
1775
1776 lua_checkstack(L, 1 + 2);
1777 lua_newtable(L);
1778
1779 for (int i = 0; i < cmdDescCount; i++) {
1780 LuaUtils::PushCommandDesc(L, cmdDescs[i]);
1781 lua_rawseti(L, -2, i + CMD_INDEX_OFFSET);
1782 }
1783 return 1;
1784 }
1785
1786
GetActiveCmdDesc(lua_State * L)1787 int LuaUnsyncedRead::GetActiveCmdDesc(lua_State* L)
1788 {
1789 if (guihandler == NULL) {
1790 return 0;
1791 }
1792 const int cmdIndex = luaL_checkint(L, 1) - CMD_INDEX_OFFSET;
1793
1794 const vector<CommandDescription>& cmdDescs = guihandler->commands;
1795 const int cmdDescCount = (int)cmdDescs.size();
1796 if ((cmdIndex < 0) || (cmdIndex >= cmdDescCount)) {
1797 return 0;
1798 }
1799 LuaUtils::PushCommandDesc(L, cmdDescs[cmdIndex]);
1800 return 1;
1801 }
1802
1803
GetCmdDescIndex(lua_State * L)1804 int LuaUnsyncedRead::GetCmdDescIndex(lua_State* L)
1805 {
1806 if (guihandler == NULL) {
1807 return 0;
1808 }
1809 const int cmdId = luaL_checkint(L, 1);
1810
1811 const vector<CommandDescription>& cmdDescs = guihandler->commands;
1812 const int cmdDescCount = (int)cmdDescs.size();
1813 for (int i = 0; i < cmdDescCount; i++) {
1814 if (cmdId == cmdDescs[i].id) {
1815 lua_pushnumber(L, i + CMD_INDEX_OFFSET);
1816 return 1;
1817 }
1818 }
1819 return 0;
1820 }
1821
1822
1823 /******************************************************************************/
1824
GetBuildFacing(lua_State * L)1825 int LuaUnsyncedRead::GetBuildFacing(lua_State* L)
1826 {
1827 if (guihandler == NULL) {
1828 return 0;
1829 }
1830 lua_pushnumber(L, guihandler->buildFacing);
1831 return 1;
1832 }
1833
1834
GetBuildSpacing(lua_State * L)1835 int LuaUnsyncedRead::GetBuildSpacing(lua_State* L)
1836 {
1837 if (guihandler == NULL) {
1838 return 0;
1839 }
1840 lua_pushnumber(L, guihandler->buildSpacing);
1841 return 1;
1842 }
1843
1844
GetGatherMode(lua_State * L)1845 int LuaUnsyncedRead::GetGatherMode(lua_State* L)
1846 {
1847 if (guihandler == NULL) {
1848 return 0;
1849 }
1850 lua_pushnumber(L, guihandler->GetGatherMode());
1851 return 1;
1852 }
1853
1854
1855 /******************************************************************************/
1856
GetActivePage(lua_State * L)1857 int LuaUnsyncedRead::GetActivePage(lua_State* L)
1858 {
1859 if (guihandler == NULL) {
1860 return 0;
1861 }
1862 lua_pushnumber(L, guihandler->GetActivePage());
1863 lua_pushnumber(L, guihandler->GetMaxPage());
1864 return 2;
1865 }
1866
1867
1868 /******************************************************************************/
1869
GetMouseState(lua_State * L)1870 int LuaUnsyncedRead::GetMouseState(lua_State* L)
1871 {
1872 lua_pushnumber(L, mouse->lastx - globalRendering->viewPosX);
1873 lua_pushnumber(L, globalRendering->viewSizeY - mouse->lasty - 1);
1874 lua_pushboolean(L, mouse->buttons[SDL_BUTTON_LEFT].pressed);
1875 lua_pushboolean(L, mouse->buttons[SDL_BUTTON_MIDDLE].pressed);
1876 lua_pushboolean(L, mouse->buttons[SDL_BUTTON_RIGHT].pressed);
1877 return 5;
1878 }
1879
1880
GetMouseCursor(lua_State * L)1881 int LuaUnsyncedRead::GetMouseCursor(lua_State* L)
1882 {
1883 lua_pushsstring(L, mouse->GetCurrentCursor());
1884 lua_pushnumber(L, mouse->GetCurrentCursorScale());
1885 return 2;
1886 }
1887
1888
GetMouseStartPosition(lua_State * L)1889 int LuaUnsyncedRead::GetMouseStartPosition(lua_State* L)
1890 {
1891 if (mouse == NULL) {
1892 return 0;
1893 }
1894 const int button = luaL_checkint(L, 1);
1895 if ((button <= 0) || (button > NUM_BUTTONS)) {
1896 return 0;
1897 }
1898 const CMouseHandler::ButtonPressEvt& bp = mouse->buttons[button];
1899 lua_pushnumber(L, bp.x);
1900 lua_pushnumber(L, bp.y);
1901 lua_pushnumber(L, bp.camPos.x);
1902 lua_pushnumber(L, bp.camPos.y);
1903 lua_pushnumber(L, bp.camPos.z);
1904 lua_pushnumber(L, bp.dir.x);
1905 lua_pushnumber(L, bp.dir.y);
1906 lua_pushnumber(L, bp.dir.z);
1907 return 8;
1908 }
1909
1910
1911 /******************************************************************************/
1912 /******************************************************************************/
1913
GetKeyState(lua_State * L)1914 int LuaUnsyncedRead::GetKeyState(lua_State* L)
1915 {
1916 const int key = luaL_checkint(L, 1);
1917 lua_pushboolean(L, KeyInput::IsKeyPressed(key));
1918 return 1;
1919 }
1920
1921
GetModKeyState(lua_State * L)1922 int LuaUnsyncedRead::GetModKeyState(lua_State* L)
1923 {
1924 lua_pushboolean(L, KeyInput::GetKeyModState(KMOD_ALT));
1925 lua_pushboolean(L, KeyInput::GetKeyModState(KMOD_CTRL));
1926 lua_pushboolean(L, KeyInput::GetKeyModState(KMOD_GUI));
1927 lua_pushboolean(L, KeyInput::GetKeyModState(KMOD_SHIFT));
1928 return 4;
1929 }
1930
1931
GetPressedKeys(lua_State * L)1932 int LuaUnsyncedRead::GetPressedKeys(lua_State* L)
1933 {
1934 lua_newtable(L);
1935 for (auto key: KeyInput::GetPressedKeys()) {
1936 if (key.second) {
1937 lua_pushboolean(L, true);
1938 lua_rawseti(L, -2, key.first);
1939 }
1940 }
1941 return 1;
1942 }
1943
1944
GetInvertQueueKey(lua_State * L)1945 int LuaUnsyncedRead::GetInvertQueueKey(lua_State* L)
1946 {
1947 if (guihandler == NULL) {
1948 return 0;
1949 }
1950 lua_pushboolean(L, guihandler->GetInvertQueueKey());
1951 return 1;
1952 }
1953
1954 /******************************************************************************/
1955
GetClipboard(lua_State * L)1956 int LuaUnsyncedRead::GetClipboard(lua_State* L)
1957 {
1958 char* text = SDL_GetClipboardText();
1959 if (text == NULL) {
1960 return 0;
1961 }
1962 lua_pushstring(L, text);
1963 SDL_free(text);
1964 return 1;
1965 }
1966
1967 /******************************************************************************/
1968
GetLastMessagePositions(lua_State * L)1969 int LuaUnsyncedRead::GetLastMessagePositions(lua_State* L)
1970 {
1971 CInfoConsole* ic = game->infoConsole;
1972
1973 if (ic == NULL)
1974 return 0;
1975
1976 lua_newtable(L);
1977 for (unsigned int i = 1; i <= ic->GetMsgPosCount(); i++) {
1978 lua_newtable(L); {
1979 const float3 msgpos = ic->GetMsgPos();
1980 lua_pushnumber(L, msgpos.x); lua_rawseti(L, -2, 1);
1981 lua_pushnumber(L, msgpos.y); lua_rawseti(L, -2, 2);
1982 lua_pushnumber(L, msgpos.z); lua_rawseti(L, -2, 3);
1983 }
1984 lua_rawseti(L, -2, i);
1985 }
1986 return 1;
1987 }
1988
1989 /******************************************************************************/
1990
GetConsoleBuffer(lua_State * L)1991 int LuaUnsyncedRead::GetConsoleBuffer(lua_State* L)
1992 {
1993 CInfoConsole* ic = game->infoConsole;
1994 if (ic == NULL) {
1995 return true;
1996 }
1997
1998 const int args = lua_gettop(L); // number of arguments
1999
2000 std::deque<CInfoConsole::RawLine> lines;
2001 ic->GetRawLines(lines);
2002 const int lineCount = (int)lines.size();
2003
2004 int start = 0;
2005 if (args >= 1) {
2006 const int maxLines = luaL_checkint(L, 1);
2007 if (maxLines < lineCount) {
2008 start = (lineCount - maxLines);
2009 }
2010 }
2011
2012 // table = { [1] = { text = string, zone = number}, etc... }
2013 lua_newtable(L);
2014
2015 unsigned int count = 0;
2016
2017 for (int i = start; i < lineCount; i++) {
2018 count++;
2019 lua_pushnumber(L, count);
2020 lua_newtable(L); {
2021 lua_pushliteral(L, "text");
2022 lua_pushsstring(L, lines[i].text);
2023 lua_rawset(L, -3);
2024 lua_pushliteral(L, "priority");
2025 lua_pushnumber(L, lines[i].level);
2026 lua_rawset(L, -3);
2027 }
2028 lua_rawset(L, -3);
2029 }
2030
2031 return 1;
2032 }
2033
2034
GetCurrentTooltip(lua_State * L)2035 int LuaUnsyncedRead::GetCurrentTooltip(lua_State* L)
2036 {
2037 lua_pushsstring(L, mouse->GetCurrentTooltip());
2038 return 1;
2039 }
2040
2041
GetKeyCode(lua_State * L)2042 int LuaUnsyncedRead::GetKeyCode(lua_State* L)
2043 {
2044 if (keyCodes == NULL) {
2045 return 0;
2046 }
2047
2048 const int keycode = keyCodes->GetCode(luaL_checksstring(L, 1));
2049 lua_pushnumber(L, SDL21_keysyms(keycode));
2050 return 1;
2051 }
2052
2053
GetKeySymbol(lua_State * L)2054 int LuaUnsyncedRead::GetKeySymbol(lua_State* L)
2055 {
2056 const int keycode = SDL12_keysyms(luaL_checkint(L, 1));
2057 lua_pushsstring(L, (keyCodes != NULL)? keyCodes->GetName(keycode): "");
2058 lua_pushsstring(L, (keyCodes != NULL)? keyCodes->GetDefaultName(keycode): "");
2059 return 2;
2060 }
2061
2062
GetKeyBindings(lua_State * L)2063 int LuaUnsyncedRead::GetKeyBindings(lua_State* L)
2064 {
2065 CKeySet ks;
2066
2067 if (!ks.Parse(luaL_checksstring(L, 1)))
2068 return 0;
2069 if (keyBindings == NULL)
2070 return 0;
2071
2072 const CKeyBindings::ActionList& actions = keyBindings->GetActionList(ks);
2073
2074 int i = 1;
2075 lua_newtable(L);
2076 for (const Action& action: actions) {
2077 lua_newtable(L);
2078 lua_pushsstring(L, action.command);
2079 lua_pushsstring(L, action.extra);
2080 lua_rawset(L, -3);
2081 LuaPushNamedString(L, "command", action.command);
2082 LuaPushNamedString(L, "extra", action.extra);
2083 LuaPushNamedString(L, "boundWith", action.boundWith);
2084 lua_rawseti(L, -2, i++);
2085 }
2086 return 1;
2087 }
2088
2089
GetActionHotKeys(lua_State * L)2090 int LuaUnsyncedRead::GetActionHotKeys(lua_State* L)
2091 {
2092 if (keyBindings == NULL)
2093 return 0;
2094
2095 const CKeyBindings::HotkeyList& hotkeys = keyBindings->GetHotkeys(luaL_checksstring(L, 1));
2096
2097 lua_newtable(L);
2098 int i = 1;
2099 for (const std::string& hotkey: hotkeys) {
2100 lua_pushsstring(L, hotkey);
2101 lua_rawseti(L, -2, i++);
2102 }
2103 return 1;
2104 }
2105
2106 /******************************************************************************/
2107
GetGroupList(lua_State * L)2108 int LuaUnsyncedRead::GetGroupList(lua_State* L)
2109 {
2110 if (grouphandlers[gu->myTeam] == NULL) {
2111 return 0;
2112 }
2113 lua_newtable(L);
2114
2115 unsigned int count = 0;
2116
2117 const vector<CGroup*>& groups = grouphandlers[gu->myTeam]->groups;
2118 vector<CGroup*>::const_iterator git;
2119 for (git = groups.begin(); git != groups.end(); ++git) {
2120 const CGroup* group = *git;
2121 if ((group != NULL) && !group->units.empty()) {
2122 lua_pushnumber(L, group->units.size());
2123 lua_rawseti(L, -2, group->id);
2124 count++;
2125 }
2126 }
2127 lua_pushnumber(L, count);
2128 return 2;
2129 }
2130
2131
GetSelectedGroup(lua_State * L)2132 int LuaUnsyncedRead::GetSelectedGroup(lua_State* L)
2133 {
2134 lua_pushnumber(L, selectedUnitsHandler.GetSelectedGroup());
2135 return 1;
2136 }
2137
2138
GetUnitGroup(lua_State * L)2139 int LuaUnsyncedRead::GetUnitGroup(lua_State* L)
2140 {
2141 CUnit* unit = ParseUnit(L, __FUNCTION__, 1);
2142 if (unit == NULL) {
2143 return 0;
2144 }
2145 if ((unit->team == gu->myTeam) && (unit->group)) {
2146 lua_pushnumber(L, unit->group->id);
2147 return 1;
2148 }
2149 return 0;
2150 }
2151
2152
2153 /******************************************************************************/
2154
GetGroupUnits(lua_State * L)2155 int LuaUnsyncedRead::GetGroupUnits(lua_State* L)
2156 {
2157 const int groupID = luaL_checkint(L, 1);
2158 const vector<CGroup*>& groups = grouphandlers[gu->myTeam]->groups;
2159 if ((groupID < 0) || ((size_t)groupID >= groups.size()) ||
2160 (groups[groupID] == NULL)) {
2161 return 0; // nils
2162 }
2163
2164 lua_newtable(L);
2165
2166 unsigned int count = 0;
2167
2168 const CUnitSet& groupUnits = groups[groupID]->units;
2169 CUnitSet::const_iterator it;
2170 for (it = groupUnits.begin(); it != groupUnits.end(); ++it) {
2171 count++;
2172 lua_pushnumber(L, (*it)->id);
2173 lua_rawseti(L, -2, count);
2174 }
2175
2176 return 1;
2177 }
2178
2179
GetGroupUnitsSorted(lua_State * L)2180 int LuaUnsyncedRead::GetGroupUnitsSorted(lua_State* L)
2181 {
2182 const int groupID = luaL_checkint(L, 1);
2183 const vector<CGroup*>& groups = grouphandlers[gu->myTeam]->groups;
2184 if ((groupID < 0) || ((size_t)groupID >= groups.size()) ||
2185 (groups[groupID] == NULL)) {
2186 return 0; // nils
2187 }
2188
2189 map<int, vector<CUnit*> > unitDefMap;
2190 const CUnitSet& groupUnits = groups[groupID]->units;
2191 CUnitSet::const_iterator it;
2192 for (it = groupUnits.begin(); it != groupUnits.end(); ++it) {
2193 CUnit* unit = *it;
2194 unitDefMap[unit->unitDef->id].push_back(unit);
2195 }
2196
2197 lua_newtable(L);
2198 map<int, vector<CUnit*> >::const_iterator mit;
2199 for (mit = unitDefMap.begin(); mit != unitDefMap.end(); ++mit) {
2200 lua_pushnumber(L, mit->first); // push the UnitDef index
2201 lua_newtable(L); {
2202 const vector<CUnit*>& v = mit->second;
2203 for (int i = 0; i < (int)v.size(); i++) {
2204 CUnit* unit = v[i];
2205 lua_pushnumber(L, unit->id);
2206 lua_rawseti(L, -2, i + 1);
2207 }
2208 }
2209 lua_rawset(L, -3);
2210 }
2211
2212 return 1;
2213 }
2214
2215
GetGroupUnitsCounts(lua_State * L)2216 int LuaUnsyncedRead::GetGroupUnitsCounts(lua_State* L)
2217 {
2218 const int groupID = luaL_checkint(L, 1);
2219 const vector<CGroup*>& groups = grouphandlers[gu->myTeam]->groups;
2220 if ((groupID < 0) || ((size_t)groupID >= groups.size()) ||
2221 (groups[groupID] == NULL)) {
2222 return 0; // nils
2223 }
2224
2225 map<int, int> countMap;
2226 const CUnitSet& groupUnits = groups[groupID]->units;
2227 CUnitSet::const_iterator it;
2228 for (it = groupUnits.begin(); it != groupUnits.end(); ++it) {
2229 CUnit* unit = *it;
2230 const int udID = unit->unitDef->id;
2231 map<int, int>::iterator mit = countMap.find(udID);
2232 if (mit == countMap.end()) {
2233 countMap[udID] = 1;
2234 } else {
2235 mit->second++;
2236 }
2237 }
2238
2239 lua_newtable(L);
2240 map<int, int>::const_iterator mit;
2241 for (mit = countMap.begin(); mit != countMap.end(); ++mit) {
2242 lua_pushnumber(L, mit->second); // push the UnitDef unit count
2243 lua_rawseti(L, -2, mit->first); // push the UnitDef index
2244 }
2245
2246 return 1;
2247 }
2248
2249
GetGroupUnitsCount(lua_State * L)2250 int LuaUnsyncedRead::GetGroupUnitsCount(lua_State* L)
2251 {
2252 const int groupID = luaL_checkint(L, 1);
2253 const vector<CGroup*>& groups = grouphandlers[gu->myTeam]->groups;
2254 if ((groupID < 0) || ((size_t)groupID >= groups.size()) ||
2255 (groups[groupID] == NULL)) {
2256 return 0; // nils
2257 }
2258 lua_pushnumber(L, groups[groupID]->units.size());
2259 return 1;
2260 }
2261
2262
2263 /******************************************************************************/
2264 /******************************************************************************/
2265
GetPlayerRoster(lua_State * L)2266 int LuaUnsyncedRead::GetPlayerRoster(lua_State* L)
2267 {
2268 const PlayerRoster::SortType oldSortType = playerRoster.GetSortType();
2269
2270 if (!lua_isnone(L, 1)) {
2271 playerRoster.SetSortTypeByCode((PlayerRoster::SortType) luaL_checkint(L, 1));
2272 }
2273
2274 const bool includePathingFlag = luaL_optboolean(L, 2, false);
2275
2276 int count;
2277 const std::vector<int>& players = playerRoster.GetIndices(&count, includePathingFlag);
2278
2279 playerRoster.SetSortTypeByCode(oldSortType); // revert
2280
2281 lua_createtable(L, count, 0);
2282 for (int i = 0; i < count; i++) {
2283 AddPlayerToRoster(L, players[i], includePathingFlag);
2284 lua_rawseti(L, -2, i + 1);
2285 }
2286
2287 return 1;
2288 }
2289
GetPlayerTraffic(lua_State * L)2290 int LuaUnsyncedRead::GetPlayerTraffic(lua_State* L)
2291 {
2292 const int playerID = luaL_checkint(L, 1);
2293 const int packetID = (int)luaL_optnumber(L, 2, -1);
2294
2295 const std::map<int, CGame::PlayerTrafficInfo>& traffic
2296 = game->GetPlayerTraffic();
2297 std::map<int, CGame::PlayerTrafficInfo>::const_iterator it;
2298 it = traffic.find(playerID);
2299 if (it == traffic.end()) {
2300 lua_pushnumber(L, -1);
2301 return 1;
2302 }
2303
2304 // only allow viewing stats for specific packet types
2305 if (
2306 (playerID != -1) && // all system counts can be read
2307 (playerID != gu->myPlayerNum) && // all self counts can be read
2308 (packetID != -1) &&
2309 (packetID != NETMSG_CHAT) &&
2310 (packetID != NETMSG_PAUSE) &&
2311 (packetID != NETMSG_LUAMSG) &&
2312 (packetID != NETMSG_STARTPOS) &&
2313 (packetID != NETMSG_USER_SPEED)
2314 ) {
2315 lua_pushnumber(L, -1);
2316 return 1;
2317 }
2318
2319 const CGame::PlayerTrafficInfo& pti = it->second;
2320 if (packetID == -1) {
2321 lua_pushnumber(L, pti.total);
2322 return 1;
2323 }
2324 std::map<int, int>::const_iterator pit = pti.packets.find(packetID);
2325 if (pit == pti.packets.end()) {
2326 lua_pushnumber(L, -1);
2327 return 1;
2328 }
2329 lua_pushnumber(L, pit->second);
2330 return 1;
2331 }
2332
GetPlayerStatistics(lua_State * L)2333 int LuaUnsyncedRead::GetPlayerStatistics(lua_State* L)
2334 {
2335 const int playerID = luaL_checkint(L, 1);
2336 if (!playerHandler->IsValidPlayer(playerID)) {
2337 return 0;
2338 }
2339
2340 const CPlayer* player = playerHandler->Player(playerID);
2341 if (player == NULL) {
2342 return 0;
2343 }
2344
2345 const PlayerStatistics& pStats = player->currentStats;
2346
2347 lua_pushnumber(L, pStats.mousePixels);
2348 lua_pushnumber(L, pStats.mouseClicks);
2349 lua_pushnumber(L, pStats.keyPresses);
2350 lua_pushnumber(L, pStats.numCommands);
2351 lua_pushnumber(L, pStats.unitCommands);
2352
2353 return 5;
2354 }
2355
2356
2357 /******************************************************************************/
2358 /******************************************************************************/
2359
GetDrawSelectionInfo(lua_State * L)2360 int LuaUnsyncedRead::GetDrawSelectionInfo(lua_State* L)
2361 {
2362 lua_pushboolean(L, guihandler ? guihandler->GetDrawSelectionInfo() : 0);
2363 return 1;
2364 }
2365
2366
2367 /******************************************************************************/
2368 /******************************************************************************/
2369
GetConfigParams(lua_State * L)2370 int LuaUnsyncedRead::GetConfigParams(lua_State* L)
2371 {
2372 ConfigVariable::MetaDataMap cfgmap = ConfigVariable::GetMetaDataMap();
2373 lua_createtable(L, cfgmap.size(), 0);
2374
2375 int i = 1;
2376 for (ConfigVariable::MetaDataMap::const_iterator it = cfgmap.begin(); it != cfgmap.end(); ++it)
2377 {
2378 const ConfigVariableMetaData* meta = it->second;
2379
2380 lua_createtable(L, 0, 9);
2381
2382 lua_pushliteral(L, "name");
2383 lua_pushsstring(L, meta->GetKey());
2384 lua_rawset(L, -3);
2385 if (meta->GetDescription().IsSet()) {
2386 lua_pushliteral(L, "description");
2387 lua_pushsstring(L, meta->GetDescription().ToString());
2388 lua_rawset(L, -3);
2389 }
2390 lua_pushliteral(L, "type");
2391 lua_pushsstring(L, meta->GetType());
2392 lua_rawset(L, -3);
2393 if (meta->GetDefaultValue().IsSet()) {
2394 lua_pushliteral(L, "defaultValue");
2395 lua_pushsstring(L, meta->GetDefaultValue().ToString());
2396 lua_rawset(L, -3);
2397 }
2398 if (meta->GetMinimumValue().IsSet()) {
2399 lua_pushliteral(L, "minimumValue");
2400 lua_pushsstring(L, meta->GetMinimumValue().ToString());
2401 lua_rawset(L, -3);
2402 }
2403 if (meta->GetMaximumValue().IsSet()) {
2404 lua_pushliteral(L, "maximumValue");
2405 lua_pushsstring(L, meta->GetMaximumValue().ToString());
2406 lua_rawset(L, -3);
2407 }
2408 if (meta->GetSafemodeValue().IsSet()) {
2409 lua_pushliteral(L, "safemodeValue");
2410 lua_pushsstring(L, meta->GetSafemodeValue().ToString());
2411 lua_rawset(L, -3);
2412 }
2413 if (meta->GetDeclarationFile().IsSet()) {
2414 lua_pushliteral(L, "declarationFile");
2415 lua_pushsstring(L, meta->GetDeclarationFile().ToString());
2416 lua_rawset(L, -3);
2417 }
2418 if (meta->GetDeclarationLine().IsSet()) {
2419 lua_pushliteral(L, "declarationLine");
2420 lua_pushnumber(L, meta->GetDeclarationLine().Get());
2421 lua_rawset(L, -3);
2422 }
2423 if (meta->GetReadOnly().IsSet()) {
2424 lua_pushliteral(L, "readOnly");
2425 lua_pushboolean(L, !!meta->GetReadOnly().Get());
2426 lua_rawset(L, -3);
2427 }
2428
2429 lua_rawseti(L, -2, i++);
2430 }
2431 return 1;
2432 }
2433
2434 /******************************************************************************/
2435 /******************************************************************************/
2436
GetLogSections(lua_State * L)2437 int LuaUnsyncedRead::GetLogSections(lua_State* L) {
2438 const int numLogSections = log_filter_section_getNumRegisteredSections();
2439
2440 lua_createtable(L, 0, numLogSections);
2441 for (int i = 0; i < numLogSections; ++i) {
2442 const char* sectionName = log_filter_section_getRegisteredIndex(i);
2443 const int logLevel = log_filter_section_getMinLevel(sectionName);
2444
2445 lua_pushstring(L, sectionName);
2446 lua_pushnumber(L, logLevel);
2447 lua_rawset(L, -3);
2448 }
2449
2450 return 1;
2451 }
2452
2453 /******************************************************************************/
2454 /******************************************************************************/
2455