1 /*
2 LUA_SCRIPT.CPP
3
4 Copyright (C) 2003 and beyond by Matthew Hielscher
5 and the "Aleph One" developers
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 This license is contained in the file "COPYING",
18 which is included with this source code; it is available online at
19 http://www.gnu.org/licenses/gpl.html
20
21 Controls the loading and execution of Lua scripts.
22 */
23
24 /*
25 Created 5-20-03 by Matthew Hielscher
26 Controls the loading and execution of Lua scripts.
27
28 Matthew Hielscher, 05-28-03
29 Changed the error code to be much more graceful (no more quitting after an error)
30 Also incorporated tiennou's functions
31
32 tiennou, 06/23/03
33 Added stuff on platforms (speed, heights, movement), terminals (text index), &polygon (heights).
34
35 tiennou, 06/25/03
36 Removed the last useless logError around. They prevented some functions to behave properly.
37 Added L_Get_Player_Angle, returns player->facing & player->elevation.
38 Got rid of all the cast-related warnings in there (Thanks Br'fin !).
39
40 jkvw, 07/03/03
41 Added recharge panel triggers, exposed A1's internal random number generators, and item creation.
42
43 jkvw, 07/07/03
44 Cleaned up some of the "odd" behaviors. (e.g., new_monster/new_item would spawn their things at incorrect height.)
45 Added triggers for player revival/death.
46
47 tiennou, 07/20/03
48 Added mnemonics for sounds, changed L_Start_Fade to L_Screen_Fade, added side_index parameter to L_Call_Start/End_Refuel and updated the docs with the info I had...
49
50 jkvw, 07/21/03
51 Lua access to network scoring and network compass, and get_player_name.
52
53 Woody Zenfell, 08/05/03
54 Refactored L_Call_* to share common code; reporting runtime Lua script errors via screen_printf
55
56 jkvw, 09/16/03
57 L_Call_* no longer need guarding with #ifdef HAVE_LUA
58 */
59
60 // cseries defines HAVE_LUA on A1/SDL
61 #include "cseries.h"
62
63 #include "mouse.h"
64 #include "interface.h"
65
66 #ifdef HAVE_LUA
67 extern "C"
68 {
69 #include "lua.h"
70 #include "lauxlib.h"
71 #include "lualib.h"
72 }
73 #endif
74
75 #include <string>
76 #include <stdlib.h>
77 #include <set>
78 #include <unordered_map>
79
80 #include "alephversion.h"
81 #include "screen.h"
82 #include "tags.h"
83 #include "player.h"
84 #include "render.h"
85 #include "shell.h"
86 #include "Logging.h"
87 #include "lightsource.h"
88 #include "game_window.h"
89 #include "items.h"
90 #include "platforms.h"
91 #include "media.h"
92 #include "weapons.h"
93 #include "monsters.h"
94 #include "flood_map.h"
95 #include "vbl.h"
96 #include "fades.h"
97 #include "physics_models.h"
98 #include "Crosshairs.h"
99 #include "OGL_Setup.h"
100 #include "SoundManager.h"
101 #include "world.h"
102 #include "computer_interface.h"
103 #include "network.h"
104 #include "network_games.h"
105 #include "Random.h"
106 #include "Console.h"
107 #include "Music.h"
108 #include "ViewControl.h"
109 #include "preferences.h"
110 #include "BStream.h"
111 #include "Plugins.h"
112
113 #include "lua_script.h"
114 #include "lua_map.h"
115 #include "lua_monsters.h"
116 #include "lua_objects.h"
117 #include "lua_player.h"
118 #include "lua_projectiles.h"
119 #include "lua_saved_objects.h"
120 #include "lua_serialize.h"
121
122 #include <boost/bind.hpp>
123 #include <boost/ptr_container/ptr_map.hpp>
124 #include <boost/shared_ptr.hpp>
125 #include <boost/iostreams/device/array.hpp>
126 #include <boost/iostreams/stream_buffer.hpp>
127 namespace io = boost::iostreams;
128
129 #define DONT_REPEAT_DEFINITIONS
130 #include "item_definitions.h"
131 #include "monster_definitions.h"
132
133
134 bool use_lua_compass[MAXIMUM_NUMBER_OF_NETWORK_PLAYERS];
135 bool can_wield_weapons[MAXIMUM_NUMBER_OF_NETWORK_PLAYERS];
136 world_point2d lua_compass_beacons[MAXIMUM_NUMBER_OF_NETWORK_PLAYERS];
137 short lua_compass_states[MAXIMUM_NUMBER_OF_NETWORK_PLAYERS];
138
139 static ActionQueues* sLuaActionQueues = 0;
GetLuaActionQueues()140 ActionQueues* GetLuaActionQueues() { return sLuaActionQueues; }
141
142 int game_scoring_mode = _game_of_most_points;
143 int game_end_condition = _game_normal_end_condition;
144
GetLuaScoringMode()145 int GetLuaScoringMode() {
146 return game_scoring_mode;
147 }
148
149 #ifndef HAVE_LUA
150
L_Call_Init(bool)151 void L_Call_Init(bool) {}
L_Call_Cleanup()152 void L_Call_Cleanup() {}
L_Call_Idle()153 void L_Call_Idle() {}
L_Call_PostIdle()154 void L_Call_PostIdle() {}
L_Call_Sent_Message(const char * username,const char * message)155 void L_Call_Sent_Message(const char* username, const char* message) {}
L_Call_Start_Refuel(short type,short player_index,short panel_side_index)156 void L_Call_Start_Refuel(short type, short player_index, short panel_side_index) {}
L_Call_End_Refuel(short type,short player_index,short panel_side_index)157 void L_Call_End_Refuel(short type, short player_index, short panel_side_index) {}
L_Call_Tag_Switch(short tag,short player_index,short)158 void L_Call_Tag_Switch(short tag, short player_index, short) {}
L_Call_Light_Switch(short light,short player_index,short)159 void L_Call_Light_Switch(short light, short player_index, short) {}
L_Call_Platform_Switch(short platform,short player_index,short)160 void L_Call_Platform_Switch(short platform, short player_index, short) {}
L_Call_Terminal_Enter(short terminal_id,short player_index)161 void L_Call_Terminal_Enter(short terminal_id, short player_index) {}
L_Call_Terminal_Exit(short terminal_id,short player_index)162 void L_Call_Terminal_Exit(short terminal_id, short player_index) {}
L_Call_Pattern_Buffer(short side_index,short player_index)163 void L_Call_Pattern_Buffer(short side_index, short player_index) {}
L_Call_Got_Item(short type,short player_index)164 void L_Call_Got_Item(short type, short player_index) {}
L_Call_Light_Activated(short index)165 void L_Call_Light_Activated(short index) {}
L_Call_Platform_Activated(short index)166 void L_Call_Platform_Activated(short index) {}
L_Call_Player_Revived(short player_index)167 void L_Call_Player_Revived(short player_index) {}
L_Call_Player_Killed(short player_index,short aggressor_player_index,short action,short projectile_index)168 void L_Call_Player_Killed(short player_index, short aggressor_player_index, short action, short projectile_index) {}
L_Call_Monster_Killed(short monster_index,short aggressor_player_index,short projectile_index)169 void L_Call_Monster_Killed(short monster_index, short aggressor_player_index, short projectile_index) {}
L_Call_Monster_Damaged(short monster_index,short aggressor_monster_index,int16 damage_type,short damage_amount,short projectile_index)170 void L_Call_Monster_Damaged(short monster_index, short aggressor_monster_index, int16 damage_type, short damage_amount, short projectile_index) { }
L_Call_Player_Damaged(short player_index,short aggressor_player_index,short aggressor_monster_index,int16 damage_type,short damage_amount,short projectile_index)171 void L_Call_Player_Damaged(short player_index, short aggressor_player_index, short aggressor_monster_index, int16 damage_type, short damage_amount, short projectile_index) {}
L_Call_Projectile_Detonated(short type,short owner_index,short polygon,world_point3d location)172 void L_Call_Projectile_Detonated(short type, short owner_index, short polygon, world_point3d location) {}
L_Call_Projectile_Switch(short,short)173 void L_Call_Projectile_Switch(short, short) {}
L_Call_Projectile_Created(short projectile_index)174 void L_Call_Projectile_Created(short projectile_index) {}
L_Call_Item_Created(short item_index)175 void L_Call_Item_Created(short item_index) {}
176
L_Invalidate_Effect(short)177 void L_Invalidate_Effect(short) { }
L_Invalidate_Monster(short)178 void L_Invalidate_Monster(short) { }
L_Invalidate_Projectile(short)179 void L_Invalidate_Projectile(short) { }
L_Invalidate_Object(short)180 void L_Invalidate_Object(short) { }
181
LoadLuaScript(const char * buffer,size_t len,const char * desc)182 bool LoadLuaScript(const char *buffer, size_t len, const char *desc) { /* Should never get here! */ return false; }
RunLuaScript()183 bool RunLuaScript() {
184 for (int i = 0; i < MAXIMUM_NUMBER_OF_NETWORK_PLAYERS; i++)
185 use_lua_compass [i] = false;
186 return false;
187 }
CloseLuaScript()188 void CloseLuaScript() {}
189
ToggleLuaMute()190 void ToggleLuaMute() {}
ResetLuaMute()191 void ResetLuaMute() {}
192
UseLuaCameras()193 bool UseLuaCameras() { return false; }
LuaPlayerCanWieldWeapons(short)194 bool LuaPlayerCanWieldWeapons(short) { return true; }
195
GetLuaGameEndCondition()196 int GetLuaGameEndCondition() {
197 return _game_normal_end_condition;
198 }
199
200 #else /* HAVE_LUA */
201
202 bool mute_lua = false;
203
204 // Steal all this stuff
205 extern void ShootForTargetPoint(bool ThroughWalls, world_point3d& StartPosition, world_point3d& EndPosition, short& Polygon);
206 extern struct physics_constants *get_physics_constants_for_model(short physics_model, uint32 action_flags);
207 extern void draw_panels();
208
209 extern bool MotionSensorActive;
210 extern bool insecure_lua;
211
212 extern void instantiate_physics_variables(struct physics_constants *constants, struct physics_variables *variables, short player_index, bool first_time, bool take_action);
213
214 extern struct view_data *world_view;
215 extern struct static_data *static_world;
216
217 static const luaL_Reg lualibs[] = {
218 {"", luaopen_base},
219 {LUA_TABLIBNAME, luaopen_table},
220 {LUA_STRLIBNAME, luaopen_string},
221 {LUA_BITLIBNAME, luaopen_bit32},
222 {LUA_MATHLIBNAME, luaopen_math},
223 {LUA_DBLIBNAME, luaopen_debug},
224 {NULL, NULL}
225 };
226
227 static const luaL_Reg insecurelibs[] = {
228 {LUA_IOLIBNAME, luaopen_io},
229 {LUA_OSLIBNAME, luaopen_os},
230 {NULL, NULL}
231 };
232
L_Persistent_Table_Key()233 void* L_Persistent_Table_Key()
234 {
235 static const char *key = "persist";
236 return const_cast<char*>(key);
237 }
238
239 std::map<int, std::string> PassedLuaState;
240 std::map<int, std::string> SavedLuaState;
241
242 class LuaState
243 {
244 friend bool CollectLuaStats(std::map<std::string, std::string>&, std::map<std::string, std::string>&);
245 public:
LuaState()246 LuaState() : running_(false), num_scripts_(0) {
247 state_.reset(luaL_newstate(), lua_close);
248 }
249
~LuaState()250 virtual ~LuaState() {
251 }
252
253 public:
254
255 bool Load(const char *buffer, size_t len, const char *desc);
Loaded()256 bool Loaded() { return num_scripts_ > 0; }
Running()257 bool Running() { return running_; }
258 bool Run();
Stop()259 void Stop() { running_ = false; }
Matches(lua_State * state)260 bool Matches(lua_State *state) { return state == State(); }
261 void MarkCollections(std::set<short>* collections);
262 void ExecuteCommand(const std::string& line);
263 std::string SavePassed();
264 std::string SaveAll();
265
Initialize()266 virtual void Initialize() {
267 const luaL_Reg *lib = lualibs;
268 for (; lib->func; lib++)
269 {
270 luaL_requiref(State(), lib->name, lib->func, 1);
271 lua_pop(State(), 1);
272 }
273
274 if (insecure_lua)
275 {
276 const luaL_Reg *lib = insecurelibs;
277 for (; lib->func; lib++)
278 {
279 luaL_requiref(State(), lib->name, lib->func, 1);
280 lua_pop(State(), 1);
281 }
282 }
283
284 // set up a persistence table in the registry
285 lua_pushlightuserdata(State(), (void *) L_Persistent_Table_Key());
286 lua_newtable(State());
287 lua_settable(State(), LUA_REGISTRYINDEX);
288
289 RegisterFunctions();
290 LoadCompatibility();
291 }
292
SetSearchPath(const std::string & path)293 virtual void SetSearchPath(const std::string& path) {
294 L_Set_Search_Path(State(), path);
295 }
296
297 protected:
298 bool GetTrigger(const char *trigger);
299 void CallTrigger(int numArgs = 0);
300
301 virtual void RegisterFunctions();
302 virtual void LoadCompatibility();
303
304 boost::shared_ptr<lua_State> state_;
State()305 lua_State* State() { return state_.get(); }
306
307 public:
308 // triggers
309 void Init(bool fRestoringSaved);
310 void Idle();
311 void Cleanup();
312 void PostIdle();
313 void StartRefuel(short type, short player_index, short panel_side_index);
314 void EndRefuel(short type, short player_index, short panel_side_index);
315 void TagSwitch(short tag, short player_index, short side_index);
316 void LightSwitch(short tag, short player_index, short side_index);
317 void PlatformSwitch(short tag, short player_index, short side_index);
318 void ProjectileSwitch(short side_index, short projectile_index);
319 void TerminalEnter(short terminal_id, short player_index);
320 void TerminalExit(short terminal_id, short player_index);
321 void PatternBuffer(short side_index, short player_index);
322 void GotItem(short type, short player_index);
323 void LightActivated(short index);
324 void PlatformActivated(short index);
325 void PlayerRevived(short player_index);
326 void PlayerKilled(short player_index, short aggressor_player_index, short action, short projectile_index);
327 void MonsterKilled(short monster_index, short aggressor_player_index, short projectile_index);
328 void MonsterDamaged(short monster_index, short aggressor_monster_index, int16 damage_type, short damage_amount, short projectile_index);
329 void PlayerDamaged(short player_index, short aggressor_player_index, short aggressor_monster_index, int16 damage_type, short damage_amount, short projectile_index);
330 void ProjectileDetonated(short type, short owner_index, short polygon, world_point3d location);
331 void ProjectileCreated(short projectile_index);
332 void ItemCreated(short item_index);
333
334 void InvalidateEffect(short effect_index);
335 void InvalidateMonster(short monster_index);
336 void InvalidateProjectile(short projectile_index);
337 void InvalidateObject(short object_index);
338
339 int RestorePassed(const std::string& s);
340 int RestoreAll(const std::string& s);
341
342 private:
343 bool running_;
344 int num_scripts_;
345 };
346
347 typedef LuaState EmbeddedLuaState;
348 typedef LuaState NetscriptState;
349 typedef LuaState StatsLuaState;
350
351 class SoloScriptState : public LuaState
352 {
353 public:
SoloScriptState()354 SoloScriptState() : LuaState() { }
355
Initialize()356 void Initialize() {
357 LuaState::Initialize();
358 luaL_requiref(State(), LUA_IOLIBNAME, luaopen_io, 1);
359 lua_pop(State(), 1);
360 }
361 };
362
GetTrigger(const char * trigger)363 bool LuaState::GetTrigger(const char* trigger)
364 {
365 if (!running_)
366 return false;
367
368 lua_getglobal(State(), "Triggers");
369 if (!lua_istable(State(), -1))
370 {
371 lua_pop(State(), 1);
372 return false;
373 }
374
375 lua_pushstring(State(), trigger);
376 lua_gettable(State(), -2);
377 if (!lua_isfunction(State(), -1))
378 {
379 lua_pop(State(), 2);
380 return false;
381 }
382
383 lua_remove(State(), -2);
384 return true;
385 }
386
CallTrigger(int numArgs)387 void LuaState::CallTrigger(int numArgs)
388 {
389 if (lua_pcall(State(), numArgs, 0, 0) == LUA_ERRRUN)
390 L_Error(lua_tostring(State(), -1));
391 }
392
Init(bool fRestoringSaved)393 void LuaState::Init(bool fRestoringSaved)
394 {
395 if (GetTrigger("init"))
396 {
397 lua_pushboolean(State(), fRestoringSaved);
398 CallTrigger(1);
399 }
400 }
401
Idle()402 void LuaState::Idle()
403 {
404 if (GetTrigger("idle"))
405 CallTrigger();
406 }
407
Cleanup()408 void LuaState::Cleanup()
409 {
410 if (GetTrigger("cleanup"))
411 CallTrigger();
412 }
413
PostIdle()414 void LuaState::PostIdle()
415 {
416 if (GetTrigger("postidle"))
417 CallTrigger();
418 }
419
StartRefuel(short type,short player_index,short panel_side_index)420 void LuaState::StartRefuel(short type, short player_index, short panel_side_index)
421 {
422 if (GetTrigger("start_refuel"))
423 {
424 Lua_ControlPanelClass::Push(State(), type);
425 Lua_Player::Push(State(), player_index);
426 Lua_Side::Push(State(), panel_side_index);
427 CallTrigger(3);
428 }
429 }
430
EndRefuel(short type,short player_index,short panel_side_index)431 void LuaState::EndRefuel(short type, short player_index, short panel_side_index)
432 {
433 if (GetTrigger("end_refuel"))
434 {
435 Lua_ControlPanelClass::Push(State(), type);
436 Lua_Player::Push(State(), player_index);
437 Lua_Side::Push(State(), panel_side_index);
438 CallTrigger(3);
439 }
440 }
441
TagSwitch(short tag,short player_index,short side_index)442 void LuaState::TagSwitch(short tag, short player_index, short side_index)
443 {
444 if (GetTrigger("tag_switch"))
445 {
446 Lua_Tag::Push(State(), tag);
447 Lua_Player::Push(State(), player_index);
448 Lua_Side::Push(State(), side_index);
449 CallTrigger(3);
450 }
451 }
452
LightSwitch(short light,short player_index,short side_index)453 void LuaState::LightSwitch(short light, short player_index, short side_index)
454 {
455 if (GetTrigger("light_switch"))
456 {
457 Lua_Light::Push(State(), light);
458 Lua_Player::Push(State(), player_index);
459 Lua_Side::Push(State(), side_index);
460 CallTrigger(3);
461 }
462 }
463
PlatformSwitch(short platform,short player_index,short side_index)464 void LuaState::PlatformSwitch(short platform, short player_index, short side_index)
465 {
466 if (GetTrigger("platform_switch"))
467 {
468 Lua_Polygon::Push(State(), platform);
469 Lua_Player::Push(State(), player_index);
470 Lua_Side::Push(State(), side_index);
471 CallTrigger(3);
472 }
473 }
474
ProjectileSwitch(short side_index,short projectile_index)475 void LuaState::ProjectileSwitch(short side_index, short projectile_index)
476 {
477 if (GetTrigger("projectile_switch"))
478 {
479 Lua_Projectile::Push(State(), projectile_index);
480 Lua_Side::Push(State(), side_index);
481 CallTrigger(2);
482 }
483 }
484
TerminalEnter(short terminal_id,short player_index)485 void LuaState::TerminalEnter(short terminal_id, short player_index)
486 {
487 if (GetTrigger("terminal_enter"))
488 {
489 Lua_Terminal::Push(State(), terminal_id);
490 Lua_Player::Push(State(), player_index);
491 CallTrigger(2);
492 }
493 }
494
TerminalExit(short terminal_id,short player_index)495 void LuaState::TerminalExit(short terminal_id, short player_index)
496 {
497 if (GetTrigger("terminal_exit"))
498 {
499 Lua_Terminal::Push(State(), terminal_id);
500 Lua_Player::Push(State(), player_index);
501 CallTrigger(2);
502 }
503 }
504
PatternBuffer(short side_index,short player_index)505 void LuaState::PatternBuffer(short side_index, short player_index)
506 {
507 if (GetTrigger("pattern_buffer"))
508 {
509 Lua_Side::Push(State(), side_index);
510 Lua_Player::Push(State(), player_index);
511 CallTrigger(2);
512 }
513 }
514
GotItem(short type,short player_index)515 void LuaState::GotItem(short type, short player_index)
516 {
517 if (GetTrigger("got_item"))
518 {
519 Lua_ItemType::Push(State(), type);
520 Lua_Player::Push(State(), player_index);
521 CallTrigger(2);
522 }
523 }
524
LightActivated(short index)525 void LuaState::LightActivated(short index)
526 {
527 if (GetTrigger("light_activated"))
528 {
529 Lua_Light::Push(State(), index);
530 CallTrigger(1);
531 }
532 }
533
PlatformActivated(short index)534 void LuaState::PlatformActivated(short index)
535 {
536 if (GetTrigger("platform_activated"))
537 {
538 Lua_Polygon::Push(State(), index);
539 CallTrigger(1);
540 }
541 }
542
PlayerRevived(short player_index)543 void LuaState::PlayerRevived (short player_index)
544 {
545 if (GetTrigger("player_revived"))
546 {
547 Lua_Player::Push(State(), player_index);
548 CallTrigger(1);
549 }
550 }
551
PlayerKilled(short player_index,short aggressor_player_index,short action,short projectile_index)552 void LuaState::PlayerKilled (short player_index, short aggressor_player_index, short action, short projectile_index)
553 {
554 if (GetTrigger("player_killed"))
555 {
556 Lua_Player::Push(State(), player_index);
557
558 if (aggressor_player_index != -1)
559 Lua_Player::Push(State(), aggressor_player_index);
560 else
561 lua_pushnil(State());
562
563 Lua_MonsterAction::Push(State(), action);
564 if (projectile_index != -1)
565 Lua_Projectile::Push(State(), projectile_index);
566 else
567 lua_pushnil(State());
568
569 CallTrigger(4);
570 }
571 }
572
MonsterKilled(short monster_index,short aggressor_player_index,short projectile_index)573 void LuaState::MonsterKilled (short monster_index, short aggressor_player_index, short projectile_index)
574 {
575 if (GetTrigger("monster_killed"))
576 {
577 Lua_Monster::Push(State(), monster_index);
578 if (aggressor_player_index != -1)
579 Lua_Player::Push(State(), aggressor_player_index);
580 else
581 lua_pushnil(State());
582
583 if (projectile_index != -1)
584 Lua_Projectile::Push(State(), projectile_index);
585 else
586 lua_pushnil(State());
587
588 CallTrigger(3);
589 }
590 }
591
MonsterDamaged(short monster_index,short aggressor_monster_index,int16 damage_type,short damage_amount,short projectile_index)592 void LuaState::MonsterDamaged(short monster_index, short aggressor_monster_index, int16 damage_type, short damage_amount, short projectile_index)
593 {
594 if (GetTrigger("monster_damaged"))
595 {
596 Lua_Monster::Push(State(), monster_index);
597 if (aggressor_monster_index != -1)
598 Lua_Monster::Push(State(), aggressor_monster_index);
599 else
600 lua_pushnil(State());
601
602 Lua_DamageType::Push(State(), damage_type);
603 lua_pushnumber(State(), damage_amount);
604
605 if (projectile_index != -1)
606 Lua_Projectile::Push(State(), projectile_index);
607 else
608 lua_pushnil(State());
609
610 CallTrigger(5);
611 }
612
613 }
614
PlayerDamaged(short player_index,short aggressor_player_index,short aggressor_monster_index,int16 damage_type,short damage_amount,short projectile_index)615 void LuaState::PlayerDamaged (short player_index, short aggressor_player_index, short aggressor_monster_index, int16 damage_type, short damage_amount, short projectile_index)
616 {
617 if (GetTrigger("player_damaged"))
618 {
619 Lua_Player::Push(State(), player_index);
620
621 if (aggressor_player_index != -1)
622 Lua_Player::Push(State(), aggressor_player_index);
623 else
624 lua_pushnil(State());
625
626 if (aggressor_monster_index != -1)
627 Lua_Monster::Push(State(), aggressor_monster_index);
628 else
629 lua_pushnil(State());
630
631 Lua_DamageType::Push(State(), damage_type);
632 lua_pushnumber(State(), damage_amount);
633
634 if (projectile_index != -1)
635 Lua_Projectile::Push(State(), projectile_index);
636 else
637 lua_pushnil(State());
638
639 CallTrigger(6);
640 }
641 }
642
ProjectileDetonated(short type,short owner_index,short polygon,world_point3d location)643 void LuaState::ProjectileDetonated(short type, short owner_index, short polygon, world_point3d location)
644 {
645 if (GetTrigger("projectile_detonated"))
646 {
647 Lua_ProjectileType::Push(State(), type);
648 if (owner_index != -1)
649 Lua_Monster::Push(State(), owner_index);
650 else
651 lua_pushnil(State());
652 Lua_Polygon::Push(State(), polygon);
653 lua_pushnumber(State(), location.x / (double)WORLD_ONE);
654 lua_pushnumber(State(), location.y / (double)WORLD_ONE);
655 lua_pushnumber(State(), location.z / (double)WORLD_ONE);
656
657 CallTrigger(6);
658 }
659 }
660
ProjectileCreated(short projectile_index)661 void LuaState::ProjectileCreated (short projectile_index)
662 {
663 if (GetTrigger("projectile_created"))
664 {
665 Lua_Projectile::Push(State(), projectile_index);
666 CallTrigger(1);
667 }
668 }
669
ItemCreated(short item_index)670 void LuaState::ItemCreated (short item_index)
671 {
672 if (GetTrigger("item_created"))
673 {
674 Lua_Item::Push(State(), item_index);
675 CallTrigger(1);
676 }
677 }
678
InvalidateEffect(short effect_index)679 void LuaState::InvalidateEffect(short effect_index)
680 {
681 if (!running_) return;
682
683 Lua_Effect::Invalidate(State(), effect_index);
684 }
685
InvalidateMonster(short monster_index)686 void LuaState::InvalidateMonster(short monster_index)
687 {
688 if (!running_) return;
689
690 Lua_Monster::Invalidate(State(), monster_index);
691 }
692
InvalidateProjectile(short projectile_index)693 void LuaState::InvalidateProjectile(short projectile_index)
694 {
695 if (!running_) return;
696
697 Lua_Projectile::Invalidate(State(), projectile_index);
698 }
699
InvalidateObject(short object_index)700 void LuaState::InvalidateObject(short object_index)
701 {
702 if (!running_) return;
703
704 object_data *object = GetMemberWithBounds(objects, object_index, MAXIMUM_OBJECTS_PER_MAP);
705 if (GET_OBJECT_OWNER(object) == _object_is_item)
706 {
707 Lua_Item::Invalidate(State(), object_index);
708 }
709 else if (Lua_Scenery::Valid(object_index))
710 {
711 Lua_Scenery::Invalidate(State(), object_index);
712 }
713 }
714
715 static char L_SEARCH_PATH_KEY[] = "search_path";
716
L_Set_Search_Path(lua_State * L,const std::string & path)717 void L_Set_Search_Path(lua_State* L, const std::string& path)
718 {
719 lua_pushlightuserdata(L, reinterpret_cast<void*>(L_SEARCH_PATH_KEY));
720 lua_pushstring(L, path.c_str());
721 lua_settable(L, LUA_REGISTRYINDEX);
722 }
723
L_Get_Search_Path(lua_State * L)724 std::string L_Get_Search_Path(lua_State* L)
725 {
726 lua_pushlightuserdata(L, reinterpret_cast<void*>(L_SEARCH_PATH_KEY));
727 lua_gettable(L, LUA_REGISTRYINDEX);
728 if (lua_isstring(L, -1))
729 {
730 std::string path = lua_tostring(L, -1);
731 lua_pop(L, 1);
732 return path;
733 }
734 else
735 {
736 lua_pop(L, 1);
737 return std::string();
738 }
739
740 }
741
742 static char L_PROPER_ITEM_ACCOUNTING_KEY[] = "proper_item_accounting";
743
L_Set_Proper_Item_Accounting(lua_State * L,bool value)744 void L_Set_Proper_Item_Accounting(lua_State* L, bool value)
745 {
746 lua_pushlightuserdata(L, reinterpret_cast<void*>(L_PROPER_ITEM_ACCOUNTING_KEY));
747 lua_pushboolean(L, value);
748 lua_settable(L, LUA_REGISTRYINDEX);
749 }
750
L_Get_Proper_Item_Accounting(lua_State * L)751 bool L_Get_Proper_Item_Accounting(lua_State* L)
752 {
753 bool value = false;
754 lua_pushlightuserdata(L, reinterpret_cast<void*>(L_PROPER_ITEM_ACCOUNTING_KEY));
755 lua_gettable(L, LUA_REGISTRYINDEX);
756 if (lua_isboolean(L, -1))
757 {
758 value = lua_toboolean(L, -1);
759 }
760
761 lua_pop(L, 1);
762 return value;
763 }
764
765 static char L_NONLOCAL_OVERLAYS_KEY[] = "nonlocal_overlays";
766
L_Set_Nonlocal_Overlays(lua_State * L,bool value)767 void L_Set_Nonlocal_Overlays(lua_State* L, bool value)
768 {
769 SetScriptHUDNonlocal(value);
770 }
771
L_Get_Nonlocal_Overlays(lua_State * L)772 bool L_Get_Nonlocal_Overlays(lua_State* L)
773 {
774 return IsScriptHUDNonlocal();
775 }
776
777 static int L_Enable_Player(lua_State*);
778 static int L_Disable_Player(lua_State*);
779 static int L_Kill_Script(lua_State*);
780 static int L_Hide_Interface(lua_State*);
781 static int L_Show_Interface(lua_State*);
782 static int L_Player_Control(lua_State*);
783
RegisterFunctions()784 void LuaState::RegisterFunctions()
785 {
786 lua_register(State(), "enable_player", L_Enable_Player);
787 lua_register(State(), "disable_player", L_Disable_Player);
788 lua_register(State(), "kill_script", L_Kill_Script);
789 lua_register(State(), "hide_interface", L_Hide_Interface);
790 lua_register(State(), "show_interface", L_Show_Interface);
791 lua_register(State(), "player_control", L_Player_Control);
792 // lua_register(state, "prompt", L_Prompt);
793
794 Lua_Map_register(State());
795 Lua_Monsters_register(State());
796 Lua_Objects_register(State());
797 Lua_Player_register(State());
798 Lua_Projectiles_register(State());
799 Lua_Saved_Objects_register(State());
800 }
801
802 static const char *compatibility_triggers = ""
803 "Triggers = {}\n"
804 "Triggers.init = function(restoring_game) if init then init(restoring_game) end end\n"
805 "Triggers.cleanup = function() if cleanup then cleanup() end end\n"
806 "Triggers.idle = function() if idle then idle() end end\n"
807 "Triggers.postidle = function() if postidle then postidle() end end\n"
808 "Triggers.start_refuel = function(class, player, side) if start_refuel then start_refuel(class.index, player.index) end end\n"
809 "Triggers.end_refuel = function(class, player, side) if end_refuel then end_refuel(class.index, player.index) end end\n"
810 "Triggers.tag_switch = function(tag, player) if tag_switch then tag_switch(tag.index, player.index) end end\n"
811 "Triggers.light_switch = function(light, player) if light_switch then light_switch(light.index, player.index) end end\n"
812 "Triggers.platform_switch = function(platform, player) if platform_switch then platform_switch(platform.index, player.index) end end\n"
813 "Triggers.terminal_enter = function(terminal, player) if terminal_enter then terminal_enter(terminal.index, player.index) end end\n"
814 "Triggers.terminal_exit = function(terminal, player) if terminal_exit then terminal_exit(terminal.index, player.index) end end\n"
815 "Triggers.pattern_buffer = function(side, player) if pattern_buffer then pattern_buffer(side.control_panel.permutation, player.index) end end\n"
816 "Triggers.got_item = function(type, player) if got_item then got_item(type.index, player.index) end end\n"
817 "Triggers.light_activated = function(light) if light_activated then light_activated(light.index) end end\n"
818 "Triggers.platform_activated = function(polygon) if platform_activated then platform_activated(polygon.index) end end\n"
819 "Triggers.player_revived = function(player) if player_revived then player_revived(player.index) end end\n"
820 "Triggers.player_killed = function(player, aggressor, action, projectile) if player_killed then if aggressor then aggressor_index = aggressor.index else aggressor_index = -1 end if projectile then projectile_index = projectile.index else projectile_index = -1 end player_killed(player.index, aggressor_index, action.index, projectile_index) end end\n"
821 "Triggers.monster_killed = function(monster, aggressor, projectile) if monster_killed then if aggressor then aggressor_index = aggressor.index else aggressor_index = -1 end if projectile then projectile_index = projectile.index else projectile_index = -1 end monster_killed(monster.index, aggressor_index, projectile_index) end end\n"
822 "Triggers.player_damaged = function(player, aggressor_player, aggressor_monster, type, amount, projectile) if player_damaged then if aggressor_player then aggressor_player_index = aggressor_player.index else aggressor_player_index = -1 end if aggressor_monster then aggressor_monster_index = aggressor_monster.index else aggressor_monster_index = -1 end if projectile then projectile_index = projectile.index else projectile_index = -1 end player_damaged(player.index, aggressor_player_index, aggressor_monster_index, type.index, amount, projectile_index) end end\n"
823 "Triggers.projectile_detonated = function(type, owner, polygon, x, y, z) if projectile_detonated then if owner then owner_index = owner.index else owner_index = -1 end projectile_detonated(type.index, owner_index, polygon.index, x, y, z) end end\n"
824 "Triggers.item_created = function(item) if item_created then item_created(item.index) end end\n"
825 ;
826
LoadCompatibility()827 void LuaState::LoadCompatibility()
828 {
829 luaL_loadbuffer(State(), compatibility_triggers, strlen(compatibility_triggers), "compatibility_triggers");
830 lua_pcall(State(), 0, 0, 0);
831
832 struct lang_def
833 {
834 const char *name;
835 int value;
836 };
837 struct lang_def constant_list[] = {
838 #include "language_definition.h"
839 };
840
841 int constant_list_size = sizeof(constant_list)/sizeof(lang_def);
842 for (int i=0; i<constant_list_size; i++)
843 {
844 lua_pushnumber(State(), constant_list[i].value);
845 lua_setglobal(State(), constant_list[i].name);
846 }
847 /* SB: Don't think this is a constant? */
848 lua_pushnumber(State(), MAXIMUM_MONSTERS_PER_MAP);
849 lua_setglobal(State(), "MAXIMUM_MONSTERS_PER_MAP");
850 lua_pushnumber(State(), MAXIMUM_PROJECTILES_PER_MAP);
851 lua_setglobal(State(), "MAXIMUM_PROJECTILES_PER_MAP");
852 lua_pushnumber(State(), MAXIMUM_OBJECTS_PER_MAP);
853 lua_setglobal(State(), "MAXIMUM_OBJECTS_PER_MAP");
854 }
855
Load(const char * buffer,size_t len,const char * desc)856 bool LuaState::Load(const char *buffer, size_t len, const char *desc)
857 {
858 int status = luaL_loadbufferx(State(), buffer, len, desc, "t");
859 if (status == LUA_ERRRUN)
860 logWarning("Lua loading failed: error running script.");
861 if (status == LUA_ERRFILE)
862 logWarning("Lua loading failed: error loading file.");
863 if (status == LUA_ERRSYNTAX) {
864 logWarning("Lua loading failed: syntax error.");
865 logWarning(lua_tostring(State(), -1));
866 }
867 if (status == LUA_ERRMEM)
868 logWarning("Lua loading failed: error allocating memory.");
869 if (status == LUA_ERRERR)
870 logWarning("Lua loading failed: unknown error.");
871
872 num_scripts_ += ((status == 0) ? 1 : 0);
873 return (status == 0);
874 }
875
876
Run()877 bool LuaState::Run()
878 {
879 if (!Loaded()) return false;
880
881 int result = 0;
882 // Reverse the functions we're calling
883 for (int i = 0; i < num_scripts_ - 1; ++i)
884 lua_insert(State(), -(num_scripts_ - i));
885
886 // Call 'em
887 for (int i = 0; i < num_scripts_; ++i)
888 {
889 int ret = lua_pcall(State(), 0, LUA_MULTRET, 0);
890 if (ret != 0)
891 {
892 L_Error(lua_tostring(State(), -1));
893 result = ret;
894 break;
895 }
896 }
897
898 if (result == 0) running_ = true;
899 return (result == 0);
900 }
901
ExecuteCommand(const std::string & line)902 void LuaState::ExecuteCommand(const std::string& line)
903 {
904
905 std::string buffer;
906 bool print_result = false;
907 if (line[0] == '=')
908 {
909 buffer = "return " + line.substr(1);
910 print_result = true;
911 }
912 else
913 {
914 buffer = line;
915 }
916
917
918 if (luaL_loadbuffer(State(), buffer.c_str(), buffer.size(), "console") != 0)
919 {
920 L_Error(lua_tostring(State(), -1));
921 }
922 else
923 {
924 running_ = true;
925 if (lua_pcall(State(), 0, (print_result) ? 1 : 0, 0) != 0)
926 L_Error(lua_tostring(State(), -1));
927 else if (print_result)
928 {
929 lua_getglobal(State(), "tostring");
930 lua_insert(State(), 1);
931 lua_pcall(State(), 1, 1, 0);
932 if (lua_tostring(State(), -1))
933 {
934 screen_printf("%s", lua_tostring(State(), -1));
935 }
936 }
937 }
938
939 lua_settop(State(), 0);
940 }
941
942 extern bool can_load_collection(short);
943
944 // pass by pointer because boost::bind can't do non-const past 2nd argument
MarkCollections(std::set<short> * collections)945 void LuaState::MarkCollections(std::set<short>* collections)
946 {
947 if (!running_)
948 return;
949
950 lua_getglobal(State(), "CollectionsUsed");
951 if (lua_istable(State(), -1))
952 {
953 int i = 1;
954 lua_pushnumber(State(), i++);
955 lua_gettable(State(), -2);
956 while (lua_isnumber(State(), -1))
957 {
958 short collection_index = static_cast<short>(lua_tonumber(State(), -1));
959 if (can_load_collection(collection_index))
960 {
961 mark_collection_for_loading(collection_index);
962 collections->insert(collection_index);
963 }
964 lua_pop(State(), 1);
965 lua_pushnumber(State(), i++);
966 lua_gettable(State(), -2);
967 }
968
969 lua_pop(State(), 2);
970 }
971 else if (lua_isnumber(State(), -1))
972 {
973 short collection_index = static_cast<short>(lua_tonumber(State(), -1));
974 if (can_load_collection(collection_index))
975 {
976 mark_collection_for_loading(collection_index);
977 collections->insert(collection_index);
978 }
979
980 lua_pop(State(), 1);
981 }
982 else
983 {
984 lua_pop(State(), 1);
985 }
986 }
987
RestoreAll(const std::string & s)988 int LuaState::RestoreAll(const std::string& s)
989 {
990 if (s.empty())
991 {
992 lua_pushboolean(State(), false);
993 return 1;
994 }
995
996 std::stringbuf sb(s);
997 if (lua_restore(State(), &sb))
998 {
999 lua_pushlightuserdata(State(), L_Persistent_Table_Key());
1000 lua_insert(State(), -2);
1001 lua_settable(State(), LUA_REGISTRYINDEX); // muahaha
1002 lua_pushboolean(State(), true);
1003 }
1004 else
1005 {
1006 lua_pop(State(), 2);
1007 lua_pushboolean(State(), false);
1008 }
1009
1010 return 1;
1011 }
1012
RestorePassed(const std::string & s)1013 int LuaState::RestorePassed(const std::string& s)
1014 {
1015 if (s.empty())
1016 {
1017 lua_pushboolean(State(), false);
1018 return 1;
1019 }
1020
1021 std::stringbuf sb(s);
1022 if (lua_restore(State(), &sb))
1023 {
1024 lua_pushlightuserdata(State(), L_Persistent_Table_Key());
1025 lua_gettable(State(), LUA_REGISTRYINDEX);
1026
1027 lua_getfield(State(), -2, "player");
1028 lua_setfield(State(), -2, "player");
1029
1030 lua_getfield(State(), -2, "Game");
1031 lua_setfield(State(), -2, "Game");
1032
1033 lua_pop(State(), 2);
1034
1035 lua_pushboolean(State(), true);
1036 }
1037 else
1038 {
1039 lua_settop(State(), 0);
1040 lua_pushboolean(State(), false);
1041 }
1042
1043 return 1;
1044 }
1045
SaveAll()1046 std::string LuaState::SaveAll()
1047 {
1048 lua_pushlightuserdata(State(), L_Persistent_Table_Key());
1049 lua_gettable(State(), LUA_REGISTRYINDEX);
1050
1051 std::stringbuf sb;
1052 if (lua_save(State(), &sb))
1053 {
1054 return sb.str();
1055 }
1056 else
1057 {
1058 return std::string();
1059 }
1060 }
1061
SavePassed()1062 std::string LuaState::SavePassed()
1063 {
1064 // copy "player" and "Game" custom fields to a new table
1065 lua_pushlightuserdata(State(), reinterpret_cast<void*>(L_Persistent_Table_Key()));
1066 lua_gettable(State(), LUA_REGISTRYINDEX);
1067
1068 lua_newtable(State());
1069 lua_getfield(State(), -2, "player");
1070 lua_setfield(State(), -2, "player");
1071
1072 lua_getfield(State(), -2, "Game");
1073 lua_setfield(State(), -2, "Game");
1074
1075 lua_remove(State(), -2);
1076
1077 std::stringbuf sb;
1078 if (lua_save(State(), &sb))
1079 {
1080 return sb.str();
1081 }
1082 else
1083 {
1084 return std::string();
1085 }
1086 }
1087
1088 typedef boost::ptr_map<int, LuaState> state_map;
1089 state_map states;
1090
1091 // globals
1092 std::vector<lua_camera> lua_cameras;
1093 std::unordered_map<std::string, std::string> lua_stash;
1094
1095 uint32 *action_flags;
1096
1097 // For better_random
1098 GM_Random lua_random_generator;
1099
FindLinearValue(double startValue,double endValue,double timeRange,double timeTaken)1100 double FindLinearValue(double startValue, double endValue, double timeRange, double timeTaken)
1101 {
1102 return (((endValue-startValue)/timeRange)*timeTaken)+startValue;
1103 }
1104
FindLinearValue(world_point3d startPoint,world_point3d endPoint,double timeRange,double timeTaken)1105 world_point3d FindLinearValue(world_point3d startPoint, world_point3d endPoint, double timeRange, double timeTaken)
1106 {
1107 world_point3d realPoint;
1108 realPoint.x = static_cast<int16>(((double)(endPoint.x-startPoint.x)/timeRange)*timeTaken)+startPoint.x;
1109 realPoint.y = static_cast<int16>(((double)(endPoint.y-startPoint.y)/timeRange)*timeTaken)+startPoint.y;
1110 realPoint.z = static_cast<int16>(((double)(endPoint.z-startPoint.z)/timeRange)*timeTaken)+startPoint.z;
1111 return realPoint;
1112 }
1113
1114 void
L_Error(const char * inMessage)1115 L_Error(const char* inMessage)
1116 {
1117 if (!mute_lua) screen_printf("%s", inMessage);
1118 logError(inMessage);
1119 }
1120
1121 /*
1122 static bool
1123 L_Should_Call(const char* inLuaFunctionName)
1124 {
1125 if (!lua_running)
1126 return false;
1127
1128 lua_pushstring(state, inLuaFunctionName);
1129 lua_gettable(state, LUA_GLOBALSINDEX);
1130
1131 if (!lua_isfunction(state, -1))
1132 {
1133 lua_pop(state, 1);
1134 return false;
1135 }
1136
1137 return true;
1138 }
1139
1140 static void
1141 L_Do_Call(const char* inLuaFunctionName, int inNumArgs = 0, int inNumResults = 0)
1142 {
1143 if (lua_pcall(state, inNumArgs, inNumResults, 0)==LUA_ERRRUN)
1144 L_Error(lua_tostring(state,-1));
1145 }
1146 */
1147
LuaRunning()1148 static bool LuaRunning()
1149 {
1150 for (state_map::iterator it = states.begin(); it != states.end(); ++it)
1151 {
1152 if (it->second->Running())
1153 {
1154 return true;
1155 }
1156 }
1157
1158 return false;
1159 }
1160
1161 // call f on each Lua state
1162 template<class UnaryFunction>
L_Dispatch(const UnaryFunction & f)1163 void L_Dispatch(const UnaryFunction& f)
1164 {
1165 for (state_map::iterator it = states.begin(); it != states.end(); ++it)
1166 {
1167 f(it->second);
1168 }
1169 }
1170
L_Call_Init(bool fRestoringSaved)1171 void L_Call_Init(bool fRestoringSaved)
1172 {
1173 if (LuaRunning())
1174 {
1175 // jkvw: Seeding our better random number
1176 // generator from the lousy one is clearly not
1177 // ideal, but it should be good enough for our
1178 // purposes.
1179 uint16 current_seed = get_random_seed();
1180 lua_random_generator.z = (static_cast<uint32>(global_random ()) << 16) + static_cast<uint32>(global_random ());
1181 lua_random_generator.w = (static_cast<uint32>(global_random ()) << 16) + static_cast<uint32>(global_random ());
1182 lua_random_generator.jsr = (static_cast<uint32>(global_random ()) << 16) + static_cast<uint32>(global_random ());
1183 lua_random_generator.jcong = (static_cast<uint32>(global_random ()) << 16) + static_cast<uint32>(global_random ());
1184 if (!film_profile.lua_increments_rng)
1185 set_random_seed(current_seed);
1186
1187 }
1188
1189 L_Dispatch(boost::bind(&LuaState::Init, _1, fRestoringSaved));
1190 }
1191
L_Call_Cleanup()1192 void L_Call_Cleanup ()
1193 {
1194 L_Dispatch(boost::bind(&LuaState::Cleanup, _1));
1195 }
1196
1197 void UpdateLuaCameras();
1198
L_Call_Idle()1199 void L_Call_Idle()
1200 {
1201 UpdateLuaCameras();
1202 L_Dispatch(boost::bind(&LuaState::Idle, _1));
1203 }
1204
L_Call_PostIdle()1205 void L_Call_PostIdle()
1206 {
1207 L_Dispatch(boost::bind(&LuaState::PostIdle, _1));
1208 }
1209
L_Call_Start_Refuel(short type,short player_index,short panel_side_index)1210 void L_Call_Start_Refuel (short type, short player_index, short panel_side_index)
1211 {
1212 L_Dispatch(boost::bind(&LuaState::StartRefuel, _1, type, player_index, panel_side_index));
1213 }
1214
L_Call_End_Refuel(short type,short player_index,short panel_side_index)1215 void L_Call_End_Refuel (short type, short player_index, short panel_side_index)
1216 {
1217 L_Dispatch(boost::bind(&LuaState::EndRefuel, _1, type, player_index, panel_side_index));
1218 }
1219
L_Call_Tag_Switch(short tag,short player_index,short side_index)1220 void L_Call_Tag_Switch(short tag, short player_index, short side_index)
1221 {
1222 L_Dispatch(boost::bind(&LuaState::TagSwitch, _1, tag, player_index, side_index));
1223 }
1224
L_Call_Light_Switch(short light,short player_index,short side_index)1225 void L_Call_Light_Switch(short light, short player_index, short side_index)
1226 {
1227 L_Dispatch(boost::bind(&LuaState::LightSwitch, _1, light, player_index, side_index));
1228 }
1229
L_Call_Platform_Switch(short platform,short player_index,short side_index)1230 void L_Call_Platform_Switch(short platform, short player_index, short side_index)
1231 {
1232 L_Dispatch(boost::bind(&LuaState::PlatformSwitch, _1, platform, player_index, side_index));
1233 }
1234
L_Call_Projectile_Switch(short side_index,short projectile_index)1235 void L_Call_Projectile_Switch(short side_index, short projectile_index)
1236 {
1237 L_Dispatch(boost::bind(&LuaState::ProjectileSwitch, _1, side_index, projectile_index));
1238 }
1239
L_Call_Terminal_Enter(short terminal_id,short player_index)1240 void L_Call_Terminal_Enter(short terminal_id, short player_index)
1241 {
1242 L_Dispatch(boost::bind(&LuaState::TerminalEnter, _1, terminal_id, player_index));
1243 }
1244
L_Call_Terminal_Exit(short terminal_id,short player_index)1245 void L_Call_Terminal_Exit(short terminal_id, short player_index)
1246 {
1247 L_Dispatch(boost::bind(&LuaState::TerminalExit, _1, terminal_id, player_index));
1248 }
1249
L_Call_Pattern_Buffer(short side_index,short player_index)1250 void L_Call_Pattern_Buffer(short side_index, short player_index)
1251 {
1252 L_Dispatch(boost::bind(&LuaState::PatternBuffer, _1, side_index, player_index));
1253 }
1254
L_Call_Got_Item(short type,short player_index)1255 void L_Call_Got_Item(short type, short player_index)
1256 {
1257 L_Dispatch(boost::bind(&LuaState::GotItem, _1, type, player_index));
1258 }
1259
L_Call_Light_Activated(short index)1260 void L_Call_Light_Activated(short index)
1261 {
1262 L_Dispatch(boost::bind(&LuaState::LightActivated, _1, index));
1263 }
1264
L_Call_Platform_Activated(short index)1265 void L_Call_Platform_Activated(short index)
1266 {
1267 L_Dispatch(boost::bind(&LuaState::PlatformActivated, _1, index));
1268 }
1269
L_Call_Player_Revived(short player_index)1270 void L_Call_Player_Revived (short player_index)
1271 {
1272 L_Dispatch(boost::bind(&LuaState::PlayerRevived, _1, player_index));
1273 }
1274
L_Call_Player_Killed(short player_index,short aggressor_player_index,short action,short projectile_index)1275 void L_Call_Player_Killed (short player_index, short aggressor_player_index, short action, short projectile_index)
1276 {
1277 L_Dispatch(boost::bind(&LuaState::PlayerKilled, _1, player_index, aggressor_player_index, action, projectile_index));
1278 }
1279
L_Call_Monster_Killed(short monster_index,short aggressor_player_index,short projectile_index)1280 void L_Call_Monster_Killed (short monster_index, short aggressor_player_index, short projectile_index)
1281 {
1282 L_Dispatch(boost::bind(&LuaState::MonsterKilled, _1, monster_index, aggressor_player_index, projectile_index));
1283 }
1284
L_Call_Monster_Damaged(short monster_index,short aggressor_monster_index,int16 damage_type,short damage_amount,short projectile_index)1285 void L_Call_Monster_Damaged(short monster_index, short aggressor_monster_index, int16 damage_type, short damage_amount, short projectile_index)
1286 {
1287 L_Dispatch(boost::bind(&LuaState::MonsterDamaged, _1, monster_index, aggressor_monster_index, damage_type, damage_amount, projectile_index));
1288 }
1289
L_Call_Player_Damaged(short player_index,short aggressor_player_index,short aggressor_monster_index,int16 damage_type,short damage_amount,short projectile_index)1290 void L_Call_Player_Damaged (short player_index, short aggressor_player_index, short aggressor_monster_index, int16 damage_type, short damage_amount, short projectile_index)
1291 {
1292 L_Dispatch(boost::bind(&LuaState::PlayerDamaged, _1, player_index, aggressor_player_index, aggressor_monster_index, damage_type, damage_amount, projectile_index));
1293 }
1294
L_Call_Projectile_Detonated(short type,short owner_index,short polygon,world_point3d location)1295 void L_Call_Projectile_Detonated(short type, short owner_index, short polygon, world_point3d location)
1296 {
1297 L_Dispatch(boost::bind(&LuaState::ProjectileDetonated, _1, type, owner_index, polygon, location));
1298 }
1299
L_Call_Projectile_Created(short projectile_index)1300 void L_Call_Projectile_Created (short projectile_index)
1301 {
1302 L_Dispatch(boost::bind(&LuaState::ProjectileCreated, _1, projectile_index));
1303 }
1304
L_Call_Item_Created(short item_index)1305 void L_Call_Item_Created (short item_index)
1306 {
1307 L_Dispatch(boost::bind(&LuaState::ItemCreated, _1, item_index));
1308 }
1309
L_Invalidate_Effect(short effect_index)1310 void L_Invalidate_Effect(short effect_index)
1311 {
1312 L_Dispatch(boost::bind(&LuaState::InvalidateEffect, _1, effect_index));
1313 }
1314
L_Invalidate_Monster(short monster_index)1315 void L_Invalidate_Monster(short monster_index)
1316 {
1317 L_Dispatch(boost::bind(&LuaState::InvalidateMonster, _1, monster_index));
1318 }
1319
L_Invalidate_Projectile(short projectile_index)1320 void L_Invalidate_Projectile(short projectile_index)
1321 {
1322 L_Dispatch(boost::bind(&LuaState::InvalidateProjectile, _1, projectile_index));
1323 }
1324
L_Invalidate_Object(short object_index)1325 void L_Invalidate_Object(short object_index)
1326 {
1327 L_Dispatch(boost::bind(&LuaState::InvalidateObject, _1, object_index));
1328 }
1329
L_Enable_Player(lua_State * L)1330 int L_Enable_Player(lua_State *L)
1331 {
1332 if (!lua_isnumber(L,1))
1333 {
1334 lua_pushstring(L, "enable_player: incorrect argument type");
1335 lua_error(L);
1336 }
1337 int player_index = static_cast<int>(lua_tonumber(L,1));
1338 if (player_index < 0 || player_index >= dynamic_world->player_count)
1339 {
1340 lua_pushstring(L, "enable_player: invalid player index");
1341 lua_error(L);
1342 }
1343 player_data *player = get_player_data(player_index);
1344
1345 if (PLAYER_IS_DEAD(player) || PLAYER_IS_TOTALLY_DEAD(player))
1346 return 0;
1347 SET_PLAYER_ZOMBIE_STATUS(player, false);
1348 return 0;
1349 }
1350
L_Disable_Player(lua_State * L)1351 int L_Disable_Player(lua_State *L)
1352 {
1353 if (!lua_isnumber(L,1))
1354 {
1355 lua_pushstring(L, "disable_player: incorrect argument type");
1356 lua_error(L);
1357 }
1358 int player_index = static_cast<int>(lua_tonumber(L,1));
1359 if (player_index < 0 || player_index >= dynamic_world->player_count)
1360 {
1361 lua_pushstring(L, "disable_player: invalid player index");
1362 lua_error(L);
1363 }
1364 player_data *player = get_player_data(player_index);
1365
1366 if (PLAYER_IS_DEAD(player) || PLAYER_IS_TOTALLY_DEAD(player))
1367 return 0;
1368 SET_PLAYER_ZOMBIE_STATUS(player, true);
1369 return 0;
1370 }
1371
L_Kill_Script(lua_State * L)1372 int L_Kill_Script(lua_State *L)
1373 {
1374 for (state_map::iterator it = states.begin(); it != states.end(); ++it)
1375 {
1376 if (it->second->Matches(L)) {
1377 it->second->Stop();
1378 }
1379 }
1380
1381 return 0;
1382 }
1383
L_Hide_Interface(lua_State * L)1384 int L_Hide_Interface(lua_State *L)
1385 {
1386 if (!lua_isnumber(L,1))
1387 {
1388 lua_pushstring(L, "hide_interface: incorrect argument type");
1389 lua_error(L);
1390 }
1391 int player_index = static_cast<int>(lua_tonumber(L,1));
1392
1393 if (local_player_index != player_index)
1394 return 0;
1395
1396 screen_mode_data *the_mode;
1397 the_mode = get_screen_mode();
1398 if(the_mode->hud)
1399 {
1400 the_mode->hud = false;
1401 change_screen_mode(the_mode,true);
1402 }
1403
1404 return 0;
1405 }
1406
L_Restore_Saved(lua_State * L)1407 int L_Restore_Saved(lua_State *L)
1408 {
1409 for (state_map::iterator it = states.begin(); it != states.end(); ++it)
1410 {
1411 if (it->second->Matches(L))
1412 {
1413 return it->second->RestoreAll(SavedLuaState[it->first]);
1414 }
1415 }
1416
1417 return 0;
1418 }
1419
L_Restore_Passed(lua_State * L)1420 int L_Restore_Passed(lua_State *L)
1421 {
1422 for (state_map::iterator it = states.begin(); it != states.end(); ++it)
1423 {
1424 if (it->second->Matches(L))
1425 {
1426 return it->second->RestorePassed(PassedLuaState[it->first]);
1427 }
1428 }
1429
1430 return 0;
1431 }
1432
L_Show_Interface(lua_State * L)1433 int L_Show_Interface(lua_State *L)
1434 {
1435 if (!lua_isnumber(L,1))
1436 {
1437 lua_pushstring(L, "show_interface: incorrect argument type");
1438 lua_error(L);
1439 }
1440 int player_index = static_cast<int>(lua_tonumber(L,1));
1441
1442 if (local_player_index != player_index)
1443 return 0;
1444
1445 screen_mode_data *the_mode;
1446 the_mode = get_screen_mode();
1447 if (!the_mode->hud)
1448 {
1449 the_mode->hud = true;
1450 change_screen_mode(the_mode,true);
1451 draw_panels();
1452 }
1453
1454 return 0;
1455 }
1456
1457 #if TIENNOU_PLAYER_CONTROL
1458 enum
1459 {
1460 move_player = 1,
1461 turn_player,
1462 look_at
1463 };
1464 #endif
1465
L_Player_Control(lua_State * L)1466 int L_Player_Control(lua_State *L)
1467 {
1468 if (!lua_isnumber(L,1) || !lua_isnumber(L,2) || !lua_isnumber(L,3))
1469 {
1470 lua_pushstring(L, "player_control: incorrect argument type");
1471 lua_error(L);
1472 }
1473 int player_index = static_cast<int>(lua_tonumber(L,1));
1474 if (player_index < 0 || player_index >= dynamic_world->player_count)
1475 {
1476 lua_pushstring(L, "player_control: invalid player index");
1477 lua_error(L);
1478 }
1479 int move_type = static_cast<int>(lua_tonumber(L,2));
1480 int value = static_cast<int>(lua_tonumber(L,3));
1481 #if TIENNOU_PLAYER_CONTROL
1482 player_data *player = get_player_data(player_index);
1483 #endif
1484
1485 if (sLuaActionQueues == NULL)
1486 {
1487 sLuaActionQueues = new ActionQueues(MAXIMUM_NUMBER_OF_PLAYERS, ACTION_QUEUE_BUFFER_DIAMETER, true);
1488 }
1489
1490 // Put the enqueuing of the action flags in one place in the code,
1491 // so it will be easier to change if necessary
1492 // LP: changed to reallocate-on-expand code;
1493 // "static" values are remembered from one call to the next
1494 static uint32 *action_flags = NULL;
1495 static int prev_value = 0;
1496 if (value > prev_value)
1497 {
1498 if (action_flags) delete []action_flags;
1499 action_flags = new uint32[value];
1500 }
1501 assert(action_flags);
1502 prev_value = value;
1503
1504 bool DoAction = false;
1505 #if TIENNOU_PLAYER_CONTROL
1506 struct physics_variables variables;
1507 struct physics_variables *variablesptr;
1508 struct physics_constants *constants= get_physics_constants_for_model(static_world->physics_model, action_flags);
1509 variables = player->variables;
1510 *variablesptr = variables;
1511 #endif
1512
1513 switch(move_type)
1514 {
1515 #if TIENNOU_PLAYER_CONTROL
1516 case move_player:
1517 if (!lua_isnumber(L,3) || !lua_isnumber(L,4) || !lua_isnumber(L,5))
1518 {
1519 lua_pushstring(L, "player_control: incorrect argument type for move_player");
1520 lua_error(L);
1521 }
1522
1523 world_point3d goal_point;
1524 world_point3d current_point;
1525 current_point = player->location;
1526 goal_point.x = static_cast<int>(lua_tonumber(L,3)*WORLD_ONE);
1527 goal_point.y = static_cast<int>(lua_tonumber(L,4)*WORLD_ONE);
1528 goal_point.z = static_cast<int>(lua_tonumber(L,5)*WORLD_ONE);
1529 angle heading;
1530 heading = arctangent((current_point.y - goal_point.y), (current_point.x - goal_point.x));
1531 angle current_heading;
1532 current_heading = player->facing;
1533 _fixed delta;
1534
1535 if (current_heading < heading)
1536 {
1537 screen_printf("Player heading is on the right of the goal_point");
1538 // turn_left
1539 while (current_heading <= heading)
1540 {
1541 action_flags[0] = _turning_left;
1542 //action_flag_count++;
1543 //GetPfhortranActionQueues()->enqueueActionFlags(player_index, action_flags, 1);
1544 physics_update(constants, variablesptr, player, action_flags);
1545 instantiate_physics_variables(constants, variablesptr, player_index, false);
1546 }
1547 }
1548 else if (current_heading > heading)
1549 {
1550 screen_printf("Player heading is on the left of the goal_point");
1551 // turn_right
1552 while (player->facing >= heading)
1553 {
1554 action_flags[0] = _turning_right;
1555 //action_flag_count++;
1556 //GetPfhortranActionQueues()->enqueueActionFlags(player_index, action_flags, 1);
1557 physics_update(constants, variablesptr, player, action_flags);
1558 instantiate_physics_variables(constants, variablesptr, player_index, false);
1559 }
1560 }
1561
1562 if (current_point.x < goal_point.x)
1563 {
1564 screen_printf("goal_point is in front of player");
1565
1566 /*
1567 while (current_point.x > goal_point.x)
1568 {
1569 action_flags[0] = _moving_forward;
1570 //action_flag_count++;
1571 GetPfhortranActionQueues()->enqueueActionFlags(player_index, action_flags, 1);
1572 }
1573 */
1574 }
1575 else if (current_point.x > goal_point.x)
1576 {
1577 screen_printf("goal_point is behind player");
1578 /*
1579 while (current_point.x < goal_point.x)
1580 {
1581 action_flags[0] = _moving_backward;
1582 //action_flag_count++;
1583 GetPfhortranActionQueues()->enqueueActionFlags(player_index, action_flags, 1);
1584 }
1585 */
1586 }
1587
1588 break;
1589
1590 case turn_player:
1591 if (!lua_isnumber(L,3) || !lua_isnumber(L,4))
1592 {
1593 lua_pushstring(L, "player_control: incorrect argument type for turn_player");
1594 lua_error(L);
1595 }
1596
1597 angle new_facing;
1598 angle new_elevation;
1599 new_facing = static_cast<int16>(lua_tonumber(L,3));
1600 new_elevation = static_cast<int16>(lua_tonumber(L,4));
1601
1602 if (player->facing < new_facing)
1603 {
1604 screen_printf("new_facing is on right of the player heading");
1605 }
1606 else if (player->facing > new_facing)
1607 {
1608 screen_printf("new_facing is on left of the player heading");
1609 }
1610
1611 if (player->elevation < new_elevation)
1612 {
1613 screen_printf("new_elevation is above player elevation");
1614 }
1615 else if (player->elevation > new_elevation)
1616 {
1617 screen_printf("new_elevation is under player elevation");
1618 }
1619
1620 break;
1621
1622 case look_at:
1623 if (!lua_isnumber(L,3) || !lua_isnumber(L,4) || !lua_isnumber(L,5))
1624 {
1625 lua_pushstring(L, "player_control: incorrect argument type for look_at");
1626 lua_error(L);
1627 }
1628
1629 world_point3d look;
1630 look.x = static_cast<int16>(lua_tonumber(L, 3));
1631 look.y = static_cast<int16>(lua_tonumber(L, 4));
1632 look.z = static_cast<int16>(lua_tonumber(L, 5));
1633
1634 player->facing = arctangent(ABS(look.x-player->location.x), ABS(look.y-player->location.y));
1635 player->elevation = arctangent(ABS(look.x-player->location.x),ABS(look.z-player->location.z));
1636
1637 break;
1638 #endif
1639 #if !TIENNOU_PLAYER_CONTROL
1640 case 0:
1641 action_flags[0] = _moving_forward;
1642 DoAction = true;
1643 break;
1644
1645 case 1:
1646 action_flags[0] = _moving_backward;
1647 DoAction = true;
1648 break;
1649
1650 case 2:
1651 action_flags[0] = _sidestepping_left;
1652 DoAction = true;
1653 break;
1654
1655 case 3:
1656 action_flags[0] = _sidestepping_right;
1657 DoAction = true;
1658 break;
1659
1660 case 4:
1661 action_flags[0] = _turning_left;
1662 DoAction = true;
1663 break;
1664
1665 case 5:
1666 action_flags[0] = _turning_right;
1667 DoAction = true;
1668 break;
1669
1670 case 6:
1671 action_flags[0] = _looking_up;
1672 DoAction = true;
1673 break;
1674
1675 case 7:
1676 action_flags[0] = _looking_down;
1677 DoAction = true;
1678 break;
1679
1680 case 8:
1681 action_flags[0] = _action_trigger_state;
1682 DoAction = true;
1683 break;
1684
1685 case 9:
1686 action_flags[0] = _left_trigger_state;
1687 DoAction = true;
1688 break;
1689
1690 case 10:
1691 action_flags[0] = _right_trigger_state;
1692 DoAction = true;
1693 break;
1694
1695 case 13: // reset action queue
1696 GetLuaActionQueues()->reset();
1697 break;
1698 #endif
1699 default:
1700 break;
1701 }
1702
1703 if (DoAction)
1704 {
1705 for (int i=1; i<value; i++)
1706 action_flags[i] = action_flags[0];
1707
1708 GetLuaActionQueues()->enqueueActionFlags(player_index, action_flags, value);
1709 }
1710 return 0;
1711 }
1712 /*
1713 static void L_Prompt_Callback(const std::string& str) {
1714 if(L_Should_Call("prompt_callback"))
1715 {
1716 lua_pushnumber(state, local_player_index);
1717 lua_pushstring(state, str.c_str());
1718 L_Do_Call("prompt_callback", 2);
1719 }
1720 }
1721
1722 static int L_Prompt(lua_State *L)
1723 {
1724 if(dynamic_world->player_count > 1) {
1725 lua_pushstring(L, "prompt: Not implemented for network play");
1726 lua_error(L);
1727 }
1728 if(!lua_isnumber(L,1) || !lua_isstring(L,2))
1729 {
1730 lua_pushstring(L, "prompt: incorrect argument type");
1731 lua_error(L);
1732 }
1733 int player_index = static_cast<int>(lua_tonumber(L,1));
1734 if (player_index < 0 || player_index >= dynamic_world->player_count)
1735 {
1736 lua_pushstring(L, "prompt: invalid player index");
1737 lua_error(L);
1738 }
1739 if((Console::instance())->input_active()) {
1740 lua_pushstring(L, "prompt: prompt already active");
1741 lua_error(L);
1742 }
1743 (Console::instance())->activate_input(L_Prompt_Callback, lua_tostring(L, 2));
1744 return 0;
1745 }
1746 */
1747
LuaStateFactory(ScriptType script_type)1748 static LuaState* LuaStateFactory(ScriptType script_type)
1749 {
1750 switch (script_type) {
1751 case _embedded_lua_script:
1752 return new EmbeddedLuaState;
1753 case _lua_netscript:
1754 return new NetscriptState;
1755 case _solo_lua_script:
1756 return new SoloScriptState;
1757 case _stats_lua_script:
1758 return new StatsLuaState;
1759 }
1760 return NULL;
1761 }
1762
LoadLuaScript(const char * buffer,size_t len,ScriptType script_type)1763 bool LoadLuaScript(const char *buffer, size_t len, ScriptType script_type)
1764 {
1765 assert(script_type >= _embedded_lua_script && script_type <= _stats_lua_script);
1766 if (states.find(script_type) == states.end())
1767 {
1768 int type = script_type;
1769 states.insert(type, LuaStateFactory(script_type));
1770 states[script_type].Initialize();
1771 }
1772 const char *desc = "level_script";
1773 switch (script_type) {
1774 case _embedded_lua_script:
1775 desc = "Map Lua";
1776 break;
1777 case _lua_netscript:
1778 desc = "Netscript";
1779 break;
1780 case _solo_lua_script:
1781 desc = "Solo Lua";
1782 break;
1783 case _stats_lua_script:
1784 desc = "Stats Lua";
1785 break;
1786 }
1787 return states[script_type].Load(buffer, len, desc);
1788 }
1789
1790 #ifdef HAVE_OPENGL
1791 static OGL_FogData PreLuaFogState[OGL_NUMBER_OF_FOG_TYPES];
1792 #endif
1793 static bool MotionSensorWasActive;
1794
PreservePreLuaSettings()1795 static void PreservePreLuaSettings()
1796 {
1797 #ifdef HAVE_OPENGL
1798 for (int i = 0; i < OGL_NUMBER_OF_FOG_TYPES; i++)
1799 {
1800 PreLuaFogState[i] = *OGL_GetFogData(i);
1801 }
1802 #endif
1803 MotionSensorWasActive = MotionSensorActive;
1804 }
1805
InitializeLuaVariables()1806 static void InitializeLuaVariables()
1807 {
1808 for (int i = 0; i < MAXIMUM_NUMBER_OF_NETWORK_PLAYERS; ++i)
1809 {
1810 use_lua_compass[i] = false;
1811 can_wield_weapons[i] = true;
1812 }
1813
1814 game_end_condition = _game_normal_end_condition;
1815 game_scoring_mode = _game_of_most_points;
1816 }
1817
RestorePreLuaSettings()1818 static void RestorePreLuaSettings()
1819 {
1820 #ifdef HAVE_OPENGL
1821 for (int i = 0; i < OGL_NUMBER_OF_FOG_TYPES; i++)
1822 {
1823 *OGL_GetFogData(i) = PreLuaFogState[i];
1824 }
1825 #endif
1826 MotionSensorActive = MotionSensorWasActive;
1827 }
1828
RunLuaScript()1829 bool RunLuaScript()
1830 {
1831 InitializeLuaVariables();
1832 PreservePreLuaSettings();
1833
1834 bool running = false;
1835 for (state_map::iterator it = states.begin(); it != states.end(); ++it)
1836 {
1837 running |= it->second->Run();
1838 }
1839
1840 return running;
1841 }
1842
ExecuteLuaString(const std::string & line)1843 void ExecuteLuaString(const std::string& line)
1844 {
1845 if (states.find(_solo_lua_script) == states.end())
1846 {
1847 int type = _solo_lua_script;
1848 states.insert(type, LuaStateFactory(_solo_lua_script));
1849 states[_solo_lua_script].Initialize();
1850 }
1851
1852 states[_solo_lua_script].ExecuteCommand(line);
1853 }
1854
LoadSoloLua()1855 void LoadSoloLua()
1856 {
1857 std::string file;
1858 std::string directory;
1859
1860 if (environment_preferences->use_solo_lua)
1861 {
1862 file = environment_preferences->solo_lua_file;
1863 }
1864 else
1865 {
1866 const Plugin* solo_lua_plugin = Plugins::instance()->find_solo_lua();
1867 if (solo_lua_plugin)
1868 {
1869 file = solo_lua_plugin->solo_lua;
1870 directory = solo_lua_plugin->directory.GetPath();
1871 }
1872 }
1873
1874 if (file.size())
1875 {
1876 FileSpecifier fs (file.c_str());
1877 if (directory.size())
1878 {
1879 fs.SetNameWithPath(file.c_str(), directory);
1880 }
1881
1882 OpenedFile script_file;
1883 if (fs.Open(script_file))
1884 {
1885 int32 script_length;
1886 script_file.GetLength(script_length);
1887
1888 std::vector<char> script_buffer(script_length);
1889 if (script_file.Read(script_length, &script_buffer[0]))
1890 {
1891 LoadLuaScript(&script_buffer[0], script_length, _solo_lua_script);
1892 if (directory.size())
1893 {
1894 states[_solo_lua_script].SetSearchPath(directory);
1895 }
1896 }
1897 }
1898 }
1899 }
1900
LoadStatsLua()1901 void LoadStatsLua()
1902 {
1903 std::string file;
1904 std::string directory;
1905
1906 const Plugin* stats_lua_plugin = Plugins::instance()->find_stats_lua();
1907 if (stats_lua_plugin)
1908 {
1909 file = stats_lua_plugin->stats_lua;
1910 directory = stats_lua_plugin->directory.GetPath();
1911 }
1912
1913 if (file.size())
1914 {
1915 FileSpecifier fs(file.c_str());
1916 if (directory.size())
1917 {
1918 fs.SetNameWithPath(file.c_str(), directory);
1919 }
1920
1921 OpenedFile script_file;
1922 if (fs.Open(script_file))
1923 {
1924 int32 script_length;
1925 script_file.GetLength(script_length);
1926
1927 std::vector<char> script_buffer(script_length);
1928 if (script_file.Read(script_length, &script_buffer[0]))
1929 {
1930 LoadLuaScript(&script_buffer[0], script_length, _stats_lua_script);
1931 if (directory.size())
1932 {
1933 states[_stats_lua_script].SetSearchPath(directory);
1934 }
1935 }
1936
1937 }
1938 }
1939 }
1940
CollectLuaStats(std::map<std::string,std::string> & options,std::map<std::string,std::string> & parameters)1941 bool CollectLuaStats(std::map<std::string, std::string>& options, std::map<std::string, std::string>& parameters)
1942 {
1943 if (states.find(_stats_lua_script) == states.end())
1944 {
1945 return false;
1946 }
1947
1948 LuaState& state = states[_stats_lua_script];
1949 lua_State* L = state.State();
1950
1951 if (!state.Running())
1952 return false;
1953
1954 options.clear();
1955 parameters.clear();
1956
1957 lua_getglobal(L, "Statistics");
1958 if (!lua_istable(L, -1))
1959 {
1960 lua_pop(L, 1);
1961 return false;
1962 }
1963
1964 // grab all the keys/values
1965 lua_pushnil(L);
1966 while (lua_next(L, -2) != 0)
1967 {
1968 if (lua_type(L, -1) == LUA_TSTRING)
1969 {
1970 options[lua_tostring(L, -2)] = lua_tostring(L, -1);
1971 }
1972 lua_pop(L, 1);
1973 }
1974
1975 // grab the parameters
1976 lua_pushstring(L, "parameters");
1977 lua_gettable(L, -2);
1978 if (lua_istable(L, -1))
1979 {
1980 lua_pushnil(L);
1981 while (lua_next(L, -2) != 0)
1982 {
1983 if (lua_type(L, -2) == LUA_TSTRING)
1984 {
1985 if (lua_tostring(L, -1))
1986 {
1987 parameters[lua_tostring(L, -2)] = lua_tostring(L, -1);
1988 }
1989 // lua_tostring only works with numbers and strings
1990 else if (lua_isboolean(L, -1))
1991 {
1992 parameters[lua_tostring(L, -2)] = (lua_toboolean(L, -1) ? "true" : "false");
1993 }
1994 }
1995 lua_pop(L, 1);
1996 }
1997 }
1998
1999 // pop the Parameters table, or the nil
2000 lua_pop(L, 1);
2001
2002 // pop the Statistics table
2003 lua_pop(L, 1);
2004
2005 return true;
2006 }
2007
LoadReplayNetLua()2008 void LoadReplayNetLua()
2009 {
2010 std::string file;
2011 std::string directory;
2012
2013 if (environment_preferences->use_replay_net_lua)
2014 {
2015 file = network_preferences->netscript_file;
2016 }
2017
2018 if (file.size())
2019 {
2020 FileSpecifier fs (file.c_str());
2021 if (directory.size())
2022 {
2023 fs.SetNameWithPath(file.c_str(), directory);
2024 }
2025
2026 OpenedFile script_file;
2027 if (fs.Open(script_file))
2028 {
2029 int32 script_length;
2030 script_file.GetLength(script_length);
2031
2032 std::vector<char> script_buffer(script_length);
2033 if (script_file.Read(script_length, &script_buffer[0]))
2034 {
2035 LoadLuaScript(&script_buffer[0], script_length, _lua_netscript);
2036 if (directory.size())
2037 {
2038 states[_lua_netscript].SetSearchPath(directory);
2039 }
2040 }
2041 }
2042 }
2043 }
2044
CloseLuaScript()2045 void CloseLuaScript()
2046 {
2047 // save variables for going into next level
2048 PassedLuaState.clear();
2049 for (state_map::iterator it = states.begin(); it != states.end(); ++it)
2050 {
2051 PassedLuaState[it->first] = it->second->SavePassed();
2052 }
2053 states.clear();
2054
2055 SavedLuaState.clear();
2056
2057 RestorePreLuaSettings();
2058
2059 lua_cameras.resize(0);
2060 lua_stash.clear();
2061
2062 LuaTexturePaletteClear();
2063
2064 game_end_condition = _game_normal_end_condition;
2065
2066 }
2067
ResetPassedLua()2068 void ResetPassedLua()
2069 {
2070 PassedLuaState.clear();
2071 }
2072
ToggleLuaMute()2073 void ToggleLuaMute()
2074 {
2075 mute_lua = !mute_lua;
2076 if (mute_lua)
2077 {
2078 screen_printf("adding Lua messages to the ignore list");
2079 }
2080 else
2081 {
2082 screen_printf("removing Lua messages from the ignore list");
2083 }
2084 }
2085
ResetLuaMute()2086 void ResetLuaMute()
2087 {
2088 mute_lua = false;
2089 }
2090
MarkLuaCollections(bool loading)2091 void MarkLuaCollections(bool loading)
2092 {
2093 static std::set<short> collections;
2094 if (loading)
2095 {
2096 collections.clear();
2097
2098 L_Dispatch(boost::bind(&LuaState::MarkCollections, _1, &collections));
2099 }
2100 else
2101 {
2102 for (std::set<short>::iterator it = collections.begin(); it != collections.end(); it++)
2103 {
2104 mark_collection_for_unloading(*it);
2105 }
2106 }
2107 }
2108
UpdateLuaCameras()2109 void UpdateLuaCameras()
2110 {
2111 if (!LuaRunning())
2112 return;
2113
2114 for (std::vector<lua_camera>::iterator it = lua_cameras.begin(); it != lua_cameras.end(); ++it)
2115 {
2116 if (it->player_active != local_player_index)
2117 {
2118 continue;
2119 }
2120
2121 short point_index = it->path.current_point_index;
2122 short angle_index = it->path.current_angle_index;
2123
2124 it->time_elapsed++;
2125
2126 if (point_index >= 0 && it->time_elapsed - it->path.last_point_time >= it->path.path_points[point_index].delta_time)
2127 {
2128 it->path.current_point_index++;
2129 it->path.last_point_time = it->time_elapsed;
2130 if (it->path.current_point_index >= static_cast<short>(it->path.path_points.size()))
2131 {
2132 it->path.current_point_index = -1;
2133 }
2134 }
2135
2136 if (angle_index >= 0 && it->time_elapsed - it->path.last_angle_time >= it->path.path_angles[angle_index].delta_time)
2137 {
2138 it->path.current_angle_index++;
2139 it->path.last_angle_time = it->time_elapsed;
2140 if (it->path.current_angle_index >= static_cast<short>(it->path.path_angles.size()))
2141 {
2142 it->path.current_angle_index = -1;
2143 }
2144 }
2145 }
2146 }
2147
UseLuaCameras()2148 bool UseLuaCameras()
2149 {
2150 if (!LuaRunning())
2151 return false;
2152
2153 bool using_lua_cameras = false;
2154 for (std::vector<lua_camera>::iterator it = lua_cameras.begin(); it != lua_cameras.end(); ++it)
2155 {
2156 if (it->player_active != local_player_index)
2157 {
2158 continue;
2159 }
2160
2161 world_view->show_weapons_in_hand = false;
2162 using_lua_cameras = true;
2163
2164 short point_index = it->path.current_point_index;
2165 short angle_index = it->path.current_angle_index;
2166
2167 if (angle_index >= 0 && angle_index < static_cast<short>(it->path.path_angles.size()))
2168 {
2169 if (static_cast<size_t>(angle_index) == it->path.path_angles.size() - 1)
2170 {
2171 world_view->yaw = normalize_angle(it->path.path_angles[angle_index].yaw);
2172 world_view->pitch = normalize_angle(it->path.path_angles[angle_index].pitch);
2173 }
2174 else
2175 {
2176 world_view->yaw = normalize_angle(static_cast<short>(FindLinearValue(it->path.path_angles[angle_index].yaw, it->path.path_angles[angle_index+1].yaw, it->path.path_angles[angle_index].delta_time, it->time_elapsed - it->path.last_angle_time)));
2177 world_view->pitch = normalize_angle(static_cast<short>(FindLinearValue(it->path.path_angles[angle_index].pitch, it->path.path_angles[angle_index+1].pitch, it->path.path_angles[angle_index].delta_time, it->time_elapsed - it->path.last_angle_time)));
2178 }
2179 }
2180
2181 if (point_index >= 0 && point_index < static_cast<short>(it->path.path_points.size()))
2182 {
2183 if (static_cast<size_t>(point_index) == it->path.path_points.size() - 1)
2184 {
2185 world_view->origin = it->path.path_points[point_index].point;
2186 world_view->origin_polygon_index = it->path.path_points[point_index].polygon;
2187 }
2188 else
2189 {
2190 world_point3d oldPoint = it->path.path_points[point_index].point;
2191 world_view->origin = FindLinearValue(it->path.path_points[point_index].point, it->path.path_points[point_index+1].point, it->path.path_points[point_index].delta_time, it->time_elapsed - it->path.last_point_time);
2192 world_point3d newPoint = world_view->origin;
2193 short polygon = it->path.path_points[point_index].polygon;
2194 ShootForTargetPoint(true, oldPoint, newPoint, polygon);
2195 world_view->origin_polygon_index = polygon;
2196 }
2197 }
2198 }
2199
2200 return using_lua_cameras;
2201 }
2202
LuaPlayerCanWieldWeapons(short player_index)2203 bool LuaPlayerCanWieldWeapons(short player_index)
2204 {
2205 return (can_wield_weapons[player_index] || !LuaRunning());
2206 }
2207
GetLuaGameEndCondition()2208 int GetLuaGameEndCondition() {
2209 return game_end_condition;
2210 }
2211
save_lua_states()2212 size_t save_lua_states()
2213 {
2214 size_t length = 0;
2215
2216 SavedLuaState.clear();
2217 for (state_map::iterator it = states.begin(); it != states.end(); ++it)
2218 {
2219 SavedLuaState[it->first] = it->second->SaveAll();
2220 if (SavedLuaState[it->first].size())
2221 {
2222 length += 6; // id, length
2223 length += SavedLuaState[it->first].size();
2224 }
2225 }
2226
2227 return length;
2228 }
2229
pack_lua_states(uint8 * data,size_t length)2230 void pack_lua_states(uint8* data, size_t length)
2231 {
2232 io::stream_buffer<io::array_sink> sb(reinterpret_cast<char*>(data), length);
2233 BOStreamBE s(&sb);
2234 for (std::map<int, std::string>::iterator it = SavedLuaState.begin(); it != SavedLuaState.end(); ++it)
2235 {
2236 if (it->second.size())
2237 {
2238 s << static_cast<int16>(it->first);
2239 s << static_cast<uint32>(it->second.size());
2240 s.write(&it->second[0], it->second.size());
2241 }
2242 }
2243
2244 SavedLuaState.clear();
2245 }
2246
unpack_lua_states(uint8 * data,size_t length)2247 void unpack_lua_states(uint8* data, size_t length)
2248 {
2249 io::stream_buffer<io::array_source> sb(reinterpret_cast<char*>(data), length);
2250 BIStreamBE s(&sb);
2251
2252 SavedLuaState.clear();
2253 while (s.tellg() != s.maxg())
2254 {
2255 int16 index;
2256 uint32 length;
2257 s >> index
2258 >> length;
2259
2260 SavedLuaState[index].resize(length);
2261 s.read(&SavedLuaState[index][0], SavedLuaState[index].size());
2262 }
2263 }
2264 #endif /* HAVE_LUA */
2265