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