• R/O
  • SSH
  • HTTPS

marathon: コミット


コミットメタ情報

リビジョン500 (tree)
日時2011-11-07 17:30:24
作者logue

ログメッセージ

◆5gHss7FzOA氏のパッチをコミット。
ターミナルテキストで文字の末尾が文字化けする問題を解消。

変更サマリ

差分

--- marathon/trunk/Source_Files/Lua/lua_player.cpp (revision 499)
+++ marathon/trunk/Source_Files/Lua/lua_player.cpp (revision 500)
@@ -1,2713 +1,2713 @@
1-/*
2-LUA_PLAYER.CPP
3-
4- Copyright (C) 2008 by Gregory Smith
5-
6- This program is free software; you can redistribute it and/or modify
7- it under the terms of the GNU General Public License as published by
8- the Free Software Foundation; either version 3 of the License, or
9- (at your option) any later version.
10-
11- This program is distributed in the hope that it will be useful,
12- but WITHOUT ANY WARRANTY; without even the implied warranty of
13- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14- GNU General Public License for more details.
15-
16- This license is contained in the file "COPYING",
17- which is included with this source code; it is available online at
18- http://www.gnu.org/licenses/gpl.html
19-
20- Implements the Lua Player class
21-*/
22-
23-#include "ActionQueues.h"
24-#include "alephversion.h"
25-#include "computer_interface.h"
26-#include "Crosshairs.h"
27-#include "fades.h"
28-#include "game_window.h"
29-#include "interface.h"
30-#include "lua_map.h"
31-#include "lua_monsters.h"
32-#include "lua_objects.h"
33-#include "lua_hud_objects.h"
34-#include "lua_player.h"
35-#include "lua_script.h"
36-#include "lua_templates.h"
37-#include "map.h"
38-#include "monsters.h"
39-#include "Music.h"
40-#include "network.h"
41-#include "player.h"
42-#include "projectiles.h"
43-#include "network_games.h"
44-#include "Random.h"
45-#include "screen.h"
46-#include "shell.h"
47-#include "SoundManager.h"
48-#include "ViewControl.h"
49-
50-#define DONT_REPEAT_DEFINITIONS
51-#include "item_definitions.h"
52-#include "projectile_definitions.h"
53-
54-#ifdef HAVE_LUA
55-
56-const float AngleConvert = 360/float(FULL_CIRCLE);
57-
58-char Lua_Action_Flags_Name[] = "action_flags";
59-typedef L_Class<Lua_Action_Flags_Name> Lua_Action_Flags;
60-
61-extern ModifiableActionQueues *GetGameQueue();
62-
63-template<uint32 flag>
64-static int Lua_Action_Flags_Get_t(lua_State *L)
65-{
66- int player_index = Lua_Action_Flags::Index(L, 1);
67-
68- if (GetGameQueue()->countActionFlags(player_index))
69- {
70- uint32 flags = GetGameQueue()->peekActionFlags(player_index, 0);
71- lua_pushboolean(L, flags & flag);
72- }
73- else
74- {
75- return luaL_error(L, "action flags are only accessible in idle()");
76- }
77-
78- return 1;
79-}
80-
81-template<uint32 flag>
82-static int Lua_Action_Flags_Set_t(lua_State *L)
83-{
84- if (!lua_isboolean(L, 2))
85- return luaL_error(L, "action flags: incorrect argument type");
86-
87- int player_index = Lua_Action_Flags::Index(L, 1);
88- if (GetGameQueue()->countActionFlags(player_index))
89- {
90- if (lua_toboolean(L, 2))
91- {
92- GetGameQueue()->modifyActionFlags(player_index, flag, flag);
93- }
94- else
95- {
96- GetGameQueue()->modifyActionFlags(player_index, 0, flag);
97- }
98- }
99- else
100- {
101- return luaL_error(L, "action flags are only accessible in idle()");
102- }
103-
104- return 0;
105-}
106-
107-static int Lua_Action_Flags_Set_Microphone(lua_State *L)
108-{
109- if (!lua_isboolean(L, 2))
110- return luaL_error(L, "action flags: incorrect argument type");
111-
112- if (lua_toboolean(L, 2))
113- return luaL_error(L, "you can only disable the microphone button flag");
114-
115- int player_index = Lua_Action_Flags::Index(L, 1);
116- if (GetGameQueue()->countActionFlags(player_index))
117- {
118- GetGameQueue()->modifyActionFlags(player_index, 0, _microphone_button);
119- }
120- else
121- {
122- return luaL_error(L, "action flags are only accessible in idle()");
123- }
124-
125- return 0;
126-}
127-
128-const luaL_reg Lua_Action_Flags_Get[] = {
129- {"action_trigger", Lua_Action_Flags_Get_t<_action_trigger_state>},
130- {"cycle_weapons_backward", Lua_Action_Flags_Get_t<_cycle_weapons_backward>},
131- {"cycle_weapons_forward", Lua_Action_Flags_Get_t<_cycle_weapons_forward>},
132- {"left_trigger", Lua_Action_Flags_Get_t<_left_trigger_state>},
133- {"microphone_button", Lua_Action_Flags_Get_t<_microphone_button>},
134- {"right_trigger", Lua_Action_Flags_Get_t<_right_trigger_state>},
135- {"toggle_map", Lua_Action_Flags_Get_t<_toggle_map>},
136- {0, 0}
137-};
138-
139-const luaL_reg Lua_Action_Flags_Set[] = {
140- {"action_trigger", Lua_Action_Flags_Set_t<_action_trigger_state>},
141- {"cycle_weapons_backward", Lua_Action_Flags_Set_t<_cycle_weapons_backward>},
142- {"cycle_weapons_forward", Lua_Action_Flags_Set_t<_cycle_weapons_forward>},
143- {"left_trigger", Lua_Action_Flags_Set_t<_left_trigger_state>},
144- {"microphone_button", Lua_Action_Flags_Set_Microphone},
145- {"right_trigger", Lua_Action_Flags_Set_t<_right_trigger_state>},
146- {"toggle_map", Lua_Action_Flags_Set_t<_toggle_map>},
147- {0, 0}
148-};
149-
150-extern vector<lua_camera> lua_cameras;
151-
152-char Lua_Camera_Path_Points_Name[] = "camera_path_points";
153-typedef L_Class<Lua_Camera_Path_Points_Name> Lua_Camera_Path_Points;
154-
155-int Lua_Camera_Path_Points_New(lua_State *L)
156-{
157- if (!lua_isnumber(L, 2) || !lua_isnumber(L, 3) || !lua_isnumber(L, 4) || !lua_isnumber(L, 6))
158- return luaL_error(L, "new: incorrect argument type");
159-
160- int camera_index = Lua_Camera_Path_Points::Index(L, 1);
161-
162- int polygon = 0;
163- if (lua_isnumber(L, 5))
164- {
165- polygon = static_cast<int>(lua_tonumber(L, 5));
166- if (!Lua_Polygon::Valid(polygon))
167- return luaL_error(L, "new: invalid polygon index");
168- }
169- else if (Lua_Polygon::Is(L, 5))
170- {
171- polygon = Lua_Polygon::Index(L, 5);
172- }
173- else
174- return luaL_error(L, "new: incorrect argument type");
175-
176- world_point3d point = {
177- static_cast<world_distance>(lua_tonumber(L, 2) * WORLD_ONE),
178- static_cast<world_distance>(lua_tonumber(L, 3) * WORLD_ONE),
179- static_cast<world_distance>(lua_tonumber(L, 4) * WORLD_ONE)
180- };
181-
182- int32 time = static_cast<int32>(lua_tonumber(L, 6));
183- int point_index = lua_cameras[camera_index].path.path_points.size();
184- lua_cameras[camera_index].path.path_points.resize(point_index+1);
185- lua_cameras[camera_index].path.path_points[point_index].polygon = polygon;
186- lua_cameras[camera_index].path.path_points[point_index].point = point;
187- lua_cameras[camera_index].path.path_points[point_index].delta_time = time;
188- return 0;
189-}
190-
191-const luaL_reg Lua_Camera_Path_Points_Get[] = {
192- {"new", L_TableFunction<Lua_Camera_Path_Points_New>},
193- {0, 0}
194-};
195-
196-char Lua_Camera_Path_Angles_Name[] = "camera_path_angles";
197-typedef L_Class<Lua_Camera_Path_Angles_Name> Lua_Camera_Path_Angles;
198-
199-int Lua_Camera_Path_Angles_New(lua_State *L)
200-{
201- if (!lua_isnumber(L, 2) || !lua_isnumber(L, 3) || !lua_isnumber(L, 4))
202- return luaL_error(L, "new: incorrect argument type");
203-
204- int camera_index = Lua_Camera_Path_Angles::Index(L, 1);
205- short yaw = static_cast<short>(lua_tonumber(L,2));
206- short pitch = static_cast<short>(lua_tonumber(L,3));
207- int32 time = static_cast<int32>(lua_tonumber(L,4));
208- int angle_index = lua_cameras[camera_index].path.path_angles.size();
209-
210- lua_cameras[camera_index].path.path_angles.resize(angle_index+1);
211- lua_cameras[camera_index].path.path_angles[angle_index].yaw = static_cast<short>(yaw/AngleConvert);
212- lua_cameras[camera_index].path.path_angles[angle_index].pitch = static_cast<short>(pitch/AngleConvert);
213- lua_cameras[camera_index].path.path_angles[angle_index].delta_time = time;
214- return 0;
215-};
216-
217-const luaL_reg Lua_Camera_Path_Angles_Get[] = {
218- {"new", L_TableFunction<Lua_Camera_Path_Angles_New>},
219- {0, 0}
220-};
221-
222-char Lua_Camera_Name[] = "camera";
223-typedef L_Class<Lua_Camera_Name> Lua_Camera;
224-
225-
226-int Lua_Camera_Activate(lua_State *L)
227-{
228- int player_index = -1;
229- if (lua_isnumber(L, 2))
230- {
231- player_index = static_cast<int>(lua_tonumber(L, 2));
232- }
233- else if (Lua_Player::Is(L, 2))
234- {
235- player_index = Lua_Player::Index(L, 2);
236- }
237- else
238- return luaL_error(L, "activate: incorrect argument type");
239-
240- if (player_index == local_player_index)
241- {
242- int camera_index = Lua_Camera::Index(L, 1);
243- lua_cameras[camera_index].time_elapsed = 0;
244- lua_cameras[camera_index].player_active = player_index;
245- lua_cameras[camera_index].path.current_point_index = 0;
246- lua_cameras[camera_index].path.current_angle_index = 0;
247- lua_cameras[camera_index].path.last_point_time = 0;
248- lua_cameras[camera_index].path.last_angle_time = 0;
249- }
250-
251- return 0;
252-}
253-
254-int Lua_Camera_Clear(lua_State *L)
255-{
256- int camera_index = Lua_Camera::Index(L, 1);
257- lua_cameras[camera_index].path.path_points.resize(0);
258- lua_cameras[camera_index].path.path_angles.resize(0);
259- return 0;
260-}
261-
262-int Lua_Camera_Deactivate(lua_State *L)
263-{
264- int camera_index = Lua_Camera::Index(L, 1);
265- lua_cameras[camera_index].time_elapsed = 0;
266- lua_cameras[camera_index].player_active = -1;
267- lua_cameras[camera_index].path.last_point_time = 0;
268- lua_cameras[camera_index].path.last_angle_time = 0;
269- return 0;
270-}
271-
272-static int Lua_Get_Path_Angles(lua_State *L)
273-{
274- Lua_Camera_Path_Angles::Push(L, Lua_Camera::Index(L, 1));
275- return 1;
276-}
277-
278-static int Lua_Get_Path_Points(lua_State *L)
279-{
280- Lua_Camera_Path_Points::Push(L, Lua_Camera::Index(L, 1));
281- return 1;
282-}
283-
284-const luaL_reg Lua_Camera_Get[] = {
285- {"activate", L_TableFunction<Lua_Camera_Activate>},
286- {"clear", L_TableFunction<Lua_Camera_Clear>},
287- {"deactivate", L_TableFunction<Lua_Camera_Deactivate>},
288- {"path_angles", Lua_Get_Path_Angles},
289- {"path_points", Lua_Get_Path_Points},
290- {0, 0}
291-};
292-
293-static int Lua_Camera_Valid(int16 index)
294-{
295- return index >= 0 && index < lua_cameras.size();
296-}
297-
298-char Lua_Cameras_Name[] = "Cameras";
299-typedef L_Container<Lua_Cameras_Name, Lua_Camera> Lua_Cameras;
300-
301-static int Lua_Cameras_New(lua_State *L)
302-{
303- if (lua_cameras.size() == INT16_MAX)
304- {
305- return 0;
306- }
307-
308- lua_camera camera;
309- camera.index = lua_cameras.size();
310- camera.path.index = lua_cameras.size();
311- camera.path.current_point_index = 0;
312- camera.path.current_angle_index = 0;
313- camera.path.last_point_time = 0;
314- camera.path.last_angle_time = 0;
315- camera.time_elapsed = 0;
316- camera.player_active = -1;
317- lua_cameras.push_back(camera);
318-
319- Lua_Camera::Push(L, camera.index);
320-
321- return 1;
322-}
323-
324-const luaL_reg Lua_Cameras_Methods[] = {
325- {"new", Lua_Cameras_New},
326- {0, 0}
327-};
328-
329-static int16 Lua_Cameras_Length() {
330- return lua_cameras.size();
331-}
332-
333-char Lua_Crosshairs_Name[] = "crosshairs";
334-typedef L_Class<Lua_Crosshairs_Name> Lua_Crosshairs;
335-
336-static int Lua_Crosshairs_Get_Active(lua_State *L)
337-{
338- int player_index = Lua_Crosshairs::Index(L, 1);
339- if (player_index == local_player_index)
340- {
341- lua_pushboolean(L, Crosshairs_IsActive());
342- return 1;
343- }
344- else
345- {
346- return 0;
347- }
348-}
349-
350-const luaL_reg Lua_Crosshairs_Get[] = {
351- {"active", Lua_Crosshairs_Get_Active},
352- {0, 0}
353-};
354-
355-static int Lua_Crosshairs_Set_Active(lua_State *L)
356-{
357- int player_index = Lua_Crosshairs::Index(L, 1);
358- if (player_index == local_player_index)
359- {
360- if (!lua_isboolean(L, 2))
361- return luaL_error(L, "active: incorrect argument type");
362-
363- Crosshairs_SetActive(lua_toboolean(L, 2));
364- }
365-
366- return 0;
367-}
368-
369-const luaL_reg Lua_Crosshairs_Set[] = {
370- {"active", Lua_Crosshairs_Set_Active},
371- {0, 0}
372-};
373-
374-char Lua_OverlayColor_Name[] = "overlay_color";
375-typedef L_Enum<Lua_OverlayColor_Name> Lua_OverlayColor;
376-
377-template<char *name>
378-class PlayerSubtable : public L_Class<name>
379-{
380-public:
381- int16 m_player_index;
382- static PlayerSubtable *Push(lua_State *L, int16 player_index, int16 index);
383- static int16 PlayerIndex(lua_State *L, int index);
384-};
385-
386-template<char *name>
387-PlayerSubtable<name> *PlayerSubtable<name>::Push(lua_State *L, int16 player_index, int16 index)
388-{
389- PlayerSubtable<name> *t = 0;
390-
391- if (!L_Class<name, int16>::Valid(index) || !Lua_Player::Valid(player_index))
392- {
393- lua_pushnil(L);
394- return 0;
395- }
396-
397- t = static_cast<PlayerSubtable<name>*>(lua_newuserdata(L, sizeof(PlayerSubtable<name>)));
398- luaL_getmetatable(L, name);
399- lua_setmetatable(L, -2);
400- t->m_index = index;
401- t->m_player_index = player_index;
402-
403- return t;
404-}
405-
406-template<char *name>
407-int16 PlayerSubtable<name>::PlayerIndex(lua_State *L, int index)
408-{
409- PlayerSubtable<name> *t = static_cast<PlayerSubtable<name> *>(lua_touserdata(L, index));
410- if (!t) luaL_typerror(L, index, name);
411- return t->m_player_index;
412-}
413-
414-char Lua_Overlay_Name[] = "overlay";
415-typedef PlayerSubtable<Lua_Overlay_Name> Lua_Overlay;
416-
417-int Lua_Overlay_Clear(lua_State *L)
418-{
419- int index = Lua_Overlay::Index(L, 1);
420- if (Lua_Overlay::PlayerIndex(L, 1) == local_player_index)
421- {
422- SetScriptHUDIcon(index, 0, 0);
423- SetScriptHUDText(index, 0);
424- }
425-
426- return 0;
427-}
428-
429-int Lua_Overlay_Fill_Icon(lua_State *L)
430-{
431- if (Lua_Overlay::PlayerIndex(L, 1) == local_player_index)
432- {
433- int color = Lua_OverlayColor::ToIndex(L, 2);
434- SetScriptHUDSquare(Lua_Overlay::Index(L, 1), color);
435- }
436-
437- return 0;
438-}
439-
440-const luaL_reg Lua_Overlay_Get[] = {
441- {"clear", L_TableFunction<Lua_Overlay_Clear>},
442- {"fill_icon", L_TableFunction<Lua_Overlay_Fill_Icon>},
443- {0, 0}
444-};
445-
446-static int Lua_Overlay_Set_Icon(lua_State *L)
447-{
448- if (Lua_Overlay::PlayerIndex(L, 1) == local_player_index)
449- {
450- if (lua_isstring(L, 2))
451- {
452- SetScriptHUDIcon(Lua_Overlay::Index(L, 1), lua_tostring(L, 2), lua_strlen(L, 2));
453- }
454- else
455- {
456- SetScriptHUDIcon(Lua_Overlay::Index(L, 1), 0, 0);
457- }
458- }
459-
460- return 0;
461-}
462-
463-static int Lua_Overlay_Set_Text(lua_State *L)
464-{
465- if (Lua_Overlay::PlayerIndex(L, 1) == local_player_index)
466- {
467- const char *text = 0;
468- if (lua_isstring(L, 2))
469- text = lua_tostring(L, 2);
470-
471- SetScriptHUDText(Lua_Overlay::Index(L, 1), text);
472- }
473-
474- return 0;
475-}
476-
477-static int Lua_Overlay_Set_Text_Color(lua_State *L)
478-{
479- if (Lua_Overlay::PlayerIndex(L, 1) == local_player_index)
480- {
481- int color = Lua_OverlayColor::ToIndex(L, 2);
482- SetScriptHUDColor(Lua_Overlay::Index(L, 1), color);
483- }
484-
485- return 0;
486-}
487-
488-const luaL_reg Lua_Overlay_Set[] = {
489- {"color", Lua_Overlay_Set_Text_Color},
490- {"icon", Lua_Overlay_Set_Icon},
491- {"text", Lua_Overlay_Set_Text},
492- {0, 0}
493-};
494-
495-char Lua_Overlays_Name[] = "overlays";
496-typedef L_Class<Lua_Overlays_Name> Lua_Overlays;
497-
498-static int Lua_Overlays_Get(lua_State *L)
499-{
500- if (lua_isnumber(L, 2))
501- {
502- int player_index = Lua_Overlays::Index(L, 1);
503- int index = static_cast<int>(lua_tonumber(L, 2));
504- if (Lua_Overlays::Valid(player_index) && index >= 0 && index < MAXIMUM_NUMBER_OF_SCRIPT_HUD_ELEMENTS)
505- {
506- Lua_Overlay::Push(L, player_index, index);
507- }
508- else
509- {
510- lua_pushnil(L);
511- }
512- }
513- else
514- {
515- lua_pushnil(L);
516- }
517-
518- return 1;
519-}
520-
521-static int Lua_Overlays_Length(lua_State *L)
522-{
523- int player_index = Lua_Overlays::Index(L, 1);
524- if (Lua_Overlays::Valid(player_index))
525- lua_pushnumber(L, MAXIMUM_NUMBER_OF_SCRIPT_HUD_ELEMENTS);
526- else
527- lua_pushnumber(L, 0);
528- return 1;
529-}
530-
531-const luaL_reg Lua_Overlays_Metatable[] = {
532- {"__index", Lua_Overlays_Get},
533- {"__len", Lua_Overlays_Length},
534- {0, 0}
535-};
536-
537-extern bool use_lua_compass[MAXIMUM_NUMBER_OF_NETWORK_PLAYERS];
538-extern world_point2d lua_compass_beacons[MAXIMUM_NUMBER_OF_NETWORK_PLAYERS];
539-extern short lua_compass_states[MAXIMUM_NUMBER_OF_NETWORK_PLAYERS];
540-
541-char Lua_Player_Compass_Name[] = "player_compass";
542-typedef L_Class<Lua_Player_Compass_Name> Lua_Player_Compass;
543-
544-template<short state>
545-int Lua_Player_Compass_All(lua_State *L)
546-{
547- int player_index = Lua_Player_Compass::Index(L, 1);
548- lua_compass_states[player_index] = state;
549- return 0;
550-}
551-
552-static int Lua_Player_Compass_Get_Lua(lua_State *L)
553-{
554- int player_index = Lua_Player_Compass::Index(L, 1);
555- lua_pushboolean(L, use_lua_compass[player_index]);
556- return 1;
557-}
558-
559-template<short state>
560-static int Lua_Player_Compass_Get_State(lua_State *L)
561-{
562- int player_index = Lua_Player_Compass::Index(L, 1);
563- lua_pushboolean(L, lua_compass_states[player_index] & state);
564- return 1;
565-}
566-
567-static int Lua_Player_Compass_Get_X(lua_State *L)
568-{
569- int player_index = Lua_Player_Compass::Index(L, 1);
570- lua_pushnumber(L, static_cast<double>(lua_compass_beacons[player_index].x / WORLD_ONE));
571- return 1;
572-}
573-
574-static int Lua_Player_Compass_Get_Y(lua_State *L)
575-{
576- int player_index = Lua_Player_Compass::Index(L, 1);
577- lua_pushnumber(L, static_cast<double>(lua_compass_beacons[player_index].y / WORLD_ONE));
578- return 1;
579-}
580-
581-const luaL_reg Lua_Player_Compass_Get[] = {
582- {"all_off", L_TableFunction<Lua_Player_Compass_All<_network_compass_all_off> >},
583- {"all_on", L_TableFunction<Lua_Player_Compass_All<_network_compass_all_on> >},
584- {"beacon", Lua_Player_Compass_Get_State<_network_compass_use_beacon>},
585- {"lua", Lua_Player_Compass_Get_Lua},
586- {"ne", Lua_Player_Compass_Get_State<_network_compass_ne>},
587- {"northeast", Lua_Player_Compass_Get_State<_network_compass_ne>},
588- {"northwest", Lua_Player_Compass_Get_State<_network_compass_nw>},
589- {"nw", Lua_Player_Compass_Get_State<_network_compass_nw>},
590- {"se", Lua_Player_Compass_Get_State<_network_compass_se>},
591- {"southeast", Lua_Player_Compass_Get_State<_network_compass_se>},
592- {"southwest", Lua_Player_Compass_Get_State<_network_compass_sw>},
593- {"sw", Lua_Player_Compass_Get_State<_network_compass_sw>},
594- {"x", Lua_Player_Compass_Get_X},
595- {"y", Lua_Player_Compass_Get_Y},
596- {0, 0}
597-};
598-
599-static int Lua_Player_Compass_Set_Lua(lua_State *L)
600-{
601- if (!lua_isboolean(L, 2))
602- return luaL_error(L, "lua: incorrect argument type");
603-
604- int player_index = Lua_Player_Compass::Index(L, 1);
605- use_lua_compass[player_index] = lua_toboolean(L, 2);
606- return 0;
607-}
608-
609-template<short state>
610-static int Lua_Player_Compass_Set_State(lua_State *L)
611-{
612- if (!lua_isboolean(L, 2))
613- return luaL_error(L, "compass: incorrect argument type");
614-
615- int player_index = Lua_Player_Compass::Index(L, 1);
616- if (lua_toboolean(L, 2))
617- {
618- lua_compass_states[player_index] |= state;
619- }
620- else
621- {
622- lua_compass_states[player_index] &= ~state;
623- }
624-
625- return 0;
626-}
627-
628-static int Lua_Player_Compass_Set_X(lua_State *L)
629-{
630- if (!lua_isnumber(L, 2))
631- return luaL_error(L, "x: incorrect argument type");
632-
633- int player_index = Lua_Player_Compass::Index(L, 1);
634- lua_compass_beacons[player_index].x = static_cast<world_distance>(lua_tonumber(L, 2) * WORLD_ONE);
635- return 0;
636-}
637-
638-static int Lua_Player_Compass_Set_Y(lua_State *L)
639-{
640- if (!lua_isnumber(L, 2))
641- return luaL_error(L, "y: incorrect argument type");
642-
643- int player_index = Lua_Player_Compass::Index(L, 1);
644- lua_compass_beacons[player_index].y = static_cast<world_distance>(lua_tonumber(L, 2) * WORLD_ONE);
645- return 0;
646-}
647-
648-const luaL_reg Lua_Player_Compass_Set[] = {
649- {"beacon", Lua_Player_Compass_Set_State<_network_compass_use_beacon>},
650- {"lua", Lua_Player_Compass_Set_Lua},
651- {"ne", Lua_Player_Compass_Set_State<_network_compass_ne>},
652- {"northeast", Lua_Player_Compass_Set_State<_network_compass_ne>},
653- {"northwest", Lua_Player_Compass_Set_State<_network_compass_nw>},
654- {"nw", Lua_Player_Compass_Set_State<_network_compass_nw>},
655- {"se", Lua_Player_Compass_Set_State<_network_compass_se>},
656- {"southeast", Lua_Player_Compass_Set_State<_network_compass_se>},
657- {"southwest", Lua_Player_Compass_Set_State<_network_compass_sw>},
658- {"sw", Lua_Player_Compass_Set_State<_network_compass_sw>},
659- {"x", Lua_Player_Compass_Set_X},
660- {"y", Lua_Player_Compass_Set_Y},
661- {0, 0}
662-};
663-
664-char Lua_Player_Items_Name[] = "player_items";
665-typedef L_Class<Lua_Player_Items_Name> Lua_Player_Items;
666-
667-static int Lua_Player_Items_Get(lua_State *L)
668-{
669- int player_index = Lua_Player_Items::Index(L, 1);
670- int item_type = Lua_ItemType::ToIndex(L, 2);
671-
672- player_data *player = get_player_data(player_index);
673- int item_count = player->items[item_type];
674- if (item_count == NONE) item_count = 0;
675- lua_pushnumber(L, item_count);
676- return 1;
677-}
678-
679-static int Lua_Player_Items_Length(lua_State *L)
680-{
681- lua_pushnumber(L, NUMBER_OF_DEFINED_ITEMS);
682- return 1;
683-}
684-
685-extern void destroy_players_ball(short player_index);
686-extern void select_next_best_weapon(short player_index);
687-
688-static int Lua_Player_Items_Set(lua_State *L)
689-{
690- if (!lua_isnumber(L, 3))
691- return luaL_error(L, "items: incorrect argument type");
692-
693- int player_index = Lua_Player_Items::Index(L, 1);
694- player_data *player = get_player_data(player_index);
695- int item_type = Lua_ItemType::ToIndex(L, 2);
696- int item_count = player->items[item_type];
697- item_definition *definition = get_item_definition_external(item_type);
698- int new_item_count = static_cast<int>(lua_tonumber(L, 3));
699-
700- bool accounting = L_Get_Proper_Item_Accounting(L);
701-
702- if (new_item_count < 0)
703- luaL_error(L, "items: invalid item count");
704-
705- if (item_count == NONE) item_count = 0;
706- int real_difference = item_count - new_item_count;
707- if (new_item_count == 0) new_item_count = NONE;
708-
709- if (new_item_count < item_count)
710- {
711- if (definition->item_kind == _ball)
712- {
713- if (find_player_ball_color(player_index) != NONE)
714- destroy_players_ball(player_index);
715- }
716- else
717- {
718- player->items[item_type] = new_item_count;
719- mark_player_inventory_as_dirty(player_index, item_type);
720- if (definition->item_kind == _weapon && player->items[item_type] == NONE)
721- {
722- select_next_best_weapon(player_index);
723- }
724-
725- if (accounting)
726- {
727- for (int i = 0; i < real_difference; ++i)
728- object_was_just_destroyed(_object_is_item, item_type);
729- }
730- }
731- }
732- else if (new_item_count > item_count)
733- {
734- while (new_item_count-- > item_count)
735- {
736- if (try_and_add_player_item(player_index, item_type))
737- {
738- if (accounting)
739- object_was_just_added(_object_is_item, item_type);
740- }
741- }
742- }
743-
744- return 0;
745-}
746-
747-const luaL_reg Lua_Player_Items_Metatable[] = {
748- {"__index", Lua_Player_Items_Get},
749- {"__newindex", Lua_Player_Items_Set},
750- {"__len", Lua_Player_Items_Length},
751- {0, 0}
752-};
753-
754-char Lua_InternalVelocity_Name[] = "internal_velocity";
755-typedef L_Class<Lua_InternalVelocity_Name> Lua_InternalVelocity;
756-
757-static int Lua_InternalVelocity_Get_Forward(lua_State *L)
758-{
759- int player_index = Lua_InternalVelocity::Index(L, 1);
760- player_data *player = get_player_data(player_index);
761- lua_pushnumber(L, (double) player->variables.velocity / FIXED_ONE);
762- return 1;
763-}
764-
765-static int Lua_InternalVelocity_Get_Perpendicular(lua_State *L)
766-{
767- int player_index = Lua_InternalVelocity::Index(L, 1);
768- player_data *player = get_player_data(player_index);
769- lua_pushnumber(L, (double) player->variables.perpendicular_velocity / FIXED_ONE);
770- return 1;
771-}
772-
773-const luaL_reg Lua_InternalVelocity_Get[] = {
774- {"forward", Lua_InternalVelocity_Get_Forward},
775- {"perpendicular", Lua_InternalVelocity_Get_Perpendicular},
776- {0, 0}
777-};
778-
779-char Lua_ExternalVelocity_Name[] = "external_velocity";
780-typedef L_Class<Lua_ExternalVelocity_Name> Lua_ExternalVelocity;
781-
782-static int Lua_ExternalVelocity_Get_I(lua_State *L)
783-{
784- lua_pushnumber(L, (double) get_player_data(Lua_ExternalVelocity::Index(L, 1))->variables.external_velocity.i / WORLD_ONE);
785- return 1;
786-}
787-
788-static int Lua_ExternalVelocity_Get_J(lua_State *L)
789-{
790- lua_pushnumber(L, (double) get_player_data(Lua_ExternalVelocity::Index(L, 1))->variables.external_velocity.j / WORLD_ONE);
791- return 1;
792-}
793-
794-static int Lua_ExternalVelocity_Get_K(lua_State *L)
795-{
796- lua_pushnumber(L, (double) get_player_data(Lua_ExternalVelocity::Index(L, 1))->variables.external_velocity.k / WORLD_ONE);
797- return 1;
798-}
799-
800-const luaL_reg Lua_ExternalVelocity_Get[] = {
801- {"i", Lua_ExternalVelocity_Get_I},
802- {"j", Lua_ExternalVelocity_Get_J},
803- {"k", Lua_ExternalVelocity_Get_K},
804- {"x", Lua_ExternalVelocity_Get_I},
805- {"y", Lua_ExternalVelocity_Get_J},
806- {"z", Lua_ExternalVelocity_Get_K},
807- {0, 0}
808-};
809-
810-static int Lua_ExternalVelocity_Set_I(lua_State *L)
811-{
812- if (!lua_isnumber(L, 2))
813- return luaL_error(L, "i: incorrect argument type");
814-
815- int raw_velocity = static_cast<int>(lua_tonumber(L, 2) * WORLD_ONE);
816- get_player_data(Lua_ExternalVelocity::Index(L, 1))->variables.external_velocity.i = raw_velocity;
817- return 0;
818-}
819-
820-static int Lua_ExternalVelocity_Set_J(lua_State *L)
821-{
822- if (!lua_isnumber(L, 2))
823- return luaL_error(L, "j: incorrect argument type");
824-
825- int raw_velocity = static_cast<int>(lua_tonumber(L, 2) * WORLD_ONE);
826- get_player_data(Lua_ExternalVelocity::Index(L, 1))->variables.external_velocity.j = raw_velocity;
827- return 0;
828-}
829-
830-static int Lua_ExternalVelocity_Set_K(lua_State *L)
831-{
832- if (!lua_isnumber(L, 2))
833- return luaL_error(L, "k: incorrect argument type");
834-
835- int raw_velocity = static_cast<int>(lua_tonumber(L, 2) * WORLD_ONE);
836- get_player_data(Lua_ExternalVelocity::Index(L, 1))->variables.external_velocity.k = raw_velocity;
837- return 0;
838-}
839-
840-const luaL_reg Lua_ExternalVelocity_Set[] = {
841- {"i", Lua_ExternalVelocity_Set_I},
842- {"j", Lua_ExternalVelocity_Set_J},
843- {"k", Lua_ExternalVelocity_Set_K},
844- {"x", Lua_ExternalVelocity_Set_I},
845- {"y", Lua_ExternalVelocity_Set_J},
846- {"z", Lua_ExternalVelocity_Set_K},
847- {0, 0}
848-};
849-
850-char Lua_FadeType_Name[] = "fade_type";
851-typedef L_Enum<Lua_FadeType_Name> Lua_FadeType;
852-
853-char Lua_FadeTypes_Name[] = "FadeTypes";
854-typedef L_EnumContainer<Lua_FadeTypes_Name, Lua_FadeType> Lua_FadeTypes;
855-
856-const int MAX_TEXTURE_PALETTE_SIZE = 256;
857-struct lua_texture {
858- shape_descriptor shape;
859- short type;
860-};
861-typedef struct lua_texture lua_texture;
862-static std::vector<lua_texture> lua_texture_palette;
863-static int lua_texture_palette_selected = -1;
864-
865-void LuaTexturePaletteClear() {
866- lua_texture_palette.clear();
867-}
868-
869-int LuaTexturePaletteSize() {
870- return lua_texture_palette.size();
871-}
872-
873-shape_descriptor LuaTexturePaletteTexture(size_t index)
874-{
875- if (index < lua_texture_palette.size())
876- return lua_texture_palette[index].shape;
877- else
878- return UNONE;
879-}
880-
881-short LuaTexturePaletteTextureType(size_t index)
882-{
883- if (index < lua_texture_palette.size())
884- return lua_texture_palette[index].type;
885- else
886- return 0;
887-}
888-
889-int LuaTexturePaletteSelected()
890-{
891- return lua_texture_palette_selected;
892-}
893-
894-char Lua_Texture_Palette_Slot_Name[] = "texture_palette_slot";
895-typedef PlayerSubtable<Lua_Texture_Palette_Slot_Name> Lua_Texture_Palette_Slot;
896-
897-int Lua_Texture_Palette_Slot_Clear(lua_State *L)
898-{
899- int player_index = Lua_Texture_Palette_Slot::PlayerIndex(L, 1);
900- if (player_index != local_player_index)
901- return 0;
902-
903- lua_texture blank = { UNONE, 0 };
904- lua_texture_palette[Lua_Texture_Palette_Slot::Index(L, 1)] = blank;
905- return 0;
906-}
907-
908-static int Lua_Texture_Palette_Slot_Get_Collection(lua_State *L)
909-{
910- int player_index = Lua_Texture_Palette_Slot::PlayerIndex(L, 1);
911- if (player_index != local_player_index)
912- return 0;
913-
914- int index = Lua_Texture_Palette_Slot::Index(L, 1);
915- if (lua_texture_palette[index].shape == UNONE)
916- return 0;
917-
918- lua_pushnumber(L, GET_COLLECTION(GET_DESCRIPTOR_COLLECTION(lua_texture_palette[index].shape)));
919- return 1;
920-}
921-
922-static int Lua_Texture_Palette_Slot_Get_Texture(lua_State *L)
923-{
924- int player_index = Lua_Texture_Palette_Slot::PlayerIndex(L, 1);
925- if (player_index != local_player_index)
926- return 0;
927-
928- int index = Lua_Texture_Palette_Slot::Index(L, 1);
929- if (lua_texture_palette[index].shape == UNONE)
930- return 0;
931-
932- lua_pushnumber(L, GET_DESCRIPTOR_SHAPE(lua_texture_palette[index].shape));
933- return 1;
934-}
935-
936-static int Lua_Texture_Palette_Slot_Get_Type(lua_State *L)
937-{
938- int player_index = Lua_Texture_Palette_Slot::PlayerIndex(L, 1);
939- if (player_index != local_player_index)
940- return 0;
941-
942- int index = Lua_Texture_Palette_Slot::Index(L, 1);
943- if (lua_texture_palette[index].shape == UNONE)
944- return 0;
945-
946- lua_pushnumber(L, lua_texture_palette[index].type);
947- return 1;
948-}
949-
950-const luaL_reg Lua_Texture_Palette_Slot_Get[] = {
951- {"clear", L_TableFunction<Lua_Texture_Palette_Slot_Clear>},
952- {"collection", Lua_Texture_Palette_Slot_Get_Collection},
953- {"texture_index", Lua_Texture_Palette_Slot_Get_Texture},
954- {"type", Lua_Texture_Palette_Slot_Get_Type},
955- {0, 0}
956-};
957-
958-static int Lua_Texture_Palette_Slot_Set_Collection(lua_State *L)
959-{
960- int player_index = Lua_Texture_Palette_Slot::PlayerIndex(L, 1);
961- if (player_index != local_player_index)
962- return 0;
963-
964- int16 index = Lua_Texture_Palette_Slot::Index(L, 1);
965- short collection_index = Lua_Collection::ToIndex(L, 2);
966-
967- lua_texture_palette[index].shape = BUILD_DESCRIPTOR(collection_index, GET_DESCRIPTOR_SHAPE(lua_texture_palette[index].shape));
968- return 0;
969-}
970-
971-static int Lua_Texture_Palette_Slot_Set_Texture(lua_State *L)
972-{
973- int player_index = Lua_Texture_Palette_Slot::PlayerIndex(L, 1);
974- if (player_index != local_player_index)
975- return 0;
976-
977- if (!lua_isnumber(L, 2))
978- return luaL_error(L, "texture_index: incorrect argument type");
979-
980- int16 index = Lua_Texture_Palette_Slot::Index(L, 1);
981- short shape_index = static_cast<short>(lua_tonumber(L, 2));
982- if (shape_index < 0 || shape_index >= MAXIMUM_SHAPES_PER_COLLECTION)
983- return luaL_error(L, "texture_index: invalid texture index");
984-
985- lua_texture_palette[index].shape = BUILD_DESCRIPTOR(GET_DESCRIPTOR_COLLECTION(lua_texture_palette[index].shape), shape_index);
986- return 0;
987-}
988-
989-static int Lua_Texture_Palette_Slot_Set_Type(lua_State *L)
990-{
991- int player_index = Lua_Texture_Palette_Slot::PlayerIndex(L, 1);
992- if (player_index != local_player_index)
993- return 0;
994-
995- int16 index = Lua_Texture_Palette_Slot::Index(L, 1);
996- short texture_type = Lua_TextureType::ToIndex(L, 2);
997-
998- lua_texture_palette[index].type = texture_type;
999- return 0;
1000-}
1001-
1002-
1003-const luaL_reg Lua_Texture_Palette_Slot_Set[] = {
1004- {"collection", Lua_Texture_Palette_Slot_Set_Collection},
1005- {"texture_index", Lua_Texture_Palette_Slot_Set_Texture},
1006- {"type", Lua_Texture_Palette_Slot_Set_Type},
1007- {0, 0}
1008-};
1009-
1010-char Lua_Texture_Palette_Slots_Name[] = "texture_palette_slots";
1011-typedef L_Class<Lua_Texture_Palette_Slots_Name> Lua_Texture_Palette_Slots;
1012-
1013-static int Lua_Texture_Palette_Slots_Get(lua_State *L)
1014-{
1015- if (lua_isnumber(L, 2))
1016- {
1017- int player_index = Lua_Texture_Palette_Slots::Index(L, 1);
1018- int index = static_cast<int>(lua_tonumber(L, 2));
1019- if (Lua_Texture_Palette_Slots::Valid(player_index) && index >= 0 && index < lua_texture_palette.size())
1020- {
1021- Lua_Texture_Palette_Slot::Push(L, player_index, index);
1022- }
1023- else
1024- {
1025- lua_pushnil(L);
1026- }
1027- }
1028- else
1029- {
1030- lua_pushnil(L);
1031- }
1032-
1033- return 1;
1034-}
1035-
1036-static int Lua_Texture_Palette_Slots_Length(lua_State *L)
1037-{
1038- int player_index = Lua_Texture_Palette_Slots::Index(L, 1);
1039- if (player_index != local_player_index)
1040- return 0;
1041-
1042- lua_pushnumber(L, lua_texture_palette.size());
1043- return 1;
1044-}
1045-
1046-const luaL_reg Lua_Texture_Palette_Slots_Metatable[] = {
1047- {"__index", Lua_Texture_Palette_Slots_Get},
1048- {"__len", Lua_Texture_Palette_Slots_Length},
1049- {0, 0}
1050-};
1051-
1052-char Lua_Texture_Palette_Name[] = "texture_palette";
1053-typedef L_Class<Lua_Texture_Palette_Name> Lua_Texture_Palette;
1054-
1055-static int Lua_Texture_Palette_Get_Selected(lua_State *L)
1056-{
1057- int player_index = Lua_Texture_Palette::Index(L, 1);
1058- if (player_index != local_player_index)
1059- return 0;
1060-
1061- if (lua_texture_palette_selected == -1)
1062- return 0;
1063-
1064- lua_pushnumber(L, lua_texture_palette_selected);
1065- return 1;
1066-}
1067-
1068-static int Lua_Texture_Palette_Get_Size(lua_State *L)
1069-{
1070- int player_index = Lua_Texture_Palette::Index(L, 1);
1071- if (player_index != local_player_index)
1072- return 0;
1073-
1074- lua_pushnumber(L, lua_texture_palette.size());
1075- return 1;
1076-}
1077-
1078-static int Lua_Texture_Palette_Get_Slots(lua_State *L)
1079-{
1080- Lua_Texture_Palette_Slots::Push(L, Lua_Texture_Palette::Index(L, 1));
1081- return 1;
1082-}
1083-
1084-const luaL_reg Lua_Texture_Palette_Get[] = {
1085- {"highlight", Lua_Texture_Palette_Get_Selected},
1086- {"size", Lua_Texture_Palette_Get_Size},
1087- {"slots", Lua_Texture_Palette_Get_Slots},
1088- {0, 0}
1089-};
1090-
1091-extern void draw_panels();
1092-
1093-static int Lua_Texture_Palette_Set_Selected(lua_State *L)
1094-{
1095- int player_index = Lua_Texture_Palette::Index(L, 1);
1096- if (player_index != local_player_index)
1097- return 0;
1098-
1099- if (lua_isnil(L, 2))
1100- lua_texture_palette_selected = -1;
1101- else if (lua_isnumber(L, 2))
1102- {
1103- int selected = static_cast<int>(lua_tonumber(L, 2));
1104- if (selected < -1 || selected > lua_texture_palette.size())
1105- return luaL_error(L, "highlight: invalid slot");
1106-
1107- lua_texture_palette_selected = selected;
1108- draw_panels();
1109- }
1110- else
1111- return luaL_error(L, "highlight: incorrect argument type");
1112-
1113- return 0;
1114-}
1115-
1116-
1117-static int Lua_Texture_Palette_Set_Size(lua_State *L)
1118-{
1119- int player_index = Lua_Texture_Palette::Index(L, 1);
1120- if (player_index != local_player_index)
1121- return 0;
1122-
1123- if (!lua_isnumber(L, 2))
1124- return luaL_error(L, "size: incorrect argument type");
1125-
1126- size_t size = static_cast<size_t>(lua_tonumber(L, 2));
1127- if (size > MAX_TEXTURE_PALETTE_SIZE)
1128- return luaL_error(L, "size: Its really big");
1129-
1130- lua_texture blank = { UNONE, 0 };
1131- lua_texture_palette.resize(size, blank);
1132- if (lua_texture_palette_selected >= lua_texture_palette.size())
1133- lua_texture_palette_selected = -1;
1134-
1135- draw_panels();
1136- return 0;
1137-}
1138-
1139-const luaL_reg Lua_Texture_Palette_Set[] = {
1140- {"highlight", Lua_Texture_Palette_Set_Selected},
1141- {"size", Lua_Texture_Palette_Set_Size},
1142- {0, 0}
1143-};
1144-
1145-char Lua_WeaponType_Name[] = "weapon_type";
1146-typedef L_Enum<Lua_WeaponType_Name> Lua_WeaponType;
1147-
1148-char Lua_WeaponTypes_Name[] = "WeaponTypes";
1149-typedef L_EnumContainer<Lua_WeaponTypes_Name, Lua_WeaponType> Lua_WeaponTypes;
1150-
1151-char Lua_Player_Weapon_Trigger_Name[] = "player_weapon_trigger";
1152-class Lua_Player_Weapon_Trigger : public PlayerSubtable<Lua_Player_Weapon_Trigger_Name>
1153-{
1154-public:
1155- int16 m_weapon_index;
1156-
1157- static Lua_Player_Weapon_Trigger *Push(lua_State *L, int16 player_index, int16 weapon_index, int16 index);
1158- static int16 WeaponIndex(lua_State *L, int index);
1159-};
1160-
1161-Lua_Player_Weapon_Trigger *Lua_Player_Weapon_Trigger::Push(lua_State *L, int16 player_index, int16 weapon_index, int16 index)
1162-{
1163- Lua_Player_Weapon_Trigger *t = static_cast<Lua_Player_Weapon_Trigger *>(PlayerSubtable<Lua_Player_Weapon_Trigger_Name>::Push(L, player_index, index));
1164- if (t)
1165- {
1166- t->m_weapon_index = weapon_index;
1167- }
1168-
1169- return t;
1170-}
1171-
1172-int16 Lua_Player_Weapon_Trigger::WeaponIndex(lua_State *L, int index)
1173-{
1174- Lua_Player_Weapon_Trigger *t = static_cast<Lua_Player_Weapon_Trigger*>(lua_touserdata(L, index));
1175- if (!t) luaL_typerror(L, index, Lua_Player_Weapon_Trigger_Name);
1176- return t->m_weapon_index;
1177-}
1178-
1179-static int Lua_Player_Weapon_Trigger_Get_Rounds(lua_State *L)
1180-{
1181- short rounds = get_player_weapon_ammo_count(
1182- Lua_Player_Weapon_Trigger::PlayerIndex(L, 1),
1183- Lua_Player_Weapon_Trigger::WeaponIndex(L, 1),
1184- Lua_Player_Weapon_Trigger::Index(L, 1));
1185- lua_pushnumber(L, rounds);
1186- return 1;
1187-}
1188-
1189-const luaL_reg Lua_Player_Weapon_Trigger_Get[] = {
1190- {"rounds", Lua_Player_Weapon_Trigger_Get_Rounds},
1191- {0, 0}
1192-};
1193-
1194-char Lua_Player_Weapon_Name[] = "player_weapon";
1195-typedef PlayerSubtable<Lua_Player_Weapon_Name> Lua_Player_Weapon;
1196-
1197-template<int trigger>
1198-static int get_weapon_trigger(lua_State *L)
1199-{
1200- Lua_Player_Weapon_Trigger::Push(L, Lua_Player_Weapon::PlayerIndex(L, 1), Lua_Player_Weapon::Index(L, 1), trigger);
1201- return 1;
1202-}
1203-
1204-static int Lua_Player_Weapon_Get_Type(lua_State *L)
1205-{
1206- Lua_WeaponType::Push(L, Lua_Player_Weapon::Index(L, 1));
1207- return 1;
1208-}
1209-
1210-extern bool ready_weapon(short player_index, short weapon_index);
1211-
1212-int Lua_Player_Weapon_Select(lua_State *L)
1213-{
1214- ready_weapon(Lua_Player_Weapon::PlayerIndex(L, 1), Lua_Player_Weapon::Index(L, 1));
1215- return 0;
1216-}
1217-
1218-const luaL_reg Lua_Player_Weapon_Get[] = {
1219- {"primary", get_weapon_trigger<_primary_weapon>},
1220- {"secondary", get_weapon_trigger<_secondary_weapon>},
1221- {"select", L_TableFunction<Lua_Player_Weapon_Select>},
1222- {"type", Lua_Player_Weapon_Get_Type},
1223- {0, 0}
1224-};
1225-
1226-extern player_weapon_data *get_player_weapon_data(const short player_index);
1227-extern bool player_has_valid_weapon(short player_index);
1228-
1229-char Lua_Player_Weapons_Name[] = "player_weapons";
1230-typedef L_Class<Lua_Player_Weapons_Name> Lua_Player_Weapons;
1231-
1232-extern bool can_wield_weapons[MAXIMUM_NUMBER_OF_NETWORK_PLAYERS];
1233-
1234-static int Lua_Player_Weapons_Get(lua_State *L)
1235-{
1236- int player_index = Lua_Player_Weapons::Index(L, 1);
1237- bool string_arg = lua_isstring(L, 2) && !lua_isnumber(L, 2);
1238- if (string_arg && (strcmp(lua_tostring(L, 2), "current") == 0))
1239- {
1240- if (player_has_valid_weapon(player_index))
1241- {
1242- player_weapon_data *weapon_data = get_player_weapon_data(player_index);
1243- Lua_Player_Weapon::Push(L, player_index, weapon_data->current_weapon);
1244- }
1245- else
1246- {
1247- lua_pushnil(L);
1248- }
1249- }
1250- else if (string_arg && (strcmp(lua_tostring(L, 2), "desired") == 0))
1251- {
1252- player_weapon_data *weapon_data = get_player_weapon_data(player_index);
1253- if (weapon_data->desired_weapon != NONE)
1254- {
1255- Lua_Player_Weapon::Push(L, player_index, weapon_data->desired_weapon);
1256- }
1257- else
1258- {
1259- lua_pushnil(L);
1260- }
1261- }
1262- else if (string_arg && (strcmp(lua_tostring(L, 2), "active") == 0))
1263- {
1264- lua_pushboolean(L, can_wield_weapons[player_index]);
1265- }
1266- else
1267- {
1268- int index = Lua_WeaponType::ToIndex(L, 2);
1269- Lua_Player_Weapon::Push(L, player_index, index);
1270- }
1271-
1272- return 1;
1273-}
1274-
1275-static int Lua_Player_Weapons_Length(lua_State *L)
1276-{
1277- lua_pushnumber(L, MAXIMUM_NUMBER_OF_WEAPONS);
1278- return 1;
1279-}
1280-
1281-static int Lua_Player_Weapons_Set(lua_State *L)
1282-{
1283- if (lua_isstring(L, 2) && strcmp(lua_tostring(L, 2), "active") == 0)
1284- {
1285- if (!lua_isboolean(L, 3))
1286- return luaL_error(L, "can_wield: incorrect argument type");
1287- can_wield_weapons[Lua_Player_Weapons::Index(L, 1)] = lua_toboolean(L, 3);
1288- return 0;
1289- }
1290- else
1291- return luaL_error(L, "no such index");
1292-}
1293-
1294-const luaL_reg Lua_Player_Weapons_Metatable[] = {
1295- {"__index", Lua_Player_Weapons_Get},
1296- {"__newindex", Lua_Player_Weapons_Set},
1297- {"__len", Lua_Player_Weapons_Length},
1298- {0, 0}
1299-};
1300-
1301-char Lua_Player_Kills_Name[] = "player_kills";
1302-typedef L_Class<Lua_Player_Kills_Name> Lua_Player_Kills;
1303-
1304-static int Lua_Player_Kills_Get(lua_State *L)
1305-{
1306- int player_index = Lua_Player_Kills::Index(L, 1);
1307- int slain_player_index = Lua_Player::Index(L, 2);
1308-
1309- player_data *slain_player = get_player_data(slain_player_index);
1310-
1311- lua_pushnumber(L, slain_player->damage_taken[player_index].kills);
1312- return 1;
1313-}
1314-
1315-static int Lua_Player_Kills_Length(lua_State *L)
1316-{
1317- lua_pushnumber(L, dynamic_world->player_count);
1318- return 1;
1319-}
1320-
1321-static int Lua_Player_Kills_Set(lua_State *L)
1322-{
1323- if (!lua_isnumber(L, 3))
1324- return luaL_error(L, "kills: incorrect argument type");
1325-
1326- int player_index = Lua_Player_Kills::Index(L, 1);
1327- int slain_player_index = Lua_Player::Index(L, 2);
1328- int kills = static_cast<int>(lua_tonumber(L, 3));
1329-
1330- player_data *player = get_player_data(player_index);
1331- player_data *slain_player = get_player_data(slain_player_index);
1332-
1333- int kills_award = kills - slain_player->damage_taken[player_index].kills;
1334- if (kills_award)
1335- {
1336- slain_player->damage_taken[player_index].kills += kills_award;
1337- team_damage_taken[slain_player->team].kills += kills_award;
1338-
1339- if (player_index != slain_player_index)
1340- {
1341- player->total_damage_given.kills += kills_award;
1342- team_damage_given[player->team].kills += kills_award;
1343- }
1344- if (slain_player->team == player->team)
1345- {
1346- team_friendly_fire[slain_player->team].kills += kills_award;
1347- }
1348- mark_player_network_stats_as_dirty(current_player_index);
1349- }
1350- return 0;
1351-}
1352-
1353-const luaL_reg Lua_Player_Kills_Metatable[] = {
1354- {"__index", Lua_Player_Kills_Get},
1355- {"__newindex", Lua_Player_Kills_Set},
1356- {"__len", Lua_Player_Kills_Length},
1357- {0, 0}
1358-};
1359-
1360-char Lua_PlayerColor_Name[] = "player_color";
1361-
1362-char Lua_PlayerColors_Name[] = "PlayerColors";
1363-
1364-char Lua_Player_Name[] = "player";
1365-
1366-// methods
1367-
1368-// accelerate(direction, velocity, vertical_velocity)
1369-int Lua_Player_Accelerate(lua_State *L)
1370-{
1371- if (!lua_isnumber(L, 2) || !lua_isnumber(L, 3) || !lua_isnumber(L, 4))
1372- return luaL_error(L, "accelerate: incorrect argument type");
1373-
1374- player_data *player = get_player_data(Lua_Player::Index(L, 1));
1375- double direction = static_cast<double>(lua_tonumber(L, 2));
1376- double velocity = static_cast<double>(lua_tonumber(L, 3));
1377- double vertical_velocity = static_cast<double>(lua_tonumber(L, 4));
1378-
1379- accelerate_player(player->monster_index, static_cast<int>(vertical_velocity * WORLD_ONE), static_cast<int>(direction/AngleConvert), static_cast<int>(velocity * WORLD_ONE));
1380- return 0;
1381-}
1382-
1383-int Lua_Player_Activate_Terminal(lua_State *L)
1384-{
1385- int16 text_index = NONE;
1386- if (lua_isnumber(L, 2))
1387- text_index = static_cast<int16>(lua_tonumber(L, 2));
1388- else if (Lua_Terminal::Is(L, 2))
1389- text_index = Lua_Terminal::Index(L, 2);
1390- else
1391- return luaL_error(L, "activate_terminal: invalid terminal index");
1392-
1393- enter_computer_interface(Lua_Player::Index(L, 1), text_index, calculate_level_completion_state());
1394- return 0;
1395-}
1396-
1397-int Lua_Player_Find_Action_Key_Target(lua_State *L)
1398-{
1399- // no arguments
1400- short target_type;
1401- short object_index = find_action_key_target(Lua_Player::Index(L, 1), MAXIMUM_ACTIVATION_RANGE, &target_type);
1402-
1403- if (object_index != NONE)
1404- {
1405- switch (target_type)
1406- {
1407- case _target_is_platform:
1408- Lua_Platform::Push(L, object_index);
1409- break;
1410-
1411- case _target_is_control_panel:
1412- Lua_Side::Push(L, object_index);
1413- break;
1414-
1415- default:
1416- lua_pushnil(L);
1417- break;
1418- }
1419- }
1420- else
1421- {
1422- lua_pushnil(L);
1423- }
1424-
1425- return 1;
1426-}
1427-
1428-extern projectile_definition *get_projectile_definition(short type);
1429-
1430-int Lua_Player_Find_Target(lua_State *L)
1431-{
1432- // find the origin of projectiles (don't move left/right)
1433- player_data *player = get_player_data(Lua_Player::Index(L, 1));
1434- world_point3d origin = player->camera_location;
1435- world_point3d destination = origin;
1436-
1437- translate_point3d(&destination, WORLD_ONE, player->facing, player->elevation);
1438- short old_polygon = get_object_data(player->object_index)->polygon;
1439- short new_polygon;
1440- short obstruction_index;
1441- short line_index;
1442-
1443- projectile_definition *definition = get_projectile_definition(0);
1444- bool was_pass_transparent = definition->flags & _usually_pass_transparent_side;
1445- if (!was_pass_transparent)
1446- definition->flags |= _usually_pass_transparent_side;
1447-
1448- // preflight a projectile, 1 WU at a time (because of projectile speed bug)
1449- uint16 flags = translate_projectile(0, &origin, old_polygon, &destination, &new_polygon, player->monster_index, &obstruction_index, &line_index, true);
1450-
1451- while (!(flags & _projectile_hit))
1452- {
1453- origin = destination;
1454- old_polygon = new_polygon;
1455-
1456- translate_point3d(&destination, WORLD_ONE, player->facing, player->elevation);
1457- flags = translate_projectile(0, &origin, old_polygon, &destination, &new_polygon, player->monster_index, &obstruction_index, &line_index, true);
1458- }
1459-
1460- if (!was_pass_transparent)
1461- definition->flags &= ~_usually_pass_transparent_side;
1462-
1463- if (flags & _projectile_hit_monster)
1464- {
1465- object_data *object = get_object_data(obstruction_index);
1466- Lua_Monster::Push(L, object->permutation);
1467- }
1468- else if (flags & _projectile_hit_floor)
1469- {
1470- Lua_Polygon_Floor::Push(L, new_polygon);
1471- }
1472- else if (flags & _projectile_hit_media)
1473- {
1474- Lua_Polygon::Push(L, new_polygon);
1475- }
1476- else if (flags & _projectile_hit_scenery)
1477- {
1478- Lua_Scenery::Push(L, obstruction_index);
1479- }
1480- else if (obstruction_index != NONE)
1481- {
1482- Lua_Polygon_Ceiling::Push(L, new_polygon);
1483- }
1484- else
1485- {
1486- short side_index = find_adjacent_side(new_polygon, line_index);
1487- Lua_Side::Push(L, side_index);
1488- }
1489-
1490- lua_pushnumber(L, (double) destination.x / WORLD_ONE);
1491- lua_pushnumber(L, (double) destination.y / WORLD_ONE);
1492- lua_pushnumber(L, (double) destination.z / WORLD_ONE);
1493- Lua_Polygon::Push(L, new_polygon);
1494-
1495- return 5;
1496-}
1497-
1498-
1499-int Lua_Player_Damage(lua_State *L)
1500-{
1501- int args = lua_gettop(L);
1502- if (!lua_isnumber(L, 2))
1503- return luaL_error(L, "damage: incorrect argument type");
1504-
1505- player_data *player = get_player_data(Lua_Player::Index(L, 1));
1506- if (PLAYER_IS_DEAD(player) || PLAYER_IS_TOTALLY_DEAD(player))
1507- return 0;
1508-
1509- damage_definition damage;
1510- damage.type = _damage_crushing;
1511- damage.base = static_cast<int>(lua_tonumber(L, 2));
1512- damage.random = 0;
1513- damage.scale = FIXED_ONE;
1514-
1515- if (args > 2)
1516- {
1517- damage.type = Lua_DamageType::ToIndex(L, 3);
1518- }
1519-
1520- damage_player(player->monster_index, NONE, NONE, &damage, NONE);
1521- return 0;
1522-}
1523-
1524-int Lua_Player_Fade_Screen(lua_State *L)
1525-{
1526- short player_index = Lua_Player::Index(L, 1);
1527- if (player_index == local_player_index)
1528- {
1529- int fade_index = Lua_FadeType::ToIndex(L, 2);
1530- start_fade(fade_index);
1531- }
1532- return 0;
1533-}
1534-
1535-int Lua_Player_Play_Sound(lua_State *L)
1536-{
1537- int args = lua_gettop(L);
1538-
1539- int player_index = Lua_Player::Index(L, 1);
1540- int sound_index = Lua_Sound::ToIndex(L, 2);
1541- float pitch = 1.0;
1542- if (args > 2)
1543- {
1544- if (lua_isnumber(L, 3))
1545- pitch = static_cast<float>(lua_tonumber(L, 3));
1546- else
1547- return luaL_error(L, "play_sound: incorrect argument type");
1548- }
1549-
1550- if (local_player_index != player_index)
1551- return 0;
1552-
1553- SoundManager::instance()->PlaySound(sound_index, NULL, NONE, _fixed(FIXED_ONE * pitch));
1554- return 0;
1555-}
1556-
1557-extern bool mute_lua;
1558-
1559-int Lua_Player_Print(lua_State *L)
1560-{
1561- if (mute_lua) return 0;
1562-
1563- if (lua_gettop(L) != 2)
1564- return luaL_error(L, "print: incorrect argument type");
1565-
1566- int player_index = Lua_Player::Index(L, 1);
1567- if (local_player_index == player_index)
1568- {
1569- lua_getglobal(L, "tostring");
1570- lua_insert(L, -2);
1571- lua_pcall(L, 1, 1, 0);
1572- if (lua_tostring(L, -1))
1573- {
1574- screen_printf("%s", lua_tostring(L, -1));
1575- }
1576- lua_pop(L, 1);
1577- }
1578-
1579- return 0;
1580-}
1581-
1582-extern struct physics_constants *get_physics_constants_for_model(short physics_model, uint32 action_flags);
1583-extern void instantiate_physics_variables(struct physics_constants *constants, struct physics_variables *variables, short player_index, bool first_time, bool take_action);
1584-
1585-int Lua_Player_Position(lua_State *L)
1586-{
1587- if (!lua_isnumber(L, 2) || !lua_isnumber(L, 3) || !lua_isnumber(L, 4))
1588- return luaL_error(L, ("position: incorrect argument type"));
1589-
1590- int polygon_index = 0;
1591- if (lua_isnumber(L, 5))
1592- {
1593- polygon_index = static_cast<int>(lua_tonumber(L, 5));
1594- if (!Lua_Polygon::Valid(polygon_index))
1595- return luaL_error(L, ("position: invalid polygon index"));
1596- }
1597- else if (Lua_Polygon::Is(L, 5))
1598- {
1599- polygon_index = Lua_Polygon::Index(L, 5);
1600- }
1601- else
1602- return luaL_error(L, ("position: incorrect argument type"));
1603-
1604- int player_index = Lua_Player::Index(L, 1);
1605- player_data *player = get_player_data(player_index);
1606- object_data *object = get_object_data(player->object_index);
1607-
1608- world_point3d location;
1609- location.x = static_cast<int>(lua_tonumber(L, 2) * WORLD_ONE);
1610- location.y = static_cast<int>(lua_tonumber(L, 3) * WORLD_ONE);
1611- location.z = static_cast<int>(lua_tonumber(L, 4) * WORLD_ONE);
1612-
1613- translate_map_object(player->object_index, &location, polygon_index);
1614- player->variables.position.x = WORLD_TO_FIXED(object->location.x);
1615- player->variables.position.y = WORLD_TO_FIXED(object->location.y);
1616- player->variables.position.z = WORLD_TO_FIXED(object->location.z);
1617-
1618- instantiate_physics_variables(get_physics_constants_for_model(static_world->physics_model, 0), &player->variables, player_index, false, false);
1619- return 0;
1620-}
1621-
1622-int Lua_Player_Teleport(lua_State *L)
1623-{
1624- if (!lua_isnumber(L, 2) && !Lua_Polygon::Is(L, 2))
1625- return luaL_error(L, "teleport(): incorrect argument type");
1626-
1627- int destination = -1;
1628- if (lua_isnumber(L, 2))
1629- destination = static_cast<int>(lua_tonumber(L, 2));
1630- else
1631- destination = Lua_Polygon::Index(L, 2);
1632-
1633- int player_index = Lua_Player::Index(L, 1);
1634-
1635- player_data *player = get_player_data(player_index);
1636- monster_data *monster = get_monster_data(player->monster_index);
1637-
1638- SET_PLAYER_TELEPORTING_STATUS(player, true);
1639- monster->action = _monster_is_teleporting;
1640- player->teleporting_phase = 0;
1641- player->delay_before_teleport = 0;
1642-
1643- player->teleporting_destination = destination;
1644- if (local_player_index == player_index)
1645- start_teleporting_effect(true);
1646- play_object_sound(player->object_index, Sound_TeleportOut());
1647- return 0;
1648-}
1649-
1650-int Lua_Player_Teleport_To_Level(lua_State *L)
1651-{
1652- if (!lua_isnumber(L, 2))
1653- return luaL_error(L, "teleport_to_level(): incorrect argument type");
1654-
1655- int level = static_cast<int>(lua_tonumber(L, 2));
1656- int player_index = Lua_Player::Index(L, 1);
1657-
1658- player_data *player = get_player_data(player_index);
1659- monster_data *monster = get_monster_data(player->monster_index);
1660-
1661- SET_PLAYER_TELEPORTING_STATUS(player, true);
1662- monster->action = _monster_is_teleporting;
1663- player->teleporting_phase = 0;
1664- player->delay_before_teleport = 0;
1665-
1666- player->teleporting_destination = -level - 1;
1667- if (View_DoInterlevelTeleportOutEffects()) {
1668- start_teleporting_effect(true);
1669- play_object_sound(player->object_index, Sound_TeleportOut());
1670- }
1671- return 0;
1672-}
1673-
1674-extern short current_player_index;
1675-
1676-int Lua_Player_View_Player(lua_State *L)
1677-{
1678- int player_index = Lua_Player::Index(L, 1);
1679- if (player_index != local_player_index)
1680- return 0;
1681-
1682- int view_player_index;
1683- if (lua_isnumber(L, 2))
1684- {
1685- view_player_index = static_cast<int>(lua_tonumber(L, 2));
1686- if (view_player_index < 0 || view_player_index >= dynamic_world->player_count)
1687- return luaL_error(L, "view_player(): invalid player index");
1688- }
1689- else if (Lua_Player::Is(L, 2))
1690- view_player_index = Lua_Player::Index(L, 2);
1691- else
1692- return luaL_error(L, "view_player(): incorrect argument type");
1693-
1694- if (view_player_index != current_player_index)
1695- {
1696- set_current_player_index(view_player_index);
1697- update_interface(NONE);
1698- dirty_terminal_view(player_index);
1699- }
1700-
1701- return 0;
1702-
1703-}
1704-
1705-// get accessors
1706-
1707-static int Lua_Player_Get_Action_Flags(lua_State *L)
1708-{
1709- Lua_Action_Flags::Push(L, Lua_Player::Index(L, 1));
1710- return 1;
1711-}
1712-
1713-static int Lua_Player_Get_Color(lua_State *L)
1714-{
1715- Lua_PlayerColor::Push(L, get_player_data(Lua_Player::Index(L, 1))->color);
1716- return 1;
1717-}
1718-
1719-static int Lua_Player_Get_Compass(lua_State *L)
1720-{
1721- Lua_Player_Compass::Push(L, Lua_Player::Index(L, 1));
1722- return 1;
1723-}
1724-
1725-static int Lua_Player_Get_Crosshairs(lua_State *L)
1726-{
1727- Lua_Crosshairs::Push(L, Lua_Player::Index(L, 1));
1728- return 1;
1729-}
1730-
1731-static int Lua_Player_Get_Dead(lua_State *L)
1732-{
1733- player_data *player = get_player_data(Lua_Player::Index(L, 1));
1734- lua_pushboolean(L, (PLAYER_IS_DEAD(player) || PLAYER_IS_TOTALLY_DEAD(player)));
1735- return 1;
1736-}
1737-
1738-static int Lua_Player_Get_Deaths(lua_State *L)
1739-{
1740- player_data *player = get_player_data(Lua_Player::Index(L, 1));
1741- lua_pushnumber(L, player->monster_damage_taken.kills);
1742- return 1;
1743-}
1744-
1745-static int Lua_Player_Get_Energy(lua_State *L)
1746-{
1747- lua_pushnumber(L, get_player_data(Lua_Player::Index(L, 1))->suit_energy);
1748- return 1;
1749-}
1750-
1751-static int Lua_Player_Get_Elevation(lua_State *L)
1752-{
1753- double angle = FIXED_INTEGERAL_PART(get_player_data(Lua_Player::Index(L, 1))->variables.elevation) * AngleConvert;
1754- lua_pushnumber(L, angle);
1755- return 1;
1756-}
1757-
1758-static int Lua_Player_Get_Direction(lua_State *L)
1759-{
1760- double angle = FIXED_INTEGERAL_PART(get_player_data(Lua_Player::Index(L, 1))->variables.direction) * AngleConvert;
1761- lua_pushnumber(L, angle);
1762- return 1;
1763-}
1764-
1765-static int Lua_Player_Get_External_Velocity(lua_State *L)
1766-{
1767- Lua_ExternalVelocity::Push(L, Lua_Player::Index(L, 1));
1768- return 1;
1769-}
1770-
1771-static int Lua_Player_Get_Extravision_Duration(lua_State *L)
1772-{
1773- lua_pushnumber(L, get_player_data(Lua_Player::Index(L, 1))->extravision_duration);
1774- return 1;
1775-}
1776-
1777-template<uint16 flag>
1778-static int Lua_Player_Get_Flag(lua_State *L)
1779-{
1780- player_data *player = get_player_data(Lua_Player::Index(L, 1));
1781- lua_pushboolean(L, player->variables.flags & flag);
1782- return 1;
1783-}
1784-
1785-static int Lua_Player_Get_Infravision_Duration(lua_State *L)
1786-{
1787- lua_pushnumber(L, get_player_data(Lua_Player::Index(L, 1))->infravision_duration);
1788- return 1;
1789-}
1790-
1791-static int Lua_Player_Get_Internal_Velocity(lua_State *L)
1792-{
1793- Lua_InternalVelocity::Push(L, Lua_Player::Index(L, 1));
1794- return 1;
1795-}
1796-
1797-static int Lua_Player_Get_Invincibility_Duration(lua_State *L)
1798-{
1799- lua_pushnumber(L, get_player_data(Lua_Player::Index(L, 1))->invincibility_duration);
1800- return 1;
1801-}
1802-
1803-static int Lua_Player_Get_Invisibility_Duration(lua_State *L)
1804-{
1805- lua_pushnumber(L, get_player_data(Lua_Player::Index(L, 1))->invisibility_duration);
1806- return 1;
1807-}
1808-
1809-static int Lua_Player_Get_Items(lua_State *L)
1810-{
1811- Lua_Player_Items::Push(L, Lua_Player::Index(L, 1));
1812- return 1;
1813-}
1814-
1815-static int Lua_Player_Get_Kills(lua_State *L)
1816-{
1817- Lua_Player_Kills::Push(L, Lua_Player::Index(L, 1));
1818- return 1;
1819-}
1820-
1821-static int Lua_Player_Get_Local(lua_State *L)
1822-{
1823- lua_pushboolean(L, Lua_Player::Index(L, 1) == local_player_index);
1824- return 1;
1825-}
1826-
1827-extern bool MotionSensorActive;
1828-
1829-static int Lua_Player_Get_Motion_Sensor(lua_State *L)
1830-{
1831- short player_index = Lua_Player::Index(L, 1);
1832- if (player_index == local_player_index)
1833- {
1834- lua_pushboolean(L, MotionSensorActive);
1835- return 1;
1836- }
1837- else
1838- {
1839- return 0;
1840- }
1841-}
1842-
1843-static int Lua_Player_Get_Monster(lua_State *L)
1844-{
1845- Lua_Monster::Push(L, get_player_data(Lua_Player::Index(L, 1))->monster_index);
1846- return 1;
1847-}
1848-
1849-static int Lua_Player_Get_Name(lua_State *L)
1850-{
1851- lua_pushstring(L, get_player_data(Lua_Player::Index(L, 1))->name);
1852- return 1;
1853-}
1854-
1855-static int Lua_Player_Get_Netdead(lua_State *L)
1856-{
1857- lua_pushboolean(L, get_player_data(Lua_Player::Index(L, 1))->netdead);
1858- return 1;
1859-}
1860-
1861-static int Lua_Player_Get_Overlays(lua_State *L)
1862-{
1863- Lua_Overlays::Push(L, Lua_Player::Index(L, 1));
1864- return 1;
1865-}
1866-
1867-static int Lua_Player_Get_Oxygen(lua_State *L)
1868-{
1869- lua_pushnumber(L, get_player_data(Lua_Player::Index(L, 1))->suit_oxygen);
1870- return 1;
1871-}
1872-
1873-static int Lua_Player_Get_Points(lua_State *L)
1874-{
1875- lua_pushnumber(L, get_player_data(Lua_Player::Index(L, 1))->netgame_parameters[0]);
1876- return 1;
1877-}
1878-
1879-static int Lua_Player_Get_Polygon(lua_State *L)
1880-{
1881- Lua_Polygon::Push(L, get_player_data(Lua_Player::Index(L, 1))->supporting_polygon_index);
1882- return 1;
1883-}
1884-
1885-static int Lua_Player_Get_Team(lua_State *L)
1886-{
1887- Lua_PlayerColor::Push(L, get_player_data(Lua_Player::Index(L, 1))->team);
1888- return 1;
1889-}
1890-
1891-static int Lua_Player_Get_Texture_Palette(lua_State *L)
1892-{
1893- Lua_Texture_Palette::Push(L, Lua_Player::Index(L, 1));
1894- return 1;
1895-}
1896-
1897-static int Lua_Player_Get_Weapons(lua_State *L)
1898-{
1899- Lua_Player_Weapons::Push(L, Lua_Player::Index(L, 1));
1900- return 1;
1901-}
1902-
1903-static int Lua_Player_Get_X(lua_State *L)
1904-{
1905- lua_pushnumber(L, (double) get_player_data(Lua_Player::Index(L, 1))->location.x / WORLD_ONE);
1906- return 1;
1907-}
1908-
1909-static int Lua_Player_Get_Y(lua_State *L)
1910-{
1911- lua_pushnumber(L, (double) get_player_data(Lua_Player::Index(L, 1))->location.y / WORLD_ONE);
1912- return 1;
1913-}
1914-
1915-static int Lua_Player_Get_Z(lua_State *L)
1916-{
1917- lua_pushnumber(L, (double) get_player_data(Lua_Player::Index(L, 1))->location.z / WORLD_ONE);
1918- return 1;
1919-}
1920-
1921-static int Lua_Player_Get_Zoom(lua_State *L)
1922-{
1923- short player_index = Lua_Player::Index(L, 1);
1924- if (player_index == local_player_index)
1925- {
1926- lua_pushboolean(L, GetTunnelVision());
1927- return 1;
1928- }
1929- else
1930- {
1931- return 0;
1932- }
1933-}
1934-
1935-const luaL_reg Lua_Player_Get[] = {
1936- {"accelerate", L_TableFunction<Lua_Player_Accelerate>},
1937- {"action_flags", Lua_Player_Get_Action_Flags},
1938- {"activate_terminal", L_TableFunction<Lua_Player_Activate_Terminal>},
1939- {"color", Lua_Player_Get_Color},
1940- {"compass", Lua_Player_Get_Compass},
1941- {"crosshairs", Lua_Player_Get_Crosshairs},
1942- {"damage", L_TableFunction<Lua_Player_Damage>},
1943- {"dead", Lua_Player_Get_Dead},
1944- {"deaths", Lua_Player_Get_Deaths},
1945- {"direction", Lua_Player_Get_Direction},
1946- {"disconnected", Lua_Player_Get_Netdead},
1947- {"energy", Lua_Player_Get_Energy},
1948- {"elevation", Lua_Player_Get_Elevation},
1949- {"external_velocity", Lua_Player_Get_External_Velocity},
1950- {"extravision_duration", Lua_Player_Get_Extravision_Duration},
1951- {"feet_below_media", Lua_Player_Get_Flag<_FEET_BELOW_MEDIA_BIT>},
1952- {"fade_screen", L_TableFunction<Lua_Player_Fade_Screen>},
1953- {"find_action_key_target", L_TableFunction<Lua_Player_Find_Action_Key_Target>},
1954- {"find_target", L_TableFunction<Lua_Player_Find_Target>},
1955- {"head_below_media", Lua_Player_Get_Flag<_HEAD_BELOW_MEDIA_BIT>},
1956- {"infravision_duration", Lua_Player_Get_Infravision_Duration},
1957- {"internal_velocity", Lua_Player_Get_Internal_Velocity},
1958- {"invincibility_duration", Lua_Player_Get_Invincibility_Duration},
1959- {"invisibility_duration", Lua_Player_Get_Invisibility_Duration},
1960- {"items", Lua_Player_Get_Items},
1961- {"local_", Lua_Player_Get_Local},
1962- {"juice", Lua_Player_Get_Energy},
1963- {"kills", Lua_Player_Get_Kills},
1964- {"life", Lua_Player_Get_Energy},
1965- {"monster", Lua_Player_Get_Monster},
1966- {"motion_sensor_active", Lua_Player_Get_Motion_Sensor},
1967- {"name", Lua_Player_Get_Name},
1968- {"overlays", Lua_Player_Get_Overlays},
1969- {"oxygen", Lua_Player_Get_Oxygen},
1970- {"pitch", Lua_Player_Get_Elevation},
1971- {"print", L_TableFunction<Lua_Player_Print>},
1972- {"play_sound", L_TableFunction<Lua_Player_Play_Sound>},
1973- {"points", Lua_Player_Get_Points},
1974- {"polygon", Lua_Player_Get_Polygon},
1975- {"position", L_TableFunction<Lua_Player_Position>},
1976- {"team", Lua_Player_Get_Team},
1977- {"teleport", L_TableFunction<Lua_Player_Teleport>},
1978- {"teleport_to_level", L_TableFunction<Lua_Player_Teleport_To_Level>},
1979- {"texture_palette", Lua_Player_Get_Texture_Palette},
1980- {"view_player", L_TableFunction<Lua_Player_View_Player>},
1981- {"weapons", Lua_Player_Get_Weapons},
1982- {"x", Lua_Player_Get_X},
1983- {"y", Lua_Player_Get_Y},
1984- {"yaw", Lua_Player_Get_Direction},
1985- {"z", Lua_Player_Get_Z},
1986- {"zoom_active", Lua_Player_Get_Zoom},
1987- {0, 0}
1988-};
1989-
1990-extern void mark_shield_display_as_dirty();
1991-
1992-static int Lua_Player_Set_Color(lua_State *L)
1993-{
1994- int color = Lua_PlayerColor::ToIndex(L, 2);
1995- get_player_data(Lua_Player::Index(L, 1))->color = color;
1996-
1997- return 0;
1998-}
1999-
2000-static int Lua_Player_Set_Deaths(lua_State *L)
2001-{
2002- if (!lua_isnumber(L, 2))
2003- return luaL_error(L, "deaths: incorrect argument type");
2004-
2005- player_data *player = get_player_data(Lua_Player::Index(L, 1));
2006- int kills = static_cast<int>(lua_tonumber(L, 2));
2007- if (player->monster_damage_taken.kills != kills)
2008- {
2009- team_monster_damage_taken[player->team].kills += (kills - player->monster_damage_taken.kills);
2010- player->monster_damage_taken.kills = kills;
2011- mark_player_network_stats_as_dirty(current_player_index);
2012- }
2013-
2014- return 0;
2015-}
2016-
2017-static int Lua_Player_Set_Direction(lua_State *L)
2018-{
2019- if (!lua_isnumber(L, 2))
2020- return luaL_error(L, "direction: incorrect argument type");
2021-
2022- double facing = static_cast<double>(lua_tonumber(L, 2));
2023- int player_index = Lua_Player::Index(L, 1);
2024- player_data *player = get_player_data(player_index);
2025- player->variables.direction = INTEGER_TO_FIXED((int)(facing/AngleConvert));
2026- instantiate_physics_variables(get_physics_constants_for_model(static_world->physics_model, 0), &player->variables, player_index, false, false);
2027- return 0;
2028-}
2029-
2030-static int Lua_Player_Set_Elevation(lua_State *L)
2031-{
2032- if (!lua_isnumber(L, 2))
2033- return luaL_error(L, "elevation: incorrect argument type");
2034-
2035- double elevation = static_cast<double>(lua_tonumber(L, 2));
2036- if (elevation > 180) elevation -= 360.0;
2037- int player_index = Lua_Player::Index(L, 1);
2038- player_data *player = get_player_data(player_index);
2039- player->variables.elevation = INTEGER_TO_FIXED((int)(elevation/AngleConvert));
2040- instantiate_physics_variables(get_physics_constants_for_model(static_world->physics_model, 0), &player->variables, player_index, false, false);
2041- return 0;
2042-}
2043-
2044-static int Lua_Player_Set_Infravision_Duration(lua_State *L)
2045-{
2046- if (!lua_isnumber(L, 2))
2047- return luaL_error(L, "extravision: incorrect argument type");
2048-
2049- player_data *player = get_player_data(Lua_Player::Index(L, 1));
2050- player->infravision_duration = static_cast<int>(lua_tonumber(L, 2));
2051- return 0;
2052-}
2053-
2054-static int Lua_Player_Set_Invincibility_Duration(lua_State *L)
2055-{
2056- if (!lua_isnumber(L, 2))
2057- return luaL_error(L, "extravision: incorrect argument type");
2058-
2059- player_data *player = get_player_data(Lua_Player::Index(L, 1));
2060- player->invincibility_duration = static_cast<int>(lua_tonumber(L, 2));
2061- return 0;
2062-}
2063-
2064-static int Lua_Player_Set_Invisibility_Duration(lua_State *L)
2065-{
2066- if (!lua_isnumber(L, 2))
2067- return luaL_error(L, "extravision: incorrect argument type");
2068-
2069- player_data *player = get_player_data(Lua_Player::Index(L, 1));
2070- player->invisibility_duration = static_cast<int>(lua_tonumber(L, 2));
2071- return 0;
2072-}
2073-
2074-static int Lua_Player_Set_Energy(lua_State *L)
2075-{
2076- if (!lua_isnumber(L, 2))
2077- return luaL_error(L, "energy: incorrect argument type");
2078-
2079- int energy = static_cast<int>(lua_tonumber(L, 2));
2080- if (energy > 3 * PLAYER_MAXIMUM_SUIT_ENERGY)
2081- energy = 3 * PLAYER_MAXIMUM_SUIT_ENERGY;
2082-
2083- get_player_data(Lua_Player::Index(L, 1))->suit_energy = energy;
2084- mark_shield_display_as_dirty();
2085-
2086- return 0;
2087-}
2088-
2089-static int Lua_Player_Set_Extravision_Duration(lua_State *L)
2090-{
2091- if (!lua_isnumber(L, 2))
2092- return luaL_error(L, "extravision: incorrect argument type");
2093-
2094- int player_index = Lua_Player::Index(L, 1);
2095- player_data *player = get_player_data(player_index);
2096- short extravision_duration = static_cast<short>(lua_tonumber(L, 2));
2097- if ((player_index == local_player_index) && (extravision_duration == 0) != (player->extravision_duration == 0))
2098- {
2099- start_extravision_effect(extravision_duration);
2100- }
2101- player->extravision_duration = static_cast<int>(lua_tonumber(L, 2));
2102- return 0;
2103-}
2104-
2105-static int Lua_Player_Set_Motion_Sensor(lua_State *L)
2106-{
2107- short player_index = Lua_Player::Index(L, 1);
2108- if (player_index == local_player_index)
2109- {
2110- if (!lua_isboolean(L, 2))
2111- return luaL_error(L, "motion_sensor: incorrect argument type");
2112- bool state = lua_toboolean(L, 2);
2113- if (MotionSensorActive != state)
2114- {
2115- MotionSensorActive = lua_toboolean(L, 2);
2116- draw_panels();
2117- }
2118- }
2119-
2120- return 0;
2121-}
2122-
2123-static int Lua_Player_Set_Oxygen(lua_State *L)
2124-{
2125- if (!lua_isnumber(L, 2))
2126- return luaL_error(L, "oxygen: incorrect argument type");
2127-
2128- int oxygen = static_cast<int>(lua_tonumber(L, 2));
2129- if (oxygen > PLAYER_MAXIMUM_SUIT_OXYGEN)
2130- oxygen = PLAYER_MAXIMUM_SUIT_OXYGEN;
2131-
2132- get_player_data(Lua_Player::Index(L, 1))->suit_oxygen = oxygen;
2133- mark_shield_display_as_dirty();
2134-
2135- return 0;
2136-}
2137-
2138-static int Lua_Player_Set_Points(lua_State *L)
2139-{
2140- if (!lua_isnumber(L, 2))
2141- return luaL_error(L, "points: incorrect argument type");
2142-
2143- int points = static_cast<int>(lua_tonumber(L, 2));
2144-
2145- player_data *player = get_player_data(Lua_Player::Index(L, 1));
2146- if (player->netgame_parameters[0] != points)
2147- {
2148-#if !defined(DISABLE_NETWORKING)
2149- team_netgame_parameters[player->team][0] += points - player->netgame_parameters[0];
2150-#endif
2151- player->netgame_parameters[0] = points;
2152- mark_player_network_stats_as_dirty(current_player_index);
2153- }
2154-
2155- return 0;
2156-}
2157-
2158-static int Lua_Player_Set_Team(lua_State *L)
2159-{
2160- int team = Lua_PlayerColor::ToIndex(L, 2);
2161- get_player_data(Lua_Player::Index(L, 1))->team = team;
2162-
2163- return 0;
2164-}
2165-
2166-static int Lua_Player_Set_Zoom(lua_State *L)
2167-{
2168- short player_index = Lua_Player::Index(L, 1);
2169- if (player_index == local_player_index)
2170- {
2171- if (!lua_isboolean(L, 2))
2172- return luaL_error(L, "zoom_active: incorrect argument type");
2173-
2174- SetTunnelVision(lua_toboolean(L, 2));
2175- }
2176-
2177- return 0;
2178-}
2179-
2180-const luaL_reg Lua_Player_Set[] = {
2181- {"color", Lua_Player_Set_Color},
2182- {"deaths", Lua_Player_Set_Deaths},
2183- {"direction", Lua_Player_Set_Direction},
2184- {"elevation", Lua_Player_Set_Elevation},
2185- {"energy", Lua_Player_Set_Energy},
2186- {"extravision_duration", Lua_Player_Set_Extravision_Duration},
2187- {"infravision_duration", Lua_Player_Set_Infravision_Duration},
2188- {"invincibility_duration", Lua_Player_Set_Invincibility_Duration},
2189- {"invisibility_duration", Lua_Player_Set_Invisibility_Duration},
2190- {"juice", Lua_Player_Set_Energy},
2191- {"life", Lua_Player_Set_Energy},
2192- {"motion_sensor_active", Lua_Player_Set_Motion_Sensor},
2193- {"oxygen", Lua_Player_Set_Oxygen},
2194- {"pitch", Lua_Player_Set_Elevation},
2195- {"points", Lua_Player_Set_Points},
2196- {"team", Lua_Player_Set_Team},
2197- {"yaw", Lua_Player_Set_Direction},
2198- {"zoom_active", Lua_Player_Set_Zoom},
2199- {0, 0}
2200-};
2201-
2202-bool Lua_Player_Valid(int16 index)
2203-{
2204- return index >= 0 && index < dynamic_world->player_count;
2205-}
2206-
2207-char Lua_Players_Name[] = "Players";
2208-
2209-int Lua_Players_Print(lua_State *L)
2210-{
2211- if (mute_lua) return 0;
2212-
2213- if (lua_gettop(L) != 1)
2214- return luaL_error(L, "print: incorrect argument type");
2215-
2216- lua_getglobal(L, "tostring");
2217- lua_insert(L, -2);
2218- lua_pcall(L, 1, 1, 0);
2219- if (lua_tostring(L, -1))
2220- {
2221- screen_printf("%s", lua_tostring(L, -1));
2222- }
2223- lua_pop(L, 1);
2224-
2225- return 0;
2226-}
2227-
2228-
2229-const luaL_reg Lua_Players_Methods[] = {
2230- {"print", Lua_Players_Print},
2231- {0, 0}
2232-};
2233-
2234-int16 Lua_Players_Length() {
2235- return dynamic_world->player_count;
2236-}
2237-
2238-char Lua_DifficultyType_Name[] = "difficulty_type";
2239-typedef L_Enum<Lua_DifficultyType_Name> Lua_DifficultyType;
2240-
2241-char Lua_DifficultyTypes_Name[] = "DifficultyTypes";
2242-typedef L_EnumContainer<Lua_DifficultyTypes_Name, Lua_DifficultyType> Lua_DifficultyTypes;
2243-
2244-char Lua_GameType_Name[] = "game_type";
2245-typedef L_Enum<Lua_GameType_Name> Lua_GameType;
2246-
2247-char Lua_GameTypes_Name[] = "GameTypes";
2248-typedef L_EnumContainer<Lua_GameTypes_Name, Lua_GameType> Lua_GameTypes;
2249-
2250-char Lua_Game_Name[] = "Game";
2251-typedef L_Class<Lua_Game_Name> Lua_Game;
2252-
2253-char Lua_ScoringMode_Name[] = "scoring_mode";
2254-typedef L_Enum<Lua_ScoringMode_Name> Lua_ScoringMode;
2255-
2256-char Lua_ScoringModes_Name[] = "ScoringModes";
2257-typedef L_Container<Lua_ScoringModes_Name, Lua_ScoringMode> Lua_ScoringModes;
2258-
2259-static int Lua_Game_Get_Difficulty(lua_State *L)
2260-{
2261- Lua_DifficultyType::Push(L, dynamic_world->game_information.difficulty_level);
2262- return 1;
2263-}
2264-
2265-static int Lua_Game_Get_Kill_Limit(lua_State *L)
2266-{
2267- lua_pushnumber(L, dynamic_world->game_information.kill_limit);
2268- return 1;
2269-}
2270-
2271-static int Lua_Game_Get_Monsters_Replenish(lua_State* L)
2272-{
2273- lua_pushboolean(L, dynamic_world->game_information.game_options & _monsters_replenish);
2274- return 1;
2275-}
2276-
2277-static int Lua_Game_Get_Proper_Item_Accounting(lua_State* L)
2278-{
2279- lua_pushboolean(L, L_Get_Proper_Item_Accounting(L));
2280- return 1;
2281-}
2282-
2283-static int Lua_Game_Get_Time_Remaining(lua_State* L)
2284-{
2285- if(dynamic_world->game_information.game_time_remaining > 999 * 30)
2286- lua_pushnil(L);
2287- else
2288- lua_pushnumber(L, dynamic_world->game_information.game_time_remaining);
2289- return 1;
2290-}
2291-
2292-static int Lua_Game_Get_Ticks(lua_State *L)
2293-{
2294- lua_pushnumber(L, dynamic_world->tick_count);
2295- return 1;
2296-}
2297-
2298-static int Lua_Game_Get_Type(lua_State *L)
2299-{
2300- Lua_GameType::Push(L, GET_GAME_TYPE());
2301- return 1;
2302-}
2303-
2304-extern int game_end_condition;
2305-extern int game_scoring_mode;
2306-
2307-static int Lua_Game_Get_Scoring_Mode(lua_State *L)
2308-{
2309- Lua_ScoringMode::Push(L, game_scoring_mode);
2310- return 1;
2311-}
2312-
2313-static int Lua_Game_Get_Version(lua_State *L)
2314-{
2315- lua_pushstring(L, A1_DATE_VERSION);
2316- return 1;
2317-}
2318-
2319-static int Lua_Game_Set_Proper_Item_Accounting(lua_State* L)
2320-{
2321- if (!lua_isboolean(L, 2))
2322- luaL_error(L, "proper_item_accounting: incorrect argument type");
2323- L_Set_Proper_Item_Accounting(L, lua_toboolean(L, 2));
2324- return 0;
2325-}
2326-
2327-static int Lua_Game_Set_Scoring_Mode(lua_State *L)
2328-{
2329- int mode = Lua_ScoringMode::ToIndex(L, 2);
2330- game_scoring_mode = mode;
2331- // TODO: set network stats to dirty
2332- return 0;
2333-}
2334-
2335-static int Lua_Game_Set_Monsters_Replenish(lua_State* L)
2336-{
2337- if (!lua_isboolean(L, 2))
2338- luaL_error(L, "monsters_replenish: incorrect argument type");
2339-
2340- bool replenish = lua_toboolean(L, 2);
2341- if (replenish)
2342- {
2343- dynamic_world->game_information.game_options |= _monsters_replenish;
2344- }
2345- else
2346- {
2347- dynamic_world->game_information.game_options &= ~_monsters_replenish;
2348- }
2349- return 0;
2350-}
2351-
2352-static int Lua_Game_Set_Over(lua_State *L)
2353-{
2354- if(lua_isnil(L, 2)) game_end_condition = _game_normal_end_condition;
2355- else game_end_condition = lua_toboolean(L, 2) ? _game_end_now_condition : _game_no_end_condition;
2356- return 0;
2357-}
2358-
2359-extern GM_Random lua_random_generator;
2360-
2361-int Lua_Game_Better_Random(lua_State *L)
2362-{
2363- if (lua_isnumber(L, 1))
2364- {
2365- lua_pushnumber(L, lua_random_generator.KISS() % static_cast<uint32>(lua_tonumber(L, 1)));
2366- }
2367- else
2368- {
2369- lua_pushnumber(L, lua_random_generator.KISS());
2370- }
2371- return 1;
2372-}
2373-
2374-int Lua_Game_Global_Random(lua_State *L)
2375-{
2376- if (lua_isnumber(L, 1))
2377- {
2378- lua_pushnumber(L, ::global_random() % static_cast<uint16>(lua_tonumber(L, 1)));
2379- }
2380- else
2381- {
2382- lua_pushnumber(L, ::global_random());
2383- }
2384- return 1;
2385-}
2386-
2387-int Lua_Game_Local_Random(lua_State *L)
2388-{
2389- if (lua_isnumber(L, 1))
2390- {
2391- lua_pushnumber(L, ::local_random() % static_cast<uint16>(lua_tonumber(L, 1)));
2392- }
2393- else
2394- {
2395- lua_pushnumber(L, ::local_random());
2396- }
2397- return 1;
2398-}
2399-
2400-int Lua_Game_Save(lua_State *L)
2401-{
2402- if (!game_is_networked)
2403- save_game();
2404-
2405- return 0;
2406-}
2407-
2408-extern int L_Restore_Passed(lua_State *);
2409-extern int L_Restore_Saved(lua_State *);
2410-
2411-const luaL_reg Lua_Game_Get[] = {
2412- {"difficulty", Lua_Game_Get_Difficulty},
2413- {"global_random", L_TableFunction<Lua_Game_Global_Random>},
2414- {"kill_limit", Lua_Game_Get_Kill_Limit},
2415- {"time_remaining", Lua_Game_Get_Time_Remaining},
2416- {"local_random", L_TableFunction<Lua_Game_Local_Random>},
2417- {"monsters_replenish", Lua_Game_Get_Monsters_Replenish},
2418- {"proper_item_accounting", Lua_Game_Get_Proper_Item_Accounting},
2419- {"random", L_TableFunction<Lua_Game_Better_Random>},
2420- {"restore_passed", L_TableFunction<L_Restore_Passed>},
2421- {"restore_saved", L_TableFunction<L_Restore_Saved>},
2422- {"ticks", Lua_Game_Get_Ticks},
2423- {"type", Lua_Game_Get_Type},
2424- {"save", L_TableFunction<Lua_Game_Save>},
2425- {"scoring_mode", Lua_Game_Get_Scoring_Mode},
2426- {"version", Lua_Game_Get_Version},
2427- {0, 0}
2428-};
2429-
2430-const luaL_reg Lua_Game_Set[] = {
2431- {"monsters_replenish", Lua_Game_Set_Monsters_Replenish},
2432- {"proper_item_accounting", Lua_Game_Set_Proper_Item_Accounting},
2433- {"scoring_mode", Lua_Game_Set_Scoring_Mode},
2434- {"over", Lua_Game_Set_Over},
2435- {0, 0}
2436-};
2437-
2438-char Lua_Music_Name[] = "Music";
2439-typedef L_Class<Lua_Music_Name> Lua_Music;
2440-
2441-int Lua_Music_Clear(lua_State *L)
2442-{
2443- Music::instance()->ClearLevelMusic();
2444- return 0;
2445-}
2446-
2447-int Lua_Music_Fade(lua_State *L)
2448-{
2449- int duration;
2450- if (!lua_isnumber(L, 1))
2451- duration = 1000;
2452- else
2453- duration = static_cast<int>(lua_tonumber(L, 1) * 1000);
2454- Music::instance()->FadeOut(duration);
2455- Music::instance()->ClearLevelMusic();
2456- return 0;
2457-}
2458-
2459-int Lua_Music_Play(lua_State *L)
2460-{
2461- bool restart_music;
2462- restart_music = !Music::instance()->IsLevelMusicActive() && !Music::instance()->Playing();
2463- for (int n = 1; n <= lua_gettop(L); n++)
2464- {
2465- if (!lua_isstring(L, n))
2466- return luaL_error(L, "play: invalid file specifier");
2467-
2468- std::string search_path = L_Get_Search_Path(L);
2469-
2470- FileSpecifier file;
2471- if (search_path.size())
2472- {
2473- if (!file.SetNameWithPath(lua_tostring(L, n), search_path))
2474- Music::instance()->PushBackLevelMusic(file);
2475- }
2476- else
2477- {
2478- if (file.SetNameWithPath(lua_tostring(L, n)))
2479- Music::instance()->PushBackLevelMusic(file);
2480- }
2481- }
2482-
2483- if (restart_music)
2484- Music::instance()->PreloadLevelMusic();
2485- return 0;
2486-}
2487-
2488-int Lua_Music_Stop(lua_State *L)
2489-{
2490- Music::instance()->ClearLevelMusic();
2491- Music::instance()->StopLevelMusic();
2492-
2493- return 0;
2494-}
2495-
2496-int Lua_Music_Valid(lua_State* L) {
2497- int top = lua_gettop(L);
2498- for(int n = 1; n <= top; n++) {
2499- if(!lua_isstring(L, n))
2500- return luaL_error(L, "valid: invalid file specifier");
2501- FileSpecifier path;
2502- if(path.SetNameWithPath(lua_tostring(L, n))) {
2503- StreamDecoder* stream = StreamDecoder::Get(path);
2504- if(stream) {
2505- lua_pushboolean(L, true);
2506- delete stream;
2507- } else lua_pushboolean(L, false);
2508- } else lua_pushboolean(L, false);
2509- }
2510- return top;
2511-}
2512-
2513-const luaL_reg Lua_Music_Get[] = {
2514- {"clear", L_TableFunction<Lua_Music_Clear>},
2515- {"fade", L_TableFunction<Lua_Music_Fade>},
2516- {"play", L_TableFunction<Lua_Music_Play>},
2517- {"stop", L_TableFunction<Lua_Music_Stop>},
2518- {"valid", L_TableFunction<Lua_Music_Valid>},
2519- {0, 0}
2520-};
2521-
2522-static void Lua_Player_load_compatibility(lua_State *L);
2523-
2524-int Lua_Player_register (lua_State *L)
2525-{
2526- Lua_Action_Flags::Register(L, Lua_Action_Flags_Get, Lua_Action_Flags_Set);
2527-
2528- Lua_Camera_Path_Angles::Register(L, Lua_Camera_Path_Angles_Get);
2529- Lua_Camera_Path_Points::Register(L, Lua_Camera_Path_Points_Get);
2530- Lua_Camera::Register(L, Lua_Camera_Get);
2531- Lua_Camera::Valid = Lua_Camera_Valid;
2532-
2533- Lua_Cameras::Register(L, Lua_Cameras_Methods);
2534- Lua_Cameras::Length = Lua_Cameras_Length;
2535-
2536- Lua_Crosshairs::Register(L, Lua_Crosshairs_Get, Lua_Crosshairs_Set);
2537- Lua_Player_Compass::Register(L, Lua_Player_Compass_Get, Lua_Player_Compass_Set);
2538- Lua_Player_Items::Register(L, 0, 0, Lua_Player_Items_Metatable);
2539- Lua_Player_Kills::Register(L, 0, 0, Lua_Player_Kills_Metatable);
2540-
2541- Lua_InternalVelocity::Register(L, Lua_InternalVelocity_Get);
2542- Lua_ExternalVelocity::Register(L, Lua_ExternalVelocity_Get, Lua_ExternalVelocity_Set);
2543- Lua_FadeType::Register(L, 0, 0, 0, Lua_FadeType_Mnemonics);
2544- Lua_FadeType::Valid = Lua_FadeType::ValidRange(NUMBER_OF_FADE_TYPES);
2545-
2546- Lua_FadeTypes::Register(L);
2547- Lua_FadeTypes::Length = Lua_FadeTypes::ConstantLength((int16) NUMBER_OF_FADE_TYPES);
2548-
2549- Lua_Texture_Palette_Slot::Register(L, Lua_Texture_Palette_Slot_Get, Lua_Texture_Palette_Slot_Set);
2550- Lua_Texture_Palette_Slots::Register(L, 0, 0, Lua_Texture_Palette_Slots_Metatable);
2551- Lua_Texture_Palette::Register(L, Lua_Texture_Palette_Get, Lua_Texture_Palette_Set);
2552-
2553- Lua_WeaponType::Register(L, 0, 0, 0, Lua_WeaponType_Mnemonics);
2554- Lua_WeaponType::Valid = Lua_WeaponType::ValidRange(MAXIMUM_NUMBER_OF_WEAPONS);
2555-
2556- Lua_WeaponTypes::Register(L);
2557- Lua_WeaponTypes::Length = Lua_WeaponTypes::ConstantLength((int16) MAXIMUM_NUMBER_OF_WEAPONS);
2558-
2559- Lua_Player_Weapon::Register(L, Lua_Player_Weapon_Get);
2560- Lua_Player_Weapon::Valid = Lua_Player_Weapon::ValidRange(MAXIMUM_NUMBER_OF_WEAPONS);
2561-
2562- Lua_Player_Weapons::Register(L, 0, 0, Lua_Player_Weapons_Metatable);
2563- Lua_Player_Weapons::Valid = Lua_Player_Valid;
2564-
2565- Lua_Player_Weapon_Trigger::Register(L, Lua_Player_Weapon_Trigger_Get);
2566- Lua_Player_Weapon_Trigger::Valid = Lua_Player_Weapon_Trigger::ValidRange((int) _secondary_weapon + 1);
2567-
2568- Lua_OverlayColor::Register(L, 0, 0, 0, Lua_OverlayColor_Mnemonics);
2569- Lua_OverlayColor::Valid = Lua_OverlayColor::ValidRange(8);
2570-
2571- Lua_Overlays::Register(L, 0, 0, Lua_Overlays_Metatable);
2572- Lua_Overlays::Valid = Lua_Player_Valid;
2573-
2574- Lua_Overlay::Register(L, Lua_Overlay_Get, Lua_Overlay_Set);
2575- Lua_Overlay::Valid = Lua_Overlay::ValidRange(MAXIMUM_NUMBER_OF_SCRIPT_HUD_ELEMENTS);
2576-
2577- Lua_PlayerColor::Register(L, 0, 0, 0, Lua_PlayerColor_Mnemonics);
2578- Lua_PlayerColor::Valid = Lua_PlayerColor::ValidRange(NUMBER_OF_TEAM_COLORS);
2579-
2580- Lua_PlayerColors::Register(L);
2581- Lua_PlayerColors::Length = Lua_PlayerColors::ConstantLength((int16) NUMBER_OF_TEAM_COLORS);
2582-
2583- Lua_Player::Register(L, Lua_Player_Get, Lua_Player_Set);
2584- Lua_Player::Valid = Lua_Player_Valid;
2585-
2586- Lua_Players::Register(L, Lua_Players_Methods);
2587- Lua_Players::Length = Lua_Players_Length;
2588-
2589- Lua_Game::Register(L, Lua_Game_Get, Lua_Game_Set);
2590-
2591- Lua_GameType::Register(L, 0, 0, 0, Lua_GameType_Mnemonics);
2592- Lua_GameType::Valid = Lua_GameType::ValidRange(NUMBER_OF_GAME_TYPES);
2593-
2594- Lua_GameTypes::Register(L);
2595- Lua_GameTypes::Length = Lua_GameTypes::ConstantLength(NUMBER_OF_GAME_TYPES);
2596-
2597- Lua_ScoringMode::Register(L, 0, 0, 0, Lua_ScoringMode_Mnemonics);
2598- Lua_ScoringMode::Valid = Lua_ScoringMode::ValidRange(NUMBER_OF_GAME_SCORING_MODES);
2599-
2600- Lua_ScoringModes::Register(L);
2601- Lua_ScoringModes::Length = Lua_ScoringModes::ConstantLength(NUMBER_OF_GAME_SCORING_MODES);
2602-
2603- Lua_DifficultyType::Register(L, 0, 0, 0, Lua_DifficultyType_Mnemonics);
2604- Lua_DifficultyType::Valid = Lua_DifficultyType::ValidRange(NUMBER_OF_GAME_DIFFICULTY_LEVELS);
2605-
2606- Lua_DifficultyTypes::Register(L);
2607- Lua_DifficultyTypes::Length = Lua_DifficultyTypes::ConstantLength(NUMBER_OF_GAME_DIFFICULTY_LEVELS);
2608-
2609- Lua_TextureType::Register(L, 0, 0, 0, Lua_TextureType_Mnemonics);
2610- Lua_TextureType::Valid = Lua_TextureType::ValidRange(NUMBER_OF_LUA_TEXTURE_TYPES);
2611-
2612- Lua_TextureTypes::Register(L);
2613- Lua_TextureTypes::Length = Lua_TextureTypes::ConstantLength(NUMBER_OF_LUA_TEXTURE_TYPES);
2614-
2615- Lua_Music::Register(L, Lua_Music_Get);
2616-
2617- // register one Game userdatum globally
2618- Lua_Game::Push(L, 0);
2619- lua_setglobal(L, Lua_Game_Name);
2620-
2621- // register one Music userdatum
2622- Lua_Music::Push(L, 0);
2623- lua_setglobal(L, Lua_Music_Name);
2624-
2625- Lua_Player_load_compatibility(L);
2626-
2627- return 0;
2628-}
2629-
2630-static const char *compatibility_script = ""
2631- "function accelerate_player(player, vertical_velocity, direction, velocity) Players[player]:accelerate(direction, velocity, vertical_velocity) end\n"
2632- "function activate_camera(player, camera) Cameras[camera]:activate(player) end\n"
2633- "function activate_terminal(player, text) Players[player]:activate_terminal(text) end\n"
2634- "function add_item(player, item_type) Players[player].items[item_type] = Players[player].items[item_type] + 1 end\n"
2635- "function add_path_angle(camera, yaw, pitch, time) Cameras[camera].path_angles:new(yaw, pitch, time) end\n"
2636- "function add_path_point(camera, polygon, x, y, z, time) Cameras[camera].path_points:new(x, y, z, polygon, time) end\n"
2637- "function award_kills(player, slain_player, amount) if player == -1 then Players[slain_player].deaths = Players[slain_player].deaths + amount else Players[player].kills[slain_player] = Players[player].kills[slain_player] + amount end end\n"
2638- "function add_to_player_external_velocity(player, x, y, z) Players[player].external_velocity.i = Players[player].external_velocity.i + x Players[player].external_velocity.j = Players[player].external_velocity.j + y Players[player].external_velocity.k = Players[player].external_velocity.k + z end\n"
2639- "function award_points(player, amount) Players[player].points = Players[player].points + amount end\n"
2640- "function better_random() return Game.random() end\n"
2641- "function clear_camera(camera) Cameras[camera]:clear() end\n"
2642- "function clear_music() Music.clear() end\n"
2643- "function count_item(player, item_type) return Players[player].items[item_type] end\n"
2644- "function create_camera() return Cameras.new().index end\n"
2645- "function crosshairs_active(player) return Players[player].crosshairs.active end\n"
2646- "function deactivate_camera(camera) Cameras[camera]:deactivate() end\n"
2647- "function destroy_ball(player) for i in ItemTypes() do if i.ball then Players[player].items[i] = 0 end end end\n"
2648- "function fade_music(duration) if duration then Music.fade(duration * 60 / 1000) else Music.fade(60 / 1000) end end\n"
2649- "function get_game_difficulty() return Game.difficulty.index end\n"
2650- "function get_game_type() return Game.type.index end\n"
2651- "function get_kills(player, slain_player) if player == -1 then return Players[slain_player].deaths else return Players[player].kills[slain_player] end end\n"
2652- "function get_kill_limit() return Game.kill_limit end\n"
2653- "function get_life(player) return Players[player].energy end\n"
2654- "function get_motion_sensor_state(player) return Players[player].motion_sensor_active end\n"
2655- "function get_oxygen(player) return Players[player].oxygen end\n"
2656- "function get_player_angle(player) return Players[player].yaw, Players[player].pitch end\n"
2657- "function get_player_color(player) return Players[player].color.index end\n"
2658- "function get_player_external_velocity(player) return Players[player].external_velocity.i * 1024, Players[player].external_velocity.j * 1024, Players[player].external_velocity.k * 1024 end\n"
2659- "function get_player_internal_velocity(player) return Players[player].internal_velocity.forward * 65536, Players[player].internal_velocity.perpendicular * 65536 end\n"
2660- "function get_player_name(player) return Players[player].name end\n"
2661- "function get_player_polygon(player) return Players[player].polygon.index end\n"
2662- "function get_player_position(player) return Players[player].x, Players[player].y, Players[player].z end\n"
2663- "function get_player_powerup_duration(player, powerup) if powerup == _powerup_invisibility then return Players[player].invisibility_duration elseif powerup == _powerup_invincibility then return Players[player].invincibility_duration elseif powerup == _powerup_infravision then return Players[player].infravision_duratiohn elseif powerup == _powerup_extravision then return Players[player].extravision_duration end end\n"
2664- "function get_player_team(player) return Players[player].team.index end\n"
2665- "function get_player_weapon(player) if Players[player].weapons.current then return Players[player].weapons.current.index else return nil end end\n"
2666- "function get_points(player) return Players[player].points end\n"
2667- "function global_random() return Game.global_random() end\n"
2668- "function inflict_damage(player, amount, type) if (type) then Players[player]:damage(amount, type) else Players[player]:damage(amount) end end\n"
2669- "function local_player_index() for p in Players() do if p.local_ then return p.index end end end\n"
2670- "function local_random() return Game.local_random() end\n"
2671- "function number_of_players() return # Players end\n"
2672- "function play_music(...) Music.play(...) end\n"
2673- "function player_is_dead(player) return Players[player].dead end\n"
2674- "function player_media(player) if Players[player].head_below_media then return Players[player].polygon.media.index else return nil end end\n"
2675- "function player_to_monster_index(player) return Players[player].monster.index end\n"
2676- "function play_sound(player, sound, pitch) Players[player]:play_sound(sound, pitch) end\n"
2677- "function remove_item(player, item_type) if Players[player].items[item_type] > 0 then Players[player].items[item_type] = Players[player].items[item_type] - 1 end end\n"
2678- "function screen_fade(player, fade) if fade then Players[player]:fade_screen(fade) else for p in Players() do p:fade_screen(player) end end end\n"
2679- "function screen_print(player, message) if message then if Players[player] then Players[player]:print(message) end else Players.print(player) end end\n"
2680- "function select_weapon(player, weapon) Players[player].weapons[weapon]:select() end\n"
2681- "function set_crosshairs_state(player, state) Players[player].crosshairs.active = state end\n"
2682- "function set_kills(player, slain_player, amount) if player == -1 then Players[slain_player].deaths = amount else Players[player].kills[slain_player] = amount end end\n"
2683- "function set_life(player, shield) Players[player].energy = shield end\n"
2684- "function set_lua_compass_beacon(player, x, y) Players[player].compass.x = x Players[player].compass.y = y end\n"
2685- "function set_lua_compass_state(player, state) if state > 15 then Players[player].compass.beacon = true state = state % 16 else Players[player].compass.beacon = false end if state > 7 then Players[player].compass.se = true state = state - 8 else Players[player].compass.se = false end if state > 3 then Players[player].compass.sw = true state = state - 4 else Players[player].compass.sw = false end if state > 1 then Players[player].compass.ne = true state = state - 2 else Players[player].compass.ne = false end if state == 1 then Players[player].compass.nw = true else Players[player].compass.nw = false end end\n"
2686- "function set_motion_sensor_state(player, state) Players[player].motion_sensor_active = state end\n"
2687- "function set_overlay_color(overlay, color) for p in Players() do if p.local_ then p.overlays[overlay].color = color end end end\n"
2688- "function set_overlay_icon(overlay, icon) for p in Players() do if p.local_ then p.overlays[overlay].icon = icon end end end\n"
2689- "function set_overlay_icon_by_color(overlay, color) for p in Players() do if p.local_ then p.overlays[overlay]:fill_icon(color) end end end\n"
2690- "function set_overlay_text(overlay, text) for p in Players() do if p.local_ then p.overlays[overlay].text = text end end end\n"
2691- "function set_oxygen(player, oxygen) Players[player].oxygen = oxygen end\n"
2692- "function set_player_angle(player, yaw, pitch) Players[player].yaw = yaw Players[player].pitch = pitch + 360.0 end\n"
2693- "function set_player_color(player, color) Players[player].color = color end\n"
2694- "function set_player_external_velocity(player, x, y, z) Players[player].external_velocity.i = x / 1024 Players[player].external_velocity.j = y / 1024 Players[player].external_velocity.k = z / 1024 end\n"
2695- "function set_player_position(player, x, y, z, polygon) Players[player]:position(x, y, z, polygon) end\n"
2696- "function set_player_powerup_duration(player, powerup, duration) if powerup == _powerup_invisibility then Players[player].invisibility_duration = duration elseif powerup == _powerup_invincibility then Players[player].invincibility_duration = duration elseif powerup == _powerup_infravision then Players[player].infravision_duration = duration elseif powerup == _powerup_extravision then Players[player].extravision_duration = duration end end\n"
2697- "function set_player_team(player, team) Players[player].team = team end\n"
2698- "function set_points(player, amount) Players[player].points = amount end\n"
2699- "function stop_music() Music.stop() end\n"
2700- "function set_zoom_state(player, state) Players[player].zoom_active = state end\n"
2701- "function teleport_player(player, polygon) Players[player]:teleport(polygon) end\n"
2702- "function teleport_player_to_level(player, level) Players[player]:teleport_to_level(level) end\n"
2703- "function use_lua_compass(player, state) if state ~= nil then Players[player].compass.lua = state else for p in Players() do p.compass.lua = player end end end\n"
2704- "function zoom_active(player) return Players[player].zoom_active end\n"
2705- ;
2706-
2707-static void Lua_Player_load_compatibility(lua_State *L)
2708-{
2709- luaL_loadbuffer(L, compatibility_script, strlen(compatibility_script), "player_compatibility");
2710- lua_pcall(L, 0, 0, 0);
2711-};
2712-
2713-#endif
1+/*
2+LUA_PLAYER.CPP
3+
4+ Copyright (C) 2008 by Gregory Smith
5+
6+ This program is free software; you can redistribute it and/or modify
7+ it under the terms of the GNU General Public License as published by
8+ the Free Software Foundation; either version 3 of the License, or
9+ (at your option) any later version.
10+
11+ This program is distributed in the hope that it will be useful,
12+ but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ GNU General Public License for more details.
15+
16+ This license is contained in the file "COPYING",
17+ which is included with this source code; it is available online at
18+ http://www.gnu.org/licenses/gpl.html
19+
20+ Implements the Lua Player class
21+*/
22+
23+#include "ActionQueues.h"
24+#include "alephversion.h"
25+#include "computer_interface.h"
26+#include "Crosshairs.h"
27+#include "fades.h"
28+#include "game_window.h"
29+#include "interface.h"
30+#include "lua_map.h"
31+#include "lua_monsters.h"
32+#include "lua_objects.h"
33+#include "lua_hud_objects.h"
34+#include "lua_player.h"
35+#include "lua_script.h"
36+#include "lua_templates.h"
37+#include "map.h"
38+#include "monsters.h"
39+#include "Music.h"
40+#include "network.h"
41+#include "player.h"
42+#include "projectiles.h"
43+#include "network_games.h"
44+#include "Random.h"
45+#include "screen.h"
46+#include "shell.h"
47+#include "SoundManager.h"
48+#include "ViewControl.h"
49+
50+#define DONT_REPEAT_DEFINITIONS
51+#include "item_definitions.h"
52+#include "projectile_definitions.h"
53+
54+#ifdef HAVE_LUA
55+
56+const float AngleConvert = 360/float(FULL_CIRCLE);
57+
58+char Lua_Action_Flags_Name[] = "action_flags";
59+typedef L_Class<Lua_Action_Flags_Name> Lua_Action_Flags;
60+
61+extern ModifiableActionQueues *GetGameQueue();
62+
63+template<uint32 flag>
64+static int Lua_Action_Flags_Get_t(lua_State *L)
65+{
66+ int player_index = Lua_Action_Flags::Index(L, 1);
67+
68+ if (GetGameQueue()->countActionFlags(player_index))
69+ {
70+ uint32 flags = GetGameQueue()->peekActionFlags(player_index, 0);
71+ lua_pushboolean(L, flags & flag);
72+ }
73+ else
74+ {
75+ return luaL_error(L, "action flags are only accessible in idle()");
76+ }
77+
78+ return 1;
79+}
80+
81+template<uint32 flag>
82+static int Lua_Action_Flags_Set_t(lua_State *L)
83+{
84+ if (!lua_isboolean(L, 2))
85+ return luaL_error(L, "action flags: incorrect argument type");
86+
87+ int player_index = Lua_Action_Flags::Index(L, 1);
88+ if (GetGameQueue()->countActionFlags(player_index))
89+ {
90+ if (lua_toboolean(L, 2))
91+ {
92+ GetGameQueue()->modifyActionFlags(player_index, flag, flag);
93+ }
94+ else
95+ {
96+ GetGameQueue()->modifyActionFlags(player_index, 0, flag);
97+ }
98+ }
99+ else
100+ {
101+ return luaL_error(L, "action flags are only accessible in idle()");
102+ }
103+
104+ return 0;
105+}
106+
107+static int Lua_Action_Flags_Set_Microphone(lua_State *L)
108+{
109+ if (!lua_isboolean(L, 2))
110+ return luaL_error(L, "action flags: incorrect argument type");
111+
112+ if (lua_toboolean(L, 2))
113+ return luaL_error(L, "you can only disable the microphone button flag");
114+
115+ int player_index = Lua_Action_Flags::Index(L, 1);
116+ if (GetGameQueue()->countActionFlags(player_index))
117+ {
118+ GetGameQueue()->modifyActionFlags(player_index, 0, _microphone_button);
119+ }
120+ else
121+ {
122+ return luaL_error(L, "action flags are only accessible in idle()");
123+ }
124+
125+ return 0;
126+}
127+
128+const luaL_reg Lua_Action_Flags_Get[] = {
129+ {"action_trigger", Lua_Action_Flags_Get_t<_action_trigger_state>},
130+ {"cycle_weapons_backward", Lua_Action_Flags_Get_t<_cycle_weapons_backward>},
131+ {"cycle_weapons_forward", Lua_Action_Flags_Get_t<_cycle_weapons_forward>},
132+ {"left_trigger", Lua_Action_Flags_Get_t<_left_trigger_state>},
133+ {"microphone_button", Lua_Action_Flags_Get_t<_microphone_button>},
134+ {"right_trigger", Lua_Action_Flags_Get_t<_right_trigger_state>},
135+ {"toggle_map", Lua_Action_Flags_Get_t<_toggle_map>},
136+ {0, 0}
137+};
138+
139+const luaL_reg Lua_Action_Flags_Set[] = {
140+ {"action_trigger", Lua_Action_Flags_Set_t<_action_trigger_state>},
141+ {"cycle_weapons_backward", Lua_Action_Flags_Set_t<_cycle_weapons_backward>},
142+ {"cycle_weapons_forward", Lua_Action_Flags_Set_t<_cycle_weapons_forward>},
143+ {"left_trigger", Lua_Action_Flags_Set_t<_left_trigger_state>},
144+ {"microphone_button", Lua_Action_Flags_Set_Microphone},
145+ {"right_trigger", Lua_Action_Flags_Set_t<_right_trigger_state>},
146+ {"toggle_map", Lua_Action_Flags_Set_t<_toggle_map>},
147+ {0, 0}
148+};
149+
150+extern vector<lua_camera> lua_cameras;
151+
152+char Lua_Camera_Path_Points_Name[] = "camera_path_points";
153+typedef L_Class<Lua_Camera_Path_Points_Name> Lua_Camera_Path_Points;
154+
155+int Lua_Camera_Path_Points_New(lua_State *L)
156+{
157+ if (!lua_isnumber(L, 2) || !lua_isnumber(L, 3) || !lua_isnumber(L, 4) || !lua_isnumber(L, 6))
158+ return luaL_error(L, "new: incorrect argument type");
159+
160+ int camera_index = Lua_Camera_Path_Points::Index(L, 1);
161+
162+ int polygon = 0;
163+ if (lua_isnumber(L, 5))
164+ {
165+ polygon = static_cast<int>(lua_tonumber(L, 5));
166+ if (!Lua_Polygon::Valid(polygon))
167+ return luaL_error(L, "new: invalid polygon index");
168+ }
169+ else if (Lua_Polygon::Is(L, 5))
170+ {
171+ polygon = Lua_Polygon::Index(L, 5);
172+ }
173+ else
174+ return luaL_error(L, "new: incorrect argument type");
175+
176+ world_point3d point = {
177+ static_cast<world_distance>(lua_tonumber(L, 2) * WORLD_ONE),
178+ static_cast<world_distance>(lua_tonumber(L, 3) * WORLD_ONE),
179+ static_cast<world_distance>(lua_tonumber(L, 4) * WORLD_ONE)
180+ };
181+
182+ int32 time = static_cast<int32>(lua_tonumber(L, 6));
183+ int point_index = lua_cameras[camera_index].path.path_points.size();
184+ lua_cameras[camera_index].path.path_points.resize(point_index+1);
185+ lua_cameras[camera_index].path.path_points[point_index].polygon = polygon;
186+ lua_cameras[camera_index].path.path_points[point_index].point = point;
187+ lua_cameras[camera_index].path.path_points[point_index].delta_time = time;
188+ return 0;
189+}
190+
191+const luaL_reg Lua_Camera_Path_Points_Get[] = {
192+ {"new", L_TableFunction<Lua_Camera_Path_Points_New>},
193+ {0, 0}
194+};
195+
196+char Lua_Camera_Path_Angles_Name[] = "camera_path_angles";
197+typedef L_Class<Lua_Camera_Path_Angles_Name> Lua_Camera_Path_Angles;
198+
199+int Lua_Camera_Path_Angles_New(lua_State *L)
200+{
201+ if (!lua_isnumber(L, 2) || !lua_isnumber(L, 3) || !lua_isnumber(L, 4))
202+ return luaL_error(L, "new: incorrect argument type");
203+
204+ int camera_index = Lua_Camera_Path_Angles::Index(L, 1);
205+ short yaw = static_cast<short>(lua_tonumber(L,2));
206+ short pitch = static_cast<short>(lua_tonumber(L,3));
207+ int32 time = static_cast<int32>(lua_tonumber(L,4));
208+ int angle_index = lua_cameras[camera_index].path.path_angles.size();
209+
210+ lua_cameras[camera_index].path.path_angles.resize(angle_index+1);
211+ lua_cameras[camera_index].path.path_angles[angle_index].yaw = static_cast<short>(yaw/AngleConvert);
212+ lua_cameras[camera_index].path.path_angles[angle_index].pitch = static_cast<short>(pitch/AngleConvert);
213+ lua_cameras[camera_index].path.path_angles[angle_index].delta_time = time;
214+ return 0;
215+};
216+
217+const luaL_reg Lua_Camera_Path_Angles_Get[] = {
218+ {"new", L_TableFunction<Lua_Camera_Path_Angles_New>},
219+ {0, 0}
220+};
221+
222+char Lua_Camera_Name[] = "camera";
223+typedef L_Class<Lua_Camera_Name> Lua_Camera;
224+
225+
226+int Lua_Camera_Activate(lua_State *L)
227+{
228+ int player_index = -1;
229+ if (lua_isnumber(L, 2))
230+ {
231+ player_index = static_cast<int>(lua_tonumber(L, 2));
232+ }
233+ else if (Lua_Player::Is(L, 2))
234+ {
235+ player_index = Lua_Player::Index(L, 2);
236+ }
237+ else
238+ return luaL_error(L, "activate: incorrect argument type");
239+
240+ if (player_index == local_player_index)
241+ {
242+ int camera_index = Lua_Camera::Index(L, 1);
243+ lua_cameras[camera_index].time_elapsed = 0;
244+ lua_cameras[camera_index].player_active = player_index;
245+ lua_cameras[camera_index].path.current_point_index = 0;
246+ lua_cameras[camera_index].path.current_angle_index = 0;
247+ lua_cameras[camera_index].path.last_point_time = 0;
248+ lua_cameras[camera_index].path.last_angle_time = 0;
249+ }
250+
251+ return 0;
252+}
253+
254+int Lua_Camera_Clear(lua_State *L)
255+{
256+ int camera_index = Lua_Camera::Index(L, 1);
257+ lua_cameras[camera_index].path.path_points.resize(0);
258+ lua_cameras[camera_index].path.path_angles.resize(0);
259+ return 0;
260+}
261+
262+int Lua_Camera_Deactivate(lua_State *L)
263+{
264+ int camera_index = Lua_Camera::Index(L, 1);
265+ lua_cameras[camera_index].time_elapsed = 0;
266+ lua_cameras[camera_index].player_active = -1;
267+ lua_cameras[camera_index].path.last_point_time = 0;
268+ lua_cameras[camera_index].path.last_angle_time = 0;
269+ return 0;
270+}
271+
272+static int Lua_Get_Path_Angles(lua_State *L)
273+{
274+ Lua_Camera_Path_Angles::Push(L, Lua_Camera::Index(L, 1));
275+ return 1;
276+}
277+
278+static int Lua_Get_Path_Points(lua_State *L)
279+{
280+ Lua_Camera_Path_Points::Push(L, Lua_Camera::Index(L, 1));
281+ return 1;
282+}
283+
284+const luaL_reg Lua_Camera_Get[] = {
285+ {"activate", L_TableFunction<Lua_Camera_Activate>},
286+ {"clear", L_TableFunction<Lua_Camera_Clear>},
287+ {"deactivate", L_TableFunction<Lua_Camera_Deactivate>},
288+ {"path_angles", Lua_Get_Path_Angles},
289+ {"path_points", Lua_Get_Path_Points},
290+ {0, 0}
291+};
292+
293+static int Lua_Camera_Valid(int16 index)
294+{
295+ return index >= 0 && index < lua_cameras.size();
296+}
297+
298+char Lua_Cameras_Name[] = "Cameras";
299+typedef L_Container<Lua_Cameras_Name, Lua_Camera> Lua_Cameras;
300+
301+static int Lua_Cameras_New(lua_State *L)
302+{
303+ if (lua_cameras.size() == INT16_MAX)
304+ {
305+ return 0;
306+ }
307+
308+ lua_camera camera;
309+ camera.index = lua_cameras.size();
310+ camera.path.index = lua_cameras.size();
311+ camera.path.current_point_index = 0;
312+ camera.path.current_angle_index = 0;
313+ camera.path.last_point_time = 0;
314+ camera.path.last_angle_time = 0;
315+ camera.time_elapsed = 0;
316+ camera.player_active = -1;
317+ lua_cameras.push_back(camera);
318+
319+ Lua_Camera::Push(L, camera.index);
320+
321+ return 1;
322+}
323+
324+const luaL_reg Lua_Cameras_Methods[] = {
325+ {"new", Lua_Cameras_New},
326+ {0, 0}
327+};
328+
329+static int16 Lua_Cameras_Length() {
330+ return lua_cameras.size();
331+}
332+
333+char Lua_Crosshairs_Name[] = "crosshairs";
334+typedef L_Class<Lua_Crosshairs_Name> Lua_Crosshairs;
335+
336+static int Lua_Crosshairs_Get_Active(lua_State *L)
337+{
338+ int player_index = Lua_Crosshairs::Index(L, 1);
339+ if (player_index == local_player_index)
340+ {
341+ lua_pushboolean(L, Crosshairs_IsActive());
342+ return 1;
343+ }
344+ else
345+ {
346+ return 0;
347+ }
348+}
349+
350+const luaL_reg Lua_Crosshairs_Get[] = {
351+ {"active", Lua_Crosshairs_Get_Active},
352+ {0, 0}
353+};
354+
355+static int Lua_Crosshairs_Set_Active(lua_State *L)
356+{
357+ int player_index = Lua_Crosshairs::Index(L, 1);
358+ if (player_index == local_player_index)
359+ {
360+ if (!lua_isboolean(L, 2))
361+ return luaL_error(L, "active: incorrect argument type");
362+
363+ Crosshairs_SetActive(lua_toboolean(L, 2));
364+ }
365+
366+ return 0;
367+}
368+
369+const luaL_reg Lua_Crosshairs_Set[] = {
370+ {"active", Lua_Crosshairs_Set_Active},
371+ {0, 0}
372+};
373+
374+char Lua_OverlayColor_Name[] = "overlay_color";
375+typedef L_Enum<Lua_OverlayColor_Name> Lua_OverlayColor;
376+
377+template<char *name>
378+class PlayerSubtable : public L_Class<name>
379+{
380+public:
381+ int16 m_player_index;
382+ static PlayerSubtable *Push(lua_State *L, int16 player_index, int16 index);
383+ static int16 PlayerIndex(lua_State *L, int index);
384+};
385+
386+template<char *name>
387+PlayerSubtable<name> *PlayerSubtable<name>::Push(lua_State *L, int16 player_index, int16 index)
388+{
389+ PlayerSubtable<name> *t = 0;
390+
391+ if (!L_Class<name, int16>::Valid(index) || !Lua_Player::Valid(player_index))
392+ {
393+ lua_pushnil(L);
394+ return 0;
395+ }
396+
397+ t = static_cast<PlayerSubtable<name>*>(lua_newuserdata(L, sizeof(PlayerSubtable<name>)));
398+ luaL_getmetatable(L, name);
399+ lua_setmetatable(L, -2);
400+ t->m_index = index;
401+ t->m_player_index = player_index;
402+
403+ return t;
404+}
405+
406+template<char *name>
407+int16 PlayerSubtable<name>::PlayerIndex(lua_State *L, int index)
408+{
409+ PlayerSubtable<name> *t = static_cast<PlayerSubtable<name> *>(lua_touserdata(L, index));
410+ if (!t) luaL_typerror(L, index, name);
411+ return t->m_player_index;
412+}
413+
414+char Lua_Overlay_Name[] = "overlay";
415+typedef PlayerSubtable<Lua_Overlay_Name> Lua_Overlay;
416+
417+int Lua_Overlay_Clear(lua_State *L)
418+{
419+ int index = Lua_Overlay::Index(L, 1);
420+ if (Lua_Overlay::PlayerIndex(L, 1) == local_player_index)
421+ {
422+ SetScriptHUDIcon(index, 0, 0);
423+ SetScriptHUDText(index, 0);
424+ }
425+
426+ return 0;
427+}
428+
429+int Lua_Overlay_Fill_Icon(lua_State *L)
430+{
431+ if (Lua_Overlay::PlayerIndex(L, 1) == local_player_index)
432+ {
433+ int color = Lua_OverlayColor::ToIndex(L, 2);
434+ SetScriptHUDSquare(Lua_Overlay::Index(L, 1), color);
435+ }
436+
437+ return 0;
438+}
439+
440+const luaL_reg Lua_Overlay_Get[] = {
441+ {"clear", L_TableFunction<Lua_Overlay_Clear>},
442+ {"fill_icon", L_TableFunction<Lua_Overlay_Fill_Icon>},
443+ {0, 0}
444+};
445+
446+static int Lua_Overlay_Set_Icon(lua_State *L)
447+{
448+ if (Lua_Overlay::PlayerIndex(L, 1) == local_player_index)
449+ {
450+ if (lua_isstring(L, 2))
451+ {
452+ SetScriptHUDIcon(Lua_Overlay::Index(L, 1), lua_tostring(L, 2), lua_strlen(L, 2));
453+ }
454+ else
455+ {
456+ SetScriptHUDIcon(Lua_Overlay::Index(L, 1), 0, 0);
457+ }
458+ }
459+
460+ return 0;
461+}
462+
463+static int Lua_Overlay_Set_Text(lua_State *L)
464+{
465+ if (Lua_Overlay::PlayerIndex(L, 1) == local_player_index)
466+ {
467+ const char *text = 0;
468+ if (lua_isstring(L, 2))
469+ text = lua_tostring(L, 2);
470+
471+ SetScriptHUDText(Lua_Overlay::Index(L, 1), text);
472+ }
473+
474+ return 0;
475+}
476+
477+static int Lua_Overlay_Set_Text_Color(lua_State *L)
478+{
479+ if (Lua_Overlay::PlayerIndex(L, 1) == local_player_index)
480+ {
481+ int color = Lua_OverlayColor::ToIndex(L, 2);
482+ SetScriptHUDColor(Lua_Overlay::Index(L, 1), color);
483+ }
484+
485+ return 0;
486+}
487+
488+const luaL_reg Lua_Overlay_Set[] = {
489+ {"color", Lua_Overlay_Set_Text_Color},
490+ {"icon", Lua_Overlay_Set_Icon},
491+ {"text", Lua_Overlay_Set_Text},
492+ {0, 0}
493+};
494+
495+char Lua_Overlays_Name[] = "overlays";
496+typedef L_Class<Lua_Overlays_Name> Lua_Overlays;
497+
498+static int Lua_Overlays_Get(lua_State *L)
499+{
500+ if (lua_isnumber(L, 2))
501+ {
502+ int player_index = Lua_Overlays::Index(L, 1);
503+ int index = static_cast<int>(lua_tonumber(L, 2));
504+ if (Lua_Overlays::Valid(player_index) && index >= 0 && index < MAXIMUM_NUMBER_OF_SCRIPT_HUD_ELEMENTS)
505+ {
506+ Lua_Overlay::Push(L, player_index, index);
507+ }
508+ else
509+ {
510+ lua_pushnil(L);
511+ }
512+ }
513+ else
514+ {
515+ lua_pushnil(L);
516+ }
517+
518+ return 1;
519+}
520+
521+static int Lua_Overlays_Length(lua_State *L)
522+{
523+ int player_index = Lua_Overlays::Index(L, 1);
524+ if (Lua_Overlays::Valid(player_index))
525+ lua_pushnumber(L, MAXIMUM_NUMBER_OF_SCRIPT_HUD_ELEMENTS);
526+ else
527+ lua_pushnumber(L, 0);
528+ return 1;
529+}
530+
531+const luaL_reg Lua_Overlays_Metatable[] = {
532+ {"__index", Lua_Overlays_Get},
533+ {"__len", Lua_Overlays_Length},
534+ {0, 0}
535+};
536+
537+extern bool use_lua_compass[MAXIMUM_NUMBER_OF_NETWORK_PLAYERS];
538+extern world_point2d lua_compass_beacons[MAXIMUM_NUMBER_OF_NETWORK_PLAYERS];
539+extern short lua_compass_states[MAXIMUM_NUMBER_OF_NETWORK_PLAYERS];
540+
541+char Lua_Player_Compass_Name[] = "player_compass";
542+typedef L_Class<Lua_Player_Compass_Name> Lua_Player_Compass;
543+
544+template<short state>
545+int Lua_Player_Compass_All(lua_State *L)
546+{
547+ int player_index = Lua_Player_Compass::Index(L, 1);
548+ lua_compass_states[player_index] = state;
549+ return 0;
550+}
551+
552+static int Lua_Player_Compass_Get_Lua(lua_State *L)
553+{
554+ int player_index = Lua_Player_Compass::Index(L, 1);
555+ lua_pushboolean(L, use_lua_compass[player_index]);
556+ return 1;
557+}
558+
559+template<short state>
560+static int Lua_Player_Compass_Get_State(lua_State *L)
561+{
562+ int player_index = Lua_Player_Compass::Index(L, 1);
563+ lua_pushboolean(L, lua_compass_states[player_index] & state);
564+ return 1;
565+}
566+
567+static int Lua_Player_Compass_Get_X(lua_State *L)
568+{
569+ int player_index = Lua_Player_Compass::Index(L, 1);
570+ lua_pushnumber(L, static_cast<double>(lua_compass_beacons[player_index].x / WORLD_ONE));
571+ return 1;
572+}
573+
574+static int Lua_Player_Compass_Get_Y(lua_State *L)
575+{
576+ int player_index = Lua_Player_Compass::Index(L, 1);
577+ lua_pushnumber(L, static_cast<double>(lua_compass_beacons[player_index].y / WORLD_ONE));
578+ return 1;
579+}
580+
581+const luaL_reg Lua_Player_Compass_Get[] = {
582+ {"all_off", L_TableFunction<Lua_Player_Compass_All<_network_compass_all_off> >},
583+ {"all_on", L_TableFunction<Lua_Player_Compass_All<_network_compass_all_on> >},
584+ {"beacon", Lua_Player_Compass_Get_State<_network_compass_use_beacon>},
585+ {"lua", Lua_Player_Compass_Get_Lua},
586+ {"ne", Lua_Player_Compass_Get_State<_network_compass_ne>},
587+ {"northeast", Lua_Player_Compass_Get_State<_network_compass_ne>},
588+ {"northwest", Lua_Player_Compass_Get_State<_network_compass_nw>},
589+ {"nw", Lua_Player_Compass_Get_State<_network_compass_nw>},
590+ {"se", Lua_Player_Compass_Get_State<_network_compass_se>},
591+ {"southeast", Lua_Player_Compass_Get_State<_network_compass_se>},
592+ {"southwest", Lua_Player_Compass_Get_State<_network_compass_sw>},
593+ {"sw", Lua_Player_Compass_Get_State<_network_compass_sw>},
594+ {"x", Lua_Player_Compass_Get_X},
595+ {"y", Lua_Player_Compass_Get_Y},
596+ {0, 0}
597+};
598+
599+static int Lua_Player_Compass_Set_Lua(lua_State *L)
600+{
601+ if (!lua_isboolean(L, 2))
602+ return luaL_error(L, "lua: incorrect argument type");
603+
604+ int player_index = Lua_Player_Compass::Index(L, 1);
605+ use_lua_compass[player_index] = lua_toboolean(L, 2);
606+ return 0;
607+}
608+
609+template<short state>
610+static int Lua_Player_Compass_Set_State(lua_State *L)
611+{
612+ if (!lua_isboolean(L, 2))
613+ return luaL_error(L, "compass: incorrect argument type");
614+
615+ int player_index = Lua_Player_Compass::Index(L, 1);
616+ if (lua_toboolean(L, 2))
617+ {
618+ lua_compass_states[player_index] |= state;
619+ }
620+ else
621+ {
622+ lua_compass_states[player_index] &= ~state;
623+ }
624+
625+ return 0;
626+}
627+
628+static int Lua_Player_Compass_Set_X(lua_State *L)
629+{
630+ if (!lua_isnumber(L, 2))
631+ return luaL_error(L, "x: incorrect argument type");
632+
633+ int player_index = Lua_Player_Compass::Index(L, 1);
634+ lua_compass_beacons[player_index].x = static_cast<world_distance>(lua_tonumber(L, 2) * WORLD_ONE);
635+ return 0;
636+}
637+
638+static int Lua_Player_Compass_Set_Y(lua_State *L)
639+{
640+ if (!lua_isnumber(L, 2))
641+ return luaL_error(L, "y: incorrect argument type");
642+
643+ int player_index = Lua_Player_Compass::Index(L, 1);
644+ lua_compass_beacons[player_index].y = static_cast<world_distance>(lua_tonumber(L, 2) * WORLD_ONE);
645+ return 0;
646+}
647+
648+const luaL_reg Lua_Player_Compass_Set[] = {
649+ {"beacon", Lua_Player_Compass_Set_State<_network_compass_use_beacon>},
650+ {"lua", Lua_Player_Compass_Set_Lua},
651+ {"ne", Lua_Player_Compass_Set_State<_network_compass_ne>},
652+ {"northeast", Lua_Player_Compass_Set_State<_network_compass_ne>},
653+ {"northwest", Lua_Player_Compass_Set_State<_network_compass_nw>},
654+ {"nw", Lua_Player_Compass_Set_State<_network_compass_nw>},
655+ {"se", Lua_Player_Compass_Set_State<_network_compass_se>},
656+ {"southeast", Lua_Player_Compass_Set_State<_network_compass_se>},
657+ {"southwest", Lua_Player_Compass_Set_State<_network_compass_sw>},
658+ {"sw", Lua_Player_Compass_Set_State<_network_compass_sw>},
659+ {"x", Lua_Player_Compass_Set_X},
660+ {"y", Lua_Player_Compass_Set_Y},
661+ {0, 0}
662+};
663+
664+char Lua_Player_Items_Name[] = "player_items";
665+typedef L_Class<Lua_Player_Items_Name> Lua_Player_Items;
666+
667+static int Lua_Player_Items_Get(lua_State *L)
668+{
669+ int player_index = Lua_Player_Items::Index(L, 1);
670+ int item_type = Lua_ItemType::ToIndex(L, 2);
671+
672+ player_data *player = get_player_data(player_index);
673+ int item_count = player->items[item_type];
674+ if (item_count == NONE) item_count = 0;
675+ lua_pushnumber(L, item_count);
676+ return 1;
677+}
678+
679+static int Lua_Player_Items_Length(lua_State *L)
680+{
681+ lua_pushnumber(L, NUMBER_OF_DEFINED_ITEMS);
682+ return 1;
683+}
684+
685+extern void destroy_players_ball(short player_index);
686+extern void select_next_best_weapon(short player_index);
687+
688+static int Lua_Player_Items_Set(lua_State *L)
689+{
690+ if (!lua_isnumber(L, 3))
691+ return luaL_error(L, "items: incorrect argument type");
692+
693+ int player_index = Lua_Player_Items::Index(L, 1);
694+ player_data *player = get_player_data(player_index);
695+ int item_type = Lua_ItemType::ToIndex(L, 2);
696+ int item_count = player->items[item_type];
697+ item_definition *definition = get_item_definition_external(item_type);
698+ int new_item_count = static_cast<int>(lua_tonumber(L, 3));
699+
700+ bool accounting = L_Get_Proper_Item_Accounting(L);
701+
702+ if (new_item_count < 0)
703+ luaL_error(L, "items: invalid item count");
704+
705+ if (item_count == NONE) item_count = 0;
706+ int real_difference = item_count - new_item_count;
707+ if (new_item_count == 0) new_item_count = NONE;
708+
709+ if (new_item_count < item_count)
710+ {
711+ if (definition->item_kind == _ball)
712+ {
713+ if (find_player_ball_color(player_index) != NONE)
714+ destroy_players_ball(player_index);
715+ }
716+ else
717+ {
718+ player->items[item_type] = new_item_count;
719+ mark_player_inventory_as_dirty(player_index, item_type);
720+ if (definition->item_kind == _weapon && player->items[item_type] == NONE)
721+ {
722+ select_next_best_weapon(player_index);
723+ }
724+
725+ if (accounting)
726+ {
727+ for (int i = 0; i < real_difference; ++i)
728+ object_was_just_destroyed(_object_is_item, item_type);
729+ }
730+ }
731+ }
732+ else if (new_item_count > item_count)
733+ {
734+ while (new_item_count-- > item_count)
735+ {
736+ if (try_and_add_player_item(player_index, item_type))
737+ {
738+ if (accounting)
739+ object_was_just_added(_object_is_item, item_type);
740+ }
741+ }
742+ }
743+
744+ return 0;
745+}
746+
747+const luaL_reg Lua_Player_Items_Metatable[] = {
748+ {"__index", Lua_Player_Items_Get},
749+ {"__newindex", Lua_Player_Items_Set},
750+ {"__len", Lua_Player_Items_Length},
751+ {0, 0}
752+};
753+
754+char Lua_InternalVelocity_Name[] = "internal_velocity";
755+typedef L_Class<Lua_InternalVelocity_Name> Lua_InternalVelocity;
756+
757+static int Lua_InternalVelocity_Get_Forward(lua_State *L)
758+{
759+ int player_index = Lua_InternalVelocity::Index(L, 1);
760+ player_data *player = get_player_data(player_index);
761+ lua_pushnumber(L, (double) player->variables.velocity / FIXED_ONE);
762+ return 1;
763+}
764+
765+static int Lua_InternalVelocity_Get_Perpendicular(lua_State *L)
766+{
767+ int player_index = Lua_InternalVelocity::Index(L, 1);
768+ player_data *player = get_player_data(player_index);
769+ lua_pushnumber(L, (double) player->variables.perpendicular_velocity / FIXED_ONE);
770+ return 1;
771+}
772+
773+const luaL_reg Lua_InternalVelocity_Get[] = {
774+ {"forward", Lua_InternalVelocity_Get_Forward},
775+ {"perpendicular", Lua_InternalVelocity_Get_Perpendicular},
776+ {0, 0}
777+};
778+
779+char Lua_ExternalVelocity_Name[] = "external_velocity";
780+typedef L_Class<Lua_ExternalVelocity_Name> Lua_ExternalVelocity;
781+
782+static int Lua_ExternalVelocity_Get_I(lua_State *L)
783+{
784+ lua_pushnumber(L, (double) get_player_data(Lua_ExternalVelocity::Index(L, 1))->variables.external_velocity.i / WORLD_ONE);
785+ return 1;
786+}
787+
788+static int Lua_ExternalVelocity_Get_J(lua_State *L)
789+{
790+ lua_pushnumber(L, (double) get_player_data(Lua_ExternalVelocity::Index(L, 1))->variables.external_velocity.j / WORLD_ONE);
791+ return 1;
792+}
793+
794+static int Lua_ExternalVelocity_Get_K(lua_State *L)
795+{
796+ lua_pushnumber(L, (double) get_player_data(Lua_ExternalVelocity::Index(L, 1))->variables.external_velocity.k / WORLD_ONE);
797+ return 1;
798+}
799+
800+const luaL_reg Lua_ExternalVelocity_Get[] = {
801+ {"i", Lua_ExternalVelocity_Get_I},
802+ {"j", Lua_ExternalVelocity_Get_J},
803+ {"k", Lua_ExternalVelocity_Get_K},
804+ {"x", Lua_ExternalVelocity_Get_I},
805+ {"y", Lua_ExternalVelocity_Get_J},
806+ {"z", Lua_ExternalVelocity_Get_K},
807+ {0, 0}
808+};
809+
810+static int Lua_ExternalVelocity_Set_I(lua_State *L)
811+{
812+ if (!lua_isnumber(L, 2))
813+ return luaL_error(L, "i: incorrect argument type");
814+
815+ int raw_velocity = static_cast<int>(lua_tonumber(L, 2) * WORLD_ONE);
816+ get_player_data(Lua_ExternalVelocity::Index(L, 1))->variables.external_velocity.i = raw_velocity;
817+ return 0;
818+}
819+
820+static int Lua_ExternalVelocity_Set_J(lua_State *L)
821+{
822+ if (!lua_isnumber(L, 2))
823+ return luaL_error(L, "j: incorrect argument type");
824+
825+ int raw_velocity = static_cast<int>(lua_tonumber(L, 2) * WORLD_ONE);
826+ get_player_data(Lua_ExternalVelocity::Index(L, 1))->variables.external_velocity.j = raw_velocity;
827+ return 0;
828+}
829+
830+static int Lua_ExternalVelocity_Set_K(lua_State *L)
831+{
832+ if (!lua_isnumber(L, 2))
833+ return luaL_error(L, "k: incorrect argument type");
834+
835+ int raw_velocity = static_cast<int>(lua_tonumber(L, 2) * WORLD_ONE);
836+ get_player_data(Lua_ExternalVelocity::Index(L, 1))->variables.external_velocity.k = raw_velocity;
837+ return 0;
838+}
839+
840+const luaL_reg Lua_ExternalVelocity_Set[] = {
841+ {"i", Lua_ExternalVelocity_Set_I},
842+ {"j", Lua_ExternalVelocity_Set_J},
843+ {"k", Lua_ExternalVelocity_Set_K},
844+ {"x", Lua_ExternalVelocity_Set_I},
845+ {"y", Lua_ExternalVelocity_Set_J},
846+ {"z", Lua_ExternalVelocity_Set_K},
847+ {0, 0}
848+};
849+
850+char Lua_FadeType_Name[] = "fade_type";
851+typedef L_Enum<Lua_FadeType_Name> Lua_FadeType;
852+
853+char Lua_FadeTypes_Name[] = "FadeTypes";
854+typedef L_EnumContainer<Lua_FadeTypes_Name, Lua_FadeType> Lua_FadeTypes;
855+
856+const int MAX_TEXTURE_PALETTE_SIZE = 256;
857+struct lua_texture {
858+ shape_descriptor shape;
859+ short type;
860+};
861+typedef struct lua_texture lua_texture;
862+static std::vector<lua_texture> lua_texture_palette;
863+static int lua_texture_palette_selected = -1;
864+
865+void LuaTexturePaletteClear() {
866+ lua_texture_palette.clear();
867+}
868+
869+int LuaTexturePaletteSize() {
870+ return lua_texture_palette.size();
871+}
872+
873+shape_descriptor LuaTexturePaletteTexture(size_t index)
874+{
875+ if (index < lua_texture_palette.size())
876+ return lua_texture_palette[index].shape;
877+ else
878+ return UNONE;
879+}
880+
881+short LuaTexturePaletteTextureType(size_t index)
882+{
883+ if (index < lua_texture_palette.size())
884+ return lua_texture_palette[index].type;
885+ else
886+ return 0;
887+}
888+
889+int LuaTexturePaletteSelected()
890+{
891+ return lua_texture_palette_selected;
892+}
893+
894+char Lua_Texture_Palette_Slot_Name[] = "texture_palette_slot";
895+typedef PlayerSubtable<Lua_Texture_Palette_Slot_Name> Lua_Texture_Palette_Slot;
896+
897+int Lua_Texture_Palette_Slot_Clear(lua_State *L)
898+{
899+ int player_index = Lua_Texture_Palette_Slot::PlayerIndex(L, 1);
900+ if (player_index != local_player_index)
901+ return 0;
902+
903+ lua_texture blank = { UNONE, 0 };
904+ lua_texture_palette[Lua_Texture_Palette_Slot::Index(L, 1)] = blank;
905+ return 0;
906+}
907+
908+static int Lua_Texture_Palette_Slot_Get_Collection(lua_State *L)
909+{
910+ int player_index = Lua_Texture_Palette_Slot::PlayerIndex(L, 1);
911+ if (player_index != local_player_index)
912+ return 0;
913+
914+ int index = Lua_Texture_Palette_Slot::Index(L, 1);
915+ if (lua_texture_palette[index].shape == UNONE)
916+ return 0;
917+
918+ lua_pushnumber(L, GET_COLLECTION(GET_DESCRIPTOR_COLLECTION(lua_texture_palette[index].shape)));
919+ return 1;
920+}
921+
922+static int Lua_Texture_Palette_Slot_Get_Texture(lua_State *L)
923+{
924+ int player_index = Lua_Texture_Palette_Slot::PlayerIndex(L, 1);
925+ if (player_index != local_player_index)
926+ return 0;
927+
928+ int index = Lua_Texture_Palette_Slot::Index(L, 1);
929+ if (lua_texture_palette[index].shape == UNONE)
930+ return 0;
931+
932+ lua_pushnumber(L, GET_DESCRIPTOR_SHAPE(lua_texture_palette[index].shape));
933+ return 1;
934+}
935+
936+static int Lua_Texture_Palette_Slot_Get_Type(lua_State *L)
937+{
938+ int player_index = Lua_Texture_Palette_Slot::PlayerIndex(L, 1);
939+ if (player_index != local_player_index)
940+ return 0;
941+
942+ int index = Lua_Texture_Palette_Slot::Index(L, 1);
943+ if (lua_texture_palette[index].shape == UNONE)
944+ return 0;
945+
946+ lua_pushnumber(L, lua_texture_palette[index].type);
947+ return 1;
948+}
949+
950+const luaL_reg Lua_Texture_Palette_Slot_Get[] = {
951+ {"clear", L_TableFunction<Lua_Texture_Palette_Slot_Clear>},
952+ {"collection", Lua_Texture_Palette_Slot_Get_Collection},
953+ {"texture_index", Lua_Texture_Palette_Slot_Get_Texture},
954+ {"type", Lua_Texture_Palette_Slot_Get_Type},
955+ {0, 0}
956+};
957+
958+static int Lua_Texture_Palette_Slot_Set_Collection(lua_State *L)
959+{
960+ int player_index = Lua_Texture_Palette_Slot::PlayerIndex(L, 1);
961+ if (player_index != local_player_index)
962+ return 0;
963+
964+ int16 index = Lua_Texture_Palette_Slot::Index(L, 1);
965+ short collection_index = Lua_Collection::ToIndex(L, 2);
966+
967+ lua_texture_palette[index].shape = BUILD_DESCRIPTOR(collection_index, GET_DESCRIPTOR_SHAPE(lua_texture_palette[index].shape));
968+ return 0;
969+}
970+
971+static int Lua_Texture_Palette_Slot_Set_Texture(lua_State *L)
972+{
973+ int player_index = Lua_Texture_Palette_Slot::PlayerIndex(L, 1);
974+ if (player_index != local_player_index)
975+ return 0;
976+
977+ if (!lua_isnumber(L, 2))
978+ return luaL_error(L, "texture_index: incorrect argument type");
979+
980+ int16 index = Lua_Texture_Palette_Slot::Index(L, 1);
981+ short shape_index = static_cast<short>(lua_tonumber(L, 2));
982+ if (shape_index < 0 || shape_index >= MAXIMUM_SHAPES_PER_COLLECTION)
983+ return luaL_error(L, "texture_index: invalid texture index");
984+
985+ lua_texture_palette[index].shape = BUILD_DESCRIPTOR(GET_DESCRIPTOR_COLLECTION(lua_texture_palette[index].shape), shape_index);
986+ return 0;
987+}
988+
989+static int Lua_Texture_Palette_Slot_Set_Type(lua_State *L)
990+{
991+ int player_index = Lua_Texture_Palette_Slot::PlayerIndex(L, 1);
992+ if (player_index != local_player_index)
993+ return 0;
994+
995+ int16 index = Lua_Texture_Palette_Slot::Index(L, 1);
996+ short texture_type = Lua_TextureType::ToIndex(L, 2);
997+
998+ lua_texture_palette[index].type = texture_type;
999+ return 0;
1000+}
1001+
1002+
1003+const luaL_reg Lua_Texture_Palette_Slot_Set[] = {
1004+ {"collection", Lua_Texture_Palette_Slot_Set_Collection},
1005+ {"texture_index", Lua_Texture_Palette_Slot_Set_Texture},
1006+ {"type", Lua_Texture_Palette_Slot_Set_Type},
1007+ {0, 0}
1008+};
1009+
1010+char Lua_Texture_Palette_Slots_Name[] = "texture_palette_slots";
1011+typedef L_Class<Lua_Texture_Palette_Slots_Name> Lua_Texture_Palette_Slots;
1012+
1013+static int Lua_Texture_Palette_Slots_Get(lua_State *L)
1014+{
1015+ if (lua_isnumber(L, 2))
1016+ {
1017+ int player_index = Lua_Texture_Palette_Slots::Index(L, 1);
1018+ int index = static_cast<int>(lua_tonumber(L, 2));
1019+ if (Lua_Texture_Palette_Slots::Valid(player_index) && index >= 0 && index < lua_texture_palette.size())
1020+ {
1021+ Lua_Texture_Palette_Slot::Push(L, player_index, index);
1022+ }
1023+ else
1024+ {
1025+ lua_pushnil(L);
1026+ }
1027+ }
1028+ else
1029+ {
1030+ lua_pushnil(L);
1031+ }
1032+
1033+ return 1;
1034+}
1035+
1036+static int Lua_Texture_Palette_Slots_Length(lua_State *L)
1037+{
1038+ int player_index = Lua_Texture_Palette_Slots::Index(L, 1);
1039+ if (player_index != local_player_index)
1040+ return 0;
1041+
1042+ lua_pushnumber(L, lua_texture_palette.size());
1043+ return 1;
1044+}
1045+
1046+const luaL_reg Lua_Texture_Palette_Slots_Metatable[] = {
1047+ {"__index", Lua_Texture_Palette_Slots_Get},
1048+ {"__len", Lua_Texture_Palette_Slots_Length},
1049+ {0, 0}
1050+};
1051+
1052+char Lua_Texture_Palette_Name[] = "texture_palette";
1053+typedef L_Class<Lua_Texture_Palette_Name> Lua_Texture_Palette;
1054+
1055+static int Lua_Texture_Palette_Get_Selected(lua_State *L)
1056+{
1057+ int player_index = Lua_Texture_Palette::Index(L, 1);
1058+ if (player_index != local_player_index)
1059+ return 0;
1060+
1061+ if (lua_texture_palette_selected == -1)
1062+ return 0;
1063+
1064+ lua_pushnumber(L, lua_texture_palette_selected);
1065+ return 1;
1066+}
1067+
1068+static int Lua_Texture_Palette_Get_Size(lua_State *L)
1069+{
1070+ int player_index = Lua_Texture_Palette::Index(L, 1);
1071+ if (player_index != local_player_index)
1072+ return 0;
1073+
1074+ lua_pushnumber(L, lua_texture_palette.size());
1075+ return 1;
1076+}
1077+
1078+static int Lua_Texture_Palette_Get_Slots(lua_State *L)
1079+{
1080+ Lua_Texture_Palette_Slots::Push(L, Lua_Texture_Palette::Index(L, 1));
1081+ return 1;
1082+}
1083+
1084+const luaL_reg Lua_Texture_Palette_Get[] = {
1085+ {"highlight", Lua_Texture_Palette_Get_Selected},
1086+ {"size", Lua_Texture_Palette_Get_Size},
1087+ {"slots", Lua_Texture_Palette_Get_Slots},
1088+ {0, 0}
1089+};
1090+
1091+extern void draw_panels();
1092+
1093+static int Lua_Texture_Palette_Set_Selected(lua_State *L)
1094+{
1095+ int player_index = Lua_Texture_Palette::Index(L, 1);
1096+ if (player_index != local_player_index)
1097+ return 0;
1098+
1099+ if (lua_isnil(L, 2))
1100+ lua_texture_palette_selected = -1;
1101+ else if (lua_isnumber(L, 2))
1102+ {
1103+ int selected = static_cast<int>(lua_tonumber(L, 2));
1104+ if (selected < -1 || selected > lua_texture_palette.size())
1105+ return luaL_error(L, "highlight: invalid slot");
1106+
1107+ lua_texture_palette_selected = selected;
1108+ draw_panels();
1109+ }
1110+ else
1111+ return luaL_error(L, "highlight: incorrect argument type");
1112+
1113+ return 0;
1114+}
1115+
1116+
1117+static int Lua_Texture_Palette_Set_Size(lua_State *L)
1118+{
1119+ int player_index = Lua_Texture_Palette::Index(L, 1);
1120+ if (player_index != local_player_index)
1121+ return 0;
1122+
1123+ if (!lua_isnumber(L, 2))
1124+ return luaL_error(L, "size: incorrect argument type");
1125+
1126+ size_t size = static_cast<size_t>(lua_tonumber(L, 2));
1127+ if (size > MAX_TEXTURE_PALETTE_SIZE)
1128+ return luaL_error(L, "size: Its really big");
1129+
1130+ lua_texture blank = { UNONE, 0 };
1131+ lua_texture_palette.resize(size, blank);
1132+ if (lua_texture_palette_selected >= lua_texture_palette.size())
1133+ lua_texture_palette_selected = -1;
1134+
1135+ draw_panels();
1136+ return 0;
1137+}
1138+
1139+const luaL_reg Lua_Texture_Palette_Set[] = {
1140+ {"highlight", Lua_Texture_Palette_Set_Selected},
1141+ {"size", Lua_Texture_Palette_Set_Size},
1142+ {0, 0}
1143+};
1144+
1145+char Lua_WeaponType_Name[] = "weapon_type";
1146+typedef L_Enum<Lua_WeaponType_Name> Lua_WeaponType;
1147+
1148+char Lua_WeaponTypes_Name[] = "WeaponTypes";
1149+typedef L_EnumContainer<Lua_WeaponTypes_Name, Lua_WeaponType> Lua_WeaponTypes;
1150+
1151+char Lua_Player_Weapon_Trigger_Name[] = "player_weapon_trigger";
1152+class Lua_Player_Weapon_Trigger : public PlayerSubtable<Lua_Player_Weapon_Trigger_Name>
1153+{
1154+public:
1155+ int16 m_weapon_index;
1156+
1157+ static Lua_Player_Weapon_Trigger *Push(lua_State *L, int16 player_index, int16 weapon_index, int16 index);
1158+ static int16 WeaponIndex(lua_State *L, int index);
1159+};
1160+
1161+Lua_Player_Weapon_Trigger *Lua_Player_Weapon_Trigger::Push(lua_State *L, int16 player_index, int16 weapon_index, int16 index)
1162+{
1163+ Lua_Player_Weapon_Trigger *t = static_cast<Lua_Player_Weapon_Trigger *>(PlayerSubtable<Lua_Player_Weapon_Trigger_Name>::Push(L, player_index, index));
1164+ if (t)
1165+ {
1166+ t->m_weapon_index = weapon_index;
1167+ }
1168+
1169+ return t;
1170+}
1171+
1172+int16 Lua_Player_Weapon_Trigger::WeaponIndex(lua_State *L, int index)
1173+{
1174+ Lua_Player_Weapon_Trigger *t = static_cast<Lua_Player_Weapon_Trigger*>(lua_touserdata(L, index));
1175+ if (!t) luaL_typerror(L, index, Lua_Player_Weapon_Trigger_Name);
1176+ return t->m_weapon_index;
1177+}
1178+
1179+static int Lua_Player_Weapon_Trigger_Get_Rounds(lua_State *L)
1180+{
1181+ short rounds = get_player_weapon_ammo_count(
1182+ Lua_Player_Weapon_Trigger::PlayerIndex(L, 1),
1183+ Lua_Player_Weapon_Trigger::WeaponIndex(L, 1),
1184+ Lua_Player_Weapon_Trigger::Index(L, 1));
1185+ lua_pushnumber(L, rounds);
1186+ return 1;
1187+}
1188+
1189+const luaL_reg Lua_Player_Weapon_Trigger_Get[] = {
1190+ {"rounds", Lua_Player_Weapon_Trigger_Get_Rounds},
1191+ {0, 0}
1192+};
1193+
1194+char Lua_Player_Weapon_Name[] = "player_weapon";
1195+typedef PlayerSubtable<Lua_Player_Weapon_Name> Lua_Player_Weapon;
1196+
1197+template<int trigger>
1198+static int get_weapon_trigger(lua_State *L)
1199+{
1200+ Lua_Player_Weapon_Trigger::Push(L, Lua_Player_Weapon::PlayerIndex(L, 1), Lua_Player_Weapon::Index(L, 1), trigger);
1201+ return 1;
1202+}
1203+
1204+static int Lua_Player_Weapon_Get_Type(lua_State *L)
1205+{
1206+ Lua_WeaponType::Push(L, Lua_Player_Weapon::Index(L, 1));
1207+ return 1;
1208+}
1209+
1210+extern bool ready_weapon(short player_index, short weapon_index);
1211+
1212+int Lua_Player_Weapon_Select(lua_State *L)
1213+{
1214+ ready_weapon(Lua_Player_Weapon::PlayerIndex(L, 1), Lua_Player_Weapon::Index(L, 1));
1215+ return 0;
1216+}
1217+
1218+const luaL_reg Lua_Player_Weapon_Get[] = {
1219+ {"primary", get_weapon_trigger<_primary_weapon>},
1220+ {"secondary", get_weapon_trigger<_secondary_weapon>},
1221+ {"select", L_TableFunction<Lua_Player_Weapon_Select>},
1222+ {"type", Lua_Player_Weapon_Get_Type},
1223+ {0, 0}
1224+};
1225+
1226+extern player_weapon_data *get_player_weapon_data(const short player_index);
1227+extern bool player_has_valid_weapon(short player_index);
1228+
1229+char Lua_Player_Weapons_Name[] = "player_weapons";
1230+typedef L_Class<Lua_Player_Weapons_Name> Lua_Player_Weapons;
1231+
1232+extern bool can_wield_weapons[MAXIMUM_NUMBER_OF_NETWORK_PLAYERS];
1233+
1234+static int Lua_Player_Weapons_Get(lua_State *L)
1235+{
1236+ int player_index = Lua_Player_Weapons::Index(L, 1);
1237+ bool string_arg = lua_isstring(L, 2) && !lua_isnumber(L, 2);
1238+ if (string_arg && (strcmp(lua_tostring(L, 2), "current") == 0))
1239+ {
1240+ if (player_has_valid_weapon(player_index))
1241+ {
1242+ player_weapon_data *weapon_data = get_player_weapon_data(player_index);
1243+ Lua_Player_Weapon::Push(L, player_index, weapon_data->current_weapon);
1244+ }
1245+ else
1246+ {
1247+ lua_pushnil(L);
1248+ }
1249+ }
1250+ else if (string_arg && (strcmp(lua_tostring(L, 2), "desired") == 0))
1251+ {
1252+ player_weapon_data *weapon_data = get_player_weapon_data(player_index);
1253+ if (weapon_data->desired_weapon != NONE)
1254+ {
1255+ Lua_Player_Weapon::Push(L, player_index, weapon_data->desired_weapon);
1256+ }
1257+ else
1258+ {
1259+ lua_pushnil(L);
1260+ }
1261+ }
1262+ else if (string_arg && (strcmp(lua_tostring(L, 2), "active") == 0))
1263+ {
1264+ lua_pushboolean(L, can_wield_weapons[player_index]);
1265+ }
1266+ else
1267+ {
1268+ int index = Lua_WeaponType::ToIndex(L, 2);
1269+ Lua_Player_Weapon::Push(L, player_index, index);
1270+ }
1271+
1272+ return 1;
1273+}
1274+
1275+static int Lua_Player_Weapons_Length(lua_State *L)
1276+{
1277+ lua_pushnumber(L, MAXIMUM_NUMBER_OF_WEAPONS);
1278+ return 1;
1279+}
1280+
1281+static int Lua_Player_Weapons_Set(lua_State *L)
1282+{
1283+ if (lua_isstring(L, 2) && strcmp(lua_tostring(L, 2), "active") == 0)
1284+ {
1285+ if (!lua_isboolean(L, 3))
1286+ return luaL_error(L, "can_wield: incorrect argument type");
1287+ can_wield_weapons[Lua_Player_Weapons::Index(L, 1)] = lua_toboolean(L, 3);
1288+ return 0;
1289+ }
1290+ else
1291+ return luaL_error(L, "no such index");
1292+}
1293+
1294+const luaL_reg Lua_Player_Weapons_Metatable[] = {
1295+ {"__index", Lua_Player_Weapons_Get},
1296+ {"__newindex", Lua_Player_Weapons_Set},
1297+ {"__len", Lua_Player_Weapons_Length},
1298+ {0, 0}
1299+};
1300+
1301+char Lua_Player_Kills_Name[] = "player_kills";
1302+typedef L_Class<Lua_Player_Kills_Name> Lua_Player_Kills;
1303+
1304+static int Lua_Player_Kills_Get(lua_State *L)
1305+{
1306+ int player_index = Lua_Player_Kills::Index(L, 1);
1307+ int slain_player_index = Lua_Player::Index(L, 2);
1308+
1309+ player_data *slain_player = get_player_data(slain_player_index);
1310+
1311+ lua_pushnumber(L, slain_player->damage_taken[player_index].kills);
1312+ return 1;
1313+}
1314+
1315+static int Lua_Player_Kills_Length(lua_State *L)
1316+{
1317+ lua_pushnumber(L, dynamic_world->player_count);
1318+ return 1;
1319+}
1320+
1321+static int Lua_Player_Kills_Set(lua_State *L)
1322+{
1323+ if (!lua_isnumber(L, 3))
1324+ return luaL_error(L, "kills: incorrect argument type");
1325+
1326+ int player_index = Lua_Player_Kills::Index(L, 1);
1327+ int slain_player_index = Lua_Player::Index(L, 2);
1328+ int kills = static_cast<int>(lua_tonumber(L, 3));
1329+
1330+ player_data *player = get_player_data(player_index);
1331+ player_data *slain_player = get_player_data(slain_player_index);
1332+
1333+ int kills_award = kills - slain_player->damage_taken[player_index].kills;
1334+ if (kills_award)
1335+ {
1336+ slain_player->damage_taken[player_index].kills += kills_award;
1337+ team_damage_taken[slain_player->team].kills += kills_award;
1338+
1339+ if (player_index != slain_player_index)
1340+ {
1341+ player->total_damage_given.kills += kills_award;
1342+ team_damage_given[player->team].kills += kills_award;
1343+ }
1344+ if (slain_player->team == player->team)
1345+ {
1346+ team_friendly_fire[slain_player->team].kills += kills_award;
1347+ }
1348+ mark_player_network_stats_as_dirty(current_player_index);
1349+ }
1350+ return 0;
1351+}
1352+
1353+const luaL_reg Lua_Player_Kills_Metatable[] = {
1354+ {"__index", Lua_Player_Kills_Get},
1355+ {"__newindex", Lua_Player_Kills_Set},
1356+ {"__len", Lua_Player_Kills_Length},
1357+ {0, 0}
1358+};
1359+
1360+char Lua_PlayerColor_Name[] = "player_color";
1361+
1362+char Lua_PlayerColors_Name[] = "PlayerColors";
1363+
1364+char Lua_Player_Name[] = "player";
1365+
1366+// methods
1367+
1368+// accelerate(direction, velocity, vertical_velocity)
1369+int Lua_Player_Accelerate(lua_State *L)
1370+{
1371+ if (!lua_isnumber(L, 2) || !lua_isnumber(L, 3) || !lua_isnumber(L, 4))
1372+ return luaL_error(L, "accelerate: incorrect argument type");
1373+
1374+ player_data *player = get_player_data(Lua_Player::Index(L, 1));
1375+ double direction = static_cast<double>(lua_tonumber(L, 2));
1376+ double velocity = static_cast<double>(lua_tonumber(L, 3));
1377+ double vertical_velocity = static_cast<double>(lua_tonumber(L, 4));
1378+
1379+ accelerate_player(player->monster_index, static_cast<int>(vertical_velocity * WORLD_ONE), static_cast<int>(direction/AngleConvert), static_cast<int>(velocity * WORLD_ONE));
1380+ return 0;
1381+}
1382+
1383+int Lua_Player_Activate_Terminal(lua_State *L)
1384+{
1385+ int16 text_index = NONE;
1386+ if (lua_isnumber(L, 2))
1387+ text_index = static_cast<int16>(lua_tonumber(L, 2));
1388+ else if (Lua_Terminal::Is(L, 2))
1389+ text_index = Lua_Terminal::Index(L, 2);
1390+ else
1391+ return luaL_error(L, "activate_terminal: invalid terminal index");
1392+
1393+ enter_computer_interface(Lua_Player::Index(L, 1), text_index, calculate_level_completion_state());
1394+ return 0;
1395+}
1396+
1397+int Lua_Player_Find_Action_Key_Target(lua_State *L)
1398+{
1399+ // no arguments
1400+ short target_type;
1401+ short object_index = find_action_key_target(Lua_Player::Index(L, 1), MAXIMUM_ACTIVATION_RANGE, &target_type);
1402+
1403+ if (object_index != NONE)
1404+ {
1405+ switch (target_type)
1406+ {
1407+ case _target_is_platform:
1408+ Lua_Platform::Push(L, object_index);
1409+ break;
1410+
1411+ case _target_is_control_panel:
1412+ Lua_Side::Push(L, object_index);
1413+ break;
1414+
1415+ default:
1416+ lua_pushnil(L);
1417+ break;
1418+ }
1419+ }
1420+ else
1421+ {
1422+ lua_pushnil(L);
1423+ }
1424+
1425+ return 1;
1426+}
1427+
1428+extern projectile_definition *get_projectile_definition(short type);
1429+
1430+int Lua_Player_Find_Target(lua_State *L)
1431+{
1432+ // find the origin of projectiles (don't move left/right)
1433+ player_data *player = get_player_data(Lua_Player::Index(L, 1));
1434+ world_point3d origin = player->camera_location;
1435+ world_point3d destination = origin;
1436+
1437+ translate_point3d(&destination, WORLD_ONE, player->facing, player->elevation);
1438+ short old_polygon = get_object_data(player->object_index)->polygon;
1439+ short new_polygon;
1440+ short obstruction_index;
1441+ short line_index;
1442+
1443+ projectile_definition *definition = get_projectile_definition(0);
1444+ bool was_pass_transparent = definition->flags & _usually_pass_transparent_side;
1445+ if (!was_pass_transparent)
1446+ definition->flags |= _usually_pass_transparent_side;
1447+
1448+ // preflight a projectile, 1 WU at a time (because of projectile speed bug)
1449+ uint16 flags = translate_projectile(0, &origin, old_polygon, &destination, &new_polygon, player->monster_index, &obstruction_index, &line_index, true);
1450+
1451+ while (!(flags & _projectile_hit))
1452+ {
1453+ origin = destination;
1454+ old_polygon = new_polygon;
1455+
1456+ translate_point3d(&destination, WORLD_ONE, player->facing, player->elevation);
1457+ flags = translate_projectile(0, &origin, old_polygon, &destination, &new_polygon, player->monster_index, &obstruction_index, &line_index, true);
1458+ }
1459+
1460+ if (!was_pass_transparent)
1461+ definition->flags &= ~_usually_pass_transparent_side;
1462+
1463+ if (flags & _projectile_hit_monster)
1464+ {
1465+ object_data *object = get_object_data(obstruction_index);
1466+ Lua_Monster::Push(L, object->permutation);
1467+ }
1468+ else if (flags & _projectile_hit_floor)
1469+ {
1470+ Lua_Polygon_Floor::Push(L, new_polygon);
1471+ }
1472+ else if (flags & _projectile_hit_media)
1473+ {
1474+ Lua_Polygon::Push(L, new_polygon);
1475+ }
1476+ else if (flags & _projectile_hit_scenery)
1477+ {
1478+ Lua_Scenery::Push(L, obstruction_index);
1479+ }
1480+ else if (obstruction_index != NONE)
1481+ {
1482+ Lua_Polygon_Ceiling::Push(L, new_polygon);
1483+ }
1484+ else
1485+ {
1486+ short side_index = find_adjacent_side(new_polygon, line_index);
1487+ Lua_Side::Push(L, side_index);
1488+ }
1489+
1490+ lua_pushnumber(L, (double) destination.x / WORLD_ONE);
1491+ lua_pushnumber(L, (double) destination.y / WORLD_ONE);
1492+ lua_pushnumber(L, (double) destination.z / WORLD_ONE);
1493+ Lua_Polygon::Push(L, new_polygon);
1494+
1495+ return 5;
1496+}
1497+
1498+
1499+int Lua_Player_Damage(lua_State *L)
1500+{
1501+ int args = lua_gettop(L);
1502+ if (!lua_isnumber(L, 2))
1503+ return luaL_error(L, "damage: incorrect argument type");
1504+
1505+ player_data *player = get_player_data(Lua_Player::Index(L, 1));
1506+ if (PLAYER_IS_DEAD(player) || PLAYER_IS_TOTALLY_DEAD(player))
1507+ return 0;
1508+
1509+ damage_definition damage;
1510+ damage.type = _damage_crushing;
1511+ damage.base = static_cast<int>(lua_tonumber(L, 2));
1512+ damage.random = 0;
1513+ damage.scale = FIXED_ONE;
1514+
1515+ if (args > 2)
1516+ {
1517+ damage.type = Lua_DamageType::ToIndex(L, 3);
1518+ }
1519+
1520+ damage_player(player->monster_index, NONE, NONE, &damage, NONE);
1521+ return 0;
1522+}
1523+
1524+int Lua_Player_Fade_Screen(lua_State *L)
1525+{
1526+ short player_index = Lua_Player::Index(L, 1);
1527+ if (player_index == local_player_index)
1528+ {
1529+ int fade_index = Lua_FadeType::ToIndex(L, 2);
1530+ start_fade(fade_index);
1531+ }
1532+ return 0;
1533+}
1534+
1535+int Lua_Player_Play_Sound(lua_State *L)
1536+{
1537+ int args = lua_gettop(L);
1538+
1539+ int player_index = Lua_Player::Index(L, 1);
1540+ int sound_index = Lua_Sound::ToIndex(L, 2);
1541+ float pitch = 1.0;
1542+ if (args > 2)
1543+ {
1544+ if (lua_isnumber(L, 3))
1545+ pitch = static_cast<float>(lua_tonumber(L, 3));
1546+ else
1547+ return luaL_error(L, "play_sound: incorrect argument type");
1548+ }
1549+
1550+ if (local_player_index != player_index)
1551+ return 0;
1552+
1553+ SoundManager::instance()->PlaySound(sound_index, NULL, NONE, _fixed(FIXED_ONE * pitch));
1554+ return 0;
1555+}
1556+
1557+extern bool mute_lua;
1558+
1559+int Lua_Player_Print(lua_State *L)
1560+{
1561+ if (mute_lua) return 0;
1562+
1563+ if (lua_gettop(L) != 2)
1564+ return luaL_error(L, "print: incorrect argument type");
1565+
1566+ int player_index = Lua_Player::Index(L, 1);
1567+ if (local_player_index == player_index)
1568+ {
1569+ lua_getglobal(L, "tostring");
1570+ lua_insert(L, -2);
1571+ lua_pcall(L, 1, 1, 0);
1572+ if (lua_tostring(L, -1))
1573+ {
1574+ screen_printf("%s", lua_tostring(L, -1));
1575+ }
1576+ lua_pop(L, 1);
1577+ }
1578+
1579+ return 0;
1580+}
1581+
1582+extern struct physics_constants *get_physics_constants_for_model(short physics_model, uint32 action_flags);
1583+extern void instantiate_physics_variables(struct physics_constants *constants, struct physics_variables *variables, short player_index, bool first_time, bool take_action);
1584+
1585+int Lua_Player_Position(lua_State *L)
1586+{
1587+ if (!lua_isnumber(L, 2) || !lua_isnumber(L, 3) || !lua_isnumber(L, 4))
1588+ return luaL_error(L, ("position: incorrect argument type"));
1589+
1590+ int polygon_index = 0;
1591+ if (lua_isnumber(L, 5))
1592+ {
1593+ polygon_index = static_cast<int>(lua_tonumber(L, 5));
1594+ if (!Lua_Polygon::Valid(polygon_index))
1595+ return luaL_error(L, ("position: invalid polygon index"));
1596+ }
1597+ else if (Lua_Polygon::Is(L, 5))
1598+ {
1599+ polygon_index = Lua_Polygon::Index(L, 5);
1600+ }
1601+ else
1602+ return luaL_error(L, ("position: incorrect argument type"));
1603+
1604+ int player_index = Lua_Player::Index(L, 1);
1605+ player_data *player = get_player_data(player_index);
1606+ object_data *object = get_object_data(player->object_index);
1607+
1608+ world_point3d location;
1609+ location.x = static_cast<int>(lua_tonumber(L, 2) * WORLD_ONE);
1610+ location.y = static_cast<int>(lua_tonumber(L, 3) * WORLD_ONE);
1611+ location.z = static_cast<int>(lua_tonumber(L, 4) * WORLD_ONE);
1612+
1613+ translate_map_object(player->object_index, &location, polygon_index);
1614+ player->variables.position.x = WORLD_TO_FIXED(object->location.x);
1615+ player->variables.position.y = WORLD_TO_FIXED(object->location.y);
1616+ player->variables.position.z = WORLD_TO_FIXED(object->location.z);
1617+
1618+ instantiate_physics_variables(get_physics_constants_for_model(static_world->physics_model, 0), &player->variables, player_index, false, false);
1619+ return 0;
1620+}
1621+
1622+int Lua_Player_Teleport(lua_State *L)
1623+{
1624+ if (!lua_isnumber(L, 2) && !Lua_Polygon::Is(L, 2))
1625+ return luaL_error(L, "teleport(): incorrect argument type");
1626+
1627+ int destination = -1;
1628+ if (lua_isnumber(L, 2))
1629+ destination = static_cast<int>(lua_tonumber(L, 2));
1630+ else
1631+ destination = Lua_Polygon::Index(L, 2);
1632+
1633+ int player_index = Lua_Player::Index(L, 1);
1634+
1635+ player_data *player = get_player_data(player_index);
1636+ monster_data *monster = get_monster_data(player->monster_index);
1637+
1638+ SET_PLAYER_TELEPORTING_STATUS(player, true);
1639+ monster->action = _monster_is_teleporting;
1640+ player->teleporting_phase = 0;
1641+ player->delay_before_teleport = 0;
1642+
1643+ player->teleporting_destination = destination;
1644+ if (local_player_index == player_index)
1645+ start_teleporting_effect(true);
1646+ play_object_sound(player->object_index, Sound_TeleportOut());
1647+ return 0;
1648+}
1649+
1650+int Lua_Player_Teleport_To_Level(lua_State *L)
1651+{
1652+ if (!lua_isnumber(L, 2))
1653+ return luaL_error(L, "teleport_to_level(): incorrect argument type");
1654+
1655+ int level = static_cast<int>(lua_tonumber(L, 2));
1656+ int player_index = Lua_Player::Index(L, 1);
1657+
1658+ player_data *player = get_player_data(player_index);
1659+ monster_data *monster = get_monster_data(player->monster_index);
1660+
1661+ SET_PLAYER_TELEPORTING_STATUS(player, true);
1662+ monster->action = _monster_is_teleporting;
1663+ player->teleporting_phase = 0;
1664+ player->delay_before_teleport = 0;
1665+
1666+ player->teleporting_destination = -level - 1;
1667+ if (View_DoInterlevelTeleportOutEffects()) {
1668+ start_teleporting_effect(true);
1669+ play_object_sound(player->object_index, Sound_TeleportOut());
1670+ }
1671+ return 0;
1672+}
1673+
1674+extern short current_player_index;
1675+
1676+int Lua_Player_View_Player(lua_State *L)
1677+{
1678+ int player_index = Lua_Player::Index(L, 1);
1679+ if (player_index != local_player_index)
1680+ return 0;
1681+
1682+ int view_player_index;
1683+ if (lua_isnumber(L, 2))
1684+ {
1685+ view_player_index = static_cast<int>(lua_tonumber(L, 2));
1686+ if (view_player_index < 0 || view_player_index >= dynamic_world->player_count)
1687+ return luaL_error(L, "view_player(): invalid player index");
1688+ }
1689+ else if (Lua_Player::Is(L, 2))
1690+ view_player_index = Lua_Player::Index(L, 2);
1691+ else
1692+ return luaL_error(L, "view_player(): incorrect argument type");
1693+
1694+ if (view_player_index != current_player_index)
1695+ {
1696+ set_current_player_index(view_player_index);
1697+ update_interface(NONE);
1698+ dirty_terminal_view(player_index);
1699+ }
1700+
1701+ return 0;
1702+
1703+}
1704+
1705+// get accessors
1706+
1707+static int Lua_Player_Get_Action_Flags(lua_State *L)
1708+{
1709+ Lua_Action_Flags::Push(L, Lua_Player::Index(L, 1));
1710+ return 1;
1711+}
1712+
1713+static int Lua_Player_Get_Color(lua_State *L)
1714+{
1715+ Lua_PlayerColor::Push(L, get_player_data(Lua_Player::Index(L, 1))->color);
1716+ return 1;
1717+}
1718+
1719+static int Lua_Player_Get_Compass(lua_State *L)
1720+{
1721+ Lua_Player_Compass::Push(L, Lua_Player::Index(L, 1));
1722+ return 1;
1723+}
1724+
1725+static int Lua_Player_Get_Crosshairs(lua_State *L)
1726+{
1727+ Lua_Crosshairs::Push(L, Lua_Player::Index(L, 1));
1728+ return 1;
1729+}
1730+
1731+static int Lua_Player_Get_Dead(lua_State *L)
1732+{
1733+ player_data *player = get_player_data(Lua_Player::Index(L, 1));
1734+ lua_pushboolean(L, (PLAYER_IS_DEAD(player) || PLAYER_IS_TOTALLY_DEAD(player)));
1735+ return 1;
1736+}
1737+
1738+static int Lua_Player_Get_Deaths(lua_State *L)
1739+{
1740+ player_data *player = get_player_data(Lua_Player::Index(L, 1));
1741+ lua_pushnumber(L, player->monster_damage_taken.kills);
1742+ return 1;
1743+}
1744+
1745+static int Lua_Player_Get_Energy(lua_State *L)
1746+{
1747+ lua_pushnumber(L, get_player_data(Lua_Player::Index(L, 1))->suit_energy);
1748+ return 1;
1749+}
1750+
1751+static int Lua_Player_Get_Elevation(lua_State *L)
1752+{
1753+ double angle = FIXED_INTEGERAL_PART(get_player_data(Lua_Player::Index(L, 1))->variables.elevation) * AngleConvert;
1754+ lua_pushnumber(L, angle);
1755+ return 1;
1756+}
1757+
1758+static int Lua_Player_Get_Direction(lua_State *L)
1759+{
1760+ double angle = FIXED_INTEGERAL_PART(get_player_data(Lua_Player::Index(L, 1))->variables.direction) * AngleConvert;
1761+ lua_pushnumber(L, angle);
1762+ return 1;
1763+}
1764+
1765+static int Lua_Player_Get_External_Velocity(lua_State *L)
1766+{
1767+ Lua_ExternalVelocity::Push(L, Lua_Player::Index(L, 1));
1768+ return 1;
1769+}
1770+
1771+static int Lua_Player_Get_Extravision_Duration(lua_State *L)
1772+{
1773+ lua_pushnumber(L, get_player_data(Lua_Player::Index(L, 1))->extravision_duration);
1774+ return 1;
1775+}
1776+
1777+template<uint16 flag>
1778+static int Lua_Player_Get_Flag(lua_State *L)
1779+{
1780+ player_data *player = get_player_data(Lua_Player::Index(L, 1));
1781+ lua_pushboolean(L, player->variables.flags & flag);
1782+ return 1;
1783+}
1784+
1785+static int Lua_Player_Get_Infravision_Duration(lua_State *L)
1786+{
1787+ lua_pushnumber(L, get_player_data(Lua_Player::Index(L, 1))->infravision_duration);
1788+ return 1;
1789+}
1790+
1791+static int Lua_Player_Get_Internal_Velocity(lua_State *L)
1792+{
1793+ Lua_InternalVelocity::Push(L, Lua_Player::Index(L, 1));
1794+ return 1;
1795+}
1796+
1797+static int Lua_Player_Get_Invincibility_Duration(lua_State *L)
1798+{
1799+ lua_pushnumber(L, get_player_data(Lua_Player::Index(L, 1))->invincibility_duration);
1800+ return 1;
1801+}
1802+
1803+static int Lua_Player_Get_Invisibility_Duration(lua_State *L)
1804+{
1805+ lua_pushnumber(L, get_player_data(Lua_Player::Index(L, 1))->invisibility_duration);
1806+ return 1;
1807+}
1808+
1809+static int Lua_Player_Get_Items(lua_State *L)
1810+{
1811+ Lua_Player_Items::Push(L, Lua_Player::Index(L, 1));
1812+ return 1;
1813+}
1814+
1815+static int Lua_Player_Get_Kills(lua_State *L)
1816+{
1817+ Lua_Player_Kills::Push(L, Lua_Player::Index(L, 1));
1818+ return 1;
1819+}
1820+
1821+static int Lua_Player_Get_Local(lua_State *L)
1822+{
1823+ lua_pushboolean(L, Lua_Player::Index(L, 1) == local_player_index);
1824+ return 1;
1825+}
1826+
1827+extern bool MotionSensorActive;
1828+
1829+static int Lua_Player_Get_Motion_Sensor(lua_State *L)
1830+{
1831+ short player_index = Lua_Player::Index(L, 1);
1832+ if (player_index == local_player_index)
1833+ {
1834+ lua_pushboolean(L, MotionSensorActive);
1835+ return 1;
1836+ }
1837+ else
1838+ {
1839+ return 0;
1840+ }
1841+}
1842+
1843+static int Lua_Player_Get_Monster(lua_State *L)
1844+{
1845+ Lua_Monster::Push(L, get_player_data(Lua_Player::Index(L, 1))->monster_index);
1846+ return 1;
1847+}
1848+
1849+static int Lua_Player_Get_Name(lua_State *L)
1850+{
1851+ lua_pushstring(L, get_player_data(Lua_Player::Index(L, 1))->name);
1852+ return 1;
1853+}
1854+
1855+static int Lua_Player_Get_Netdead(lua_State *L)
1856+{
1857+ lua_pushboolean(L, get_player_data(Lua_Player::Index(L, 1))->netdead);
1858+ return 1;
1859+}
1860+
1861+static int Lua_Player_Get_Overlays(lua_State *L)
1862+{
1863+ Lua_Overlays::Push(L, Lua_Player::Index(L, 1));
1864+ return 1;
1865+}
1866+
1867+static int Lua_Player_Get_Oxygen(lua_State *L)
1868+{
1869+ lua_pushnumber(L, get_player_data(Lua_Player::Index(L, 1))->suit_oxygen);
1870+ return 1;
1871+}
1872+
1873+static int Lua_Player_Get_Points(lua_State *L)
1874+{
1875+ lua_pushnumber(L, get_player_data(Lua_Player::Index(L, 1))->netgame_parameters[0]);
1876+ return 1;
1877+}
1878+
1879+static int Lua_Player_Get_Polygon(lua_State *L)
1880+{
1881+ Lua_Polygon::Push(L, get_player_data(Lua_Player::Index(L, 1))->supporting_polygon_index);
1882+ return 1;
1883+}
1884+
1885+static int Lua_Player_Get_Team(lua_State *L)
1886+{
1887+ Lua_PlayerColor::Push(L, get_player_data(Lua_Player::Index(L, 1))->team);
1888+ return 1;
1889+}
1890+
1891+static int Lua_Player_Get_Texture_Palette(lua_State *L)
1892+{
1893+ Lua_Texture_Palette::Push(L, Lua_Player::Index(L, 1));
1894+ return 1;
1895+}
1896+
1897+static int Lua_Player_Get_Weapons(lua_State *L)
1898+{
1899+ Lua_Player_Weapons::Push(L, Lua_Player::Index(L, 1));
1900+ return 1;
1901+}
1902+
1903+static int Lua_Player_Get_X(lua_State *L)
1904+{
1905+ lua_pushnumber(L, (double) get_player_data(Lua_Player::Index(L, 1))->location.x / WORLD_ONE);
1906+ return 1;
1907+}
1908+
1909+static int Lua_Player_Get_Y(lua_State *L)
1910+{
1911+ lua_pushnumber(L, (double) get_player_data(Lua_Player::Index(L, 1))->location.y / WORLD_ONE);
1912+ return 1;
1913+}
1914+
1915+static int Lua_Player_Get_Z(lua_State *L)
1916+{
1917+ lua_pushnumber(L, (double) get_player_data(Lua_Player::Index(L, 1))->location.z / WORLD_ONE);
1918+ return 1;
1919+}
1920+
1921+static int Lua_Player_Get_Zoom(lua_State *L)
1922+{
1923+ short player_index = Lua_Player::Index(L, 1);
1924+ if (player_index == local_player_index)
1925+ {
1926+ lua_pushboolean(L, GetTunnelVision());
1927+ return 1;
1928+ }
1929+ else
1930+ {
1931+ return 0;
1932+ }
1933+}
1934+
1935+const luaL_reg Lua_Player_Get[] = {
1936+ {"accelerate", L_TableFunction<Lua_Player_Accelerate>},
1937+ {"action_flags", Lua_Player_Get_Action_Flags},
1938+ {"activate_terminal", L_TableFunction<Lua_Player_Activate_Terminal>},
1939+ {"color", Lua_Player_Get_Color},
1940+ {"compass", Lua_Player_Get_Compass},
1941+ {"crosshairs", Lua_Player_Get_Crosshairs},
1942+ {"damage", L_TableFunction<Lua_Player_Damage>},
1943+ {"dead", Lua_Player_Get_Dead},
1944+ {"deaths", Lua_Player_Get_Deaths},
1945+ {"direction", Lua_Player_Get_Direction},
1946+ {"disconnected", Lua_Player_Get_Netdead},
1947+ {"energy", Lua_Player_Get_Energy},
1948+ {"elevation", Lua_Player_Get_Elevation},
1949+ {"external_velocity", Lua_Player_Get_External_Velocity},
1950+ {"extravision_duration", Lua_Player_Get_Extravision_Duration},
1951+ {"feet_below_media", Lua_Player_Get_Flag<_FEET_BELOW_MEDIA_BIT>},
1952+ {"fade_screen", L_TableFunction<Lua_Player_Fade_Screen>},
1953+ {"find_action_key_target", L_TableFunction<Lua_Player_Find_Action_Key_Target>},
1954+ {"find_target", L_TableFunction<Lua_Player_Find_Target>},
1955+ {"head_below_media", Lua_Player_Get_Flag<_HEAD_BELOW_MEDIA_BIT>},
1956+ {"infravision_duration", Lua_Player_Get_Infravision_Duration},
1957+ {"internal_velocity", Lua_Player_Get_Internal_Velocity},
1958+ {"invincibility_duration", Lua_Player_Get_Invincibility_Duration},
1959+ {"invisibility_duration", Lua_Player_Get_Invisibility_Duration},
1960+ {"items", Lua_Player_Get_Items},
1961+ {"local_", Lua_Player_Get_Local},
1962+ {"juice", Lua_Player_Get_Energy},
1963+ {"kills", Lua_Player_Get_Kills},
1964+ {"life", Lua_Player_Get_Energy},
1965+ {"monster", Lua_Player_Get_Monster},
1966+ {"motion_sensor_active", Lua_Player_Get_Motion_Sensor},
1967+ {"name", Lua_Player_Get_Name},
1968+ {"overlays", Lua_Player_Get_Overlays},
1969+ {"oxygen", Lua_Player_Get_Oxygen},
1970+ {"pitch", Lua_Player_Get_Elevation},
1971+ {"print", L_TableFunction<Lua_Player_Print>},
1972+ {"play_sound", L_TableFunction<Lua_Player_Play_Sound>},
1973+ {"points", Lua_Player_Get_Points},
1974+ {"polygon", Lua_Player_Get_Polygon},
1975+ {"position", L_TableFunction<Lua_Player_Position>},
1976+ {"team", Lua_Player_Get_Team},
1977+ {"teleport", L_TableFunction<Lua_Player_Teleport>},
1978+ {"teleport_to_level", L_TableFunction<Lua_Player_Teleport_To_Level>},
1979+ {"texture_palette", Lua_Player_Get_Texture_Palette},
1980+ {"view_player", L_TableFunction<Lua_Player_View_Player>},
1981+ {"weapons", Lua_Player_Get_Weapons},
1982+ {"x", Lua_Player_Get_X},
1983+ {"y", Lua_Player_Get_Y},
1984+ {"yaw", Lua_Player_Get_Direction},
1985+ {"z", Lua_Player_Get_Z},
1986+ {"zoom_active", Lua_Player_Get_Zoom},
1987+ {0, 0}
1988+};
1989+
1990+extern void mark_shield_display_as_dirty();
1991+
1992+static int Lua_Player_Set_Color(lua_State *L)
1993+{
1994+ int color = Lua_PlayerColor::ToIndex(L, 2);
1995+ get_player_data(Lua_Player::Index(L, 1))->color = color;
1996+
1997+ return 0;
1998+}
1999+
2000+static int Lua_Player_Set_Deaths(lua_State *L)
2001+{
2002+ if (!lua_isnumber(L, 2))
2003+ return luaL_error(L, "deaths: incorrect argument type");
2004+
2005+ player_data *player = get_player_data(Lua_Player::Index(L, 1));
2006+ int kills = static_cast<int>(lua_tonumber(L, 2));
2007+ if (player->monster_damage_taken.kills != kills)
2008+ {
2009+ team_monster_damage_taken[player->team].kills += (kills - player->monster_damage_taken.kills);
2010+ player->monster_damage_taken.kills = kills;
2011+ mark_player_network_stats_as_dirty(current_player_index);
2012+ }
2013+
2014+ return 0;
2015+}
2016+
2017+static int Lua_Player_Set_Direction(lua_State *L)
2018+{
2019+ if (!lua_isnumber(L, 2))
2020+ return luaL_error(L, "direction: incorrect argument type");
2021+
2022+ double facing = static_cast<double>(lua_tonumber(L, 2));
2023+ int player_index = Lua_Player::Index(L, 1);
2024+ player_data *player = get_player_data(player_index);
2025+ player->variables.direction = INTEGER_TO_FIXED((int)(facing/AngleConvert));
2026+ instantiate_physics_variables(get_physics_constants_for_model(static_world->physics_model, 0), &player->variables, player_index, false, false);
2027+ return 0;
2028+}
2029+
2030+static int Lua_Player_Set_Elevation(lua_State *L)
2031+{
2032+ if (!lua_isnumber(L, 2))
2033+ return luaL_error(L, "elevation: incorrect argument type");
2034+
2035+ double elevation = static_cast<double>(lua_tonumber(L, 2));
2036+ if (elevation > 180) elevation -= 360.0;
2037+ int player_index = Lua_Player::Index(L, 1);
2038+ player_data *player = get_player_data(player_index);
2039+ player->variables.elevation = INTEGER_TO_FIXED((int)(elevation/AngleConvert));
2040+ instantiate_physics_variables(get_physics_constants_for_model(static_world->physics_model, 0), &player->variables, player_index, false, false);
2041+ return 0;
2042+}
2043+
2044+static int Lua_Player_Set_Infravision_Duration(lua_State *L)
2045+{
2046+ if (!lua_isnumber(L, 2))
2047+ return luaL_error(L, "extravision: incorrect argument type");
2048+
2049+ player_data *player = get_player_data(Lua_Player::Index(L, 1));
2050+ player->infravision_duration = static_cast<int>(lua_tonumber(L, 2));
2051+ return 0;
2052+}
2053+
2054+static int Lua_Player_Set_Invincibility_Duration(lua_State *L)
2055+{
2056+ if (!lua_isnumber(L, 2))
2057+ return luaL_error(L, "extravision: incorrect argument type");
2058+
2059+ player_data *player = get_player_data(Lua_Player::Index(L, 1));
2060+ player->invincibility_duration = static_cast<int>(lua_tonumber(L, 2));
2061+ return 0;
2062+}
2063+
2064+static int Lua_Player_Set_Invisibility_Duration(lua_State *L)
2065+{
2066+ if (!lua_isnumber(L, 2))
2067+ return luaL_error(L, "extravision: incorrect argument type");
2068+
2069+ player_data *player = get_player_data(Lua_Player::Index(L, 1));
2070+ player->invisibility_duration = static_cast<int>(lua_tonumber(L, 2));
2071+ return 0;
2072+}
2073+
2074+static int Lua_Player_Set_Energy(lua_State *L)
2075+{
2076+ if (!lua_isnumber(L, 2))
2077+ return luaL_error(L, "energy: incorrect argument type");
2078+
2079+ int energy = static_cast<int>(lua_tonumber(L, 2));
2080+ if (energy > 3 * PLAYER_MAXIMUM_SUIT_ENERGY)
2081+ energy = 3 * PLAYER_MAXIMUM_SUIT_ENERGY;
2082+
2083+ get_player_data(Lua_Player::Index(L, 1))->suit_energy = energy;
2084+ mark_shield_display_as_dirty();
2085+
2086+ return 0;
2087+}
2088+
2089+static int Lua_Player_Set_Extravision_Duration(lua_State *L)
2090+{
2091+ if (!lua_isnumber(L, 2))
2092+ return luaL_error(L, "extravision: incorrect argument type");
2093+
2094+ int player_index = Lua_Player::Index(L, 1);
2095+ player_data *player = get_player_data(player_index);
2096+ short extravision_duration = static_cast<short>(lua_tonumber(L, 2));
2097+ if ((player_index == local_player_index) && (extravision_duration == 0) != (player->extravision_duration == 0))
2098+ {
2099+ start_extravision_effect(extravision_duration);
2100+ }
2101+ player->extravision_duration = static_cast<int>(lua_tonumber(L, 2));
2102+ return 0;
2103+}
2104+
2105+static int Lua_Player_Set_Motion_Sensor(lua_State *L)
2106+{
2107+ short player_index = Lua_Player::Index(L, 1);
2108+ if (player_index == local_player_index)
2109+ {
2110+ if (!lua_isboolean(L, 2))
2111+ return luaL_error(L, "motion_sensor: incorrect argument type");
2112+ bool state = lua_toboolean(L, 2);
2113+ if (MotionSensorActive != state)
2114+ {
2115+ MotionSensorActive = lua_toboolean(L, 2);
2116+ draw_panels();
2117+ }
2118+ }
2119+
2120+ return 0;
2121+}
2122+
2123+static int Lua_Player_Set_Oxygen(lua_State *L)
2124+{
2125+ if (!lua_isnumber(L, 2))
2126+ return luaL_error(L, "oxygen: incorrect argument type");
2127+
2128+ int oxygen = static_cast<int>(lua_tonumber(L, 2));
2129+ if (oxygen > PLAYER_MAXIMUM_SUIT_OXYGEN)
2130+ oxygen = PLAYER_MAXIMUM_SUIT_OXYGEN;
2131+
2132+ get_player_data(Lua_Player::Index(L, 1))->suit_oxygen = oxygen;
2133+ mark_shield_display_as_dirty();
2134+
2135+ return 0;
2136+}
2137+
2138+static int Lua_Player_Set_Points(lua_State *L)
2139+{
2140+ if (!lua_isnumber(L, 2))
2141+ return luaL_error(L, "points: incorrect argument type");
2142+
2143+ int points = static_cast<int>(lua_tonumber(L, 2));
2144+
2145+ player_data *player = get_player_data(Lua_Player::Index(L, 1));
2146+ if (player->netgame_parameters[0] != points)
2147+ {
2148+#if !defined(DISABLE_NETWORKING)
2149+ team_netgame_parameters[player->team][0] += points - player->netgame_parameters[0];
2150+#endif
2151+ player->netgame_parameters[0] = points;
2152+ mark_player_network_stats_as_dirty(current_player_index);
2153+ }
2154+
2155+ return 0;
2156+}
2157+
2158+static int Lua_Player_Set_Team(lua_State *L)
2159+{
2160+ int team = Lua_PlayerColor::ToIndex(L, 2);
2161+ get_player_data(Lua_Player::Index(L, 1))->team = team;
2162+
2163+ return 0;
2164+}
2165+
2166+static int Lua_Player_Set_Zoom(lua_State *L)
2167+{
2168+ short player_index = Lua_Player::Index(L, 1);
2169+ if (player_index == local_player_index)
2170+ {
2171+ if (!lua_isboolean(L, 2))
2172+ return luaL_error(L, "zoom_active: incorrect argument type");
2173+
2174+ SetTunnelVision(lua_toboolean(L, 2));
2175+ }
2176+
2177+ return 0;
2178+}
2179+
2180+const luaL_reg Lua_Player_Set[] = {
2181+ {"color", Lua_Player_Set_Color},
2182+ {"deaths", Lua_Player_Set_Deaths},
2183+ {"direction", Lua_Player_Set_Direction},
2184+ {"elevation", Lua_Player_Set_Elevation},
2185+ {"energy", Lua_Player_Set_Energy},
2186+ {"extravision_duration", Lua_Player_Set_Extravision_Duration},
2187+ {"infravision_duration", Lua_Player_Set_Infravision_Duration},
2188+ {"invincibility_duration", Lua_Player_Set_Invincibility_Duration},
2189+ {"invisibility_duration", Lua_Player_Set_Invisibility_Duration},
2190+ {"juice", Lua_Player_Set_Energy},
2191+ {"life", Lua_Player_Set_Energy},
2192+ {"motion_sensor_active", Lua_Player_Set_Motion_Sensor},
2193+ {"oxygen", Lua_Player_Set_Oxygen},
2194+ {"pitch", Lua_Player_Set_Elevation},
2195+ {"points", Lua_Player_Set_Points},
2196+ {"team", Lua_Player_Set_Team},
2197+ {"yaw", Lua_Player_Set_Direction},
2198+ {"zoom_active", Lua_Player_Set_Zoom},
2199+ {0, 0}
2200+};
2201+
2202+bool Lua_Player_Valid(int16 index)
2203+{
2204+ return index >= 0 && index < dynamic_world->player_count;
2205+}
2206+
2207+char Lua_Players_Name[] = "Players";
2208+
2209+int Lua_Players_Print(lua_State *L)
2210+{
2211+ if (mute_lua) return 0;
2212+
2213+ if (lua_gettop(L) != 1)
2214+ return luaL_error(L, "print: incorrect argument type");
2215+
2216+ lua_getglobal(L, "tostring");
2217+ lua_insert(L, -2);
2218+ lua_pcall(L, 1, 1, 0);
2219+ if (lua_tostring(L, -1))
2220+ {
2221+ screen_printf("%s", lua_tostring(L, -1));
2222+ }
2223+ lua_pop(L, 1);
2224+
2225+ return 0;
2226+}
2227+
2228+
2229+const luaL_reg Lua_Players_Methods[] = {
2230+ {"print", Lua_Players_Print},
2231+ {0, 0}
2232+};
2233+
2234+int16 Lua_Players_Length() {
2235+ return dynamic_world->player_count;
2236+}
2237+
2238+char Lua_DifficultyType_Name[] = "difficulty_type";
2239+typedef L_Enum<Lua_DifficultyType_Name> Lua_DifficultyType;
2240+
2241+char Lua_DifficultyTypes_Name[] = "DifficultyTypes";
2242+typedef L_EnumContainer<Lua_DifficultyTypes_Name, Lua_DifficultyType> Lua_DifficultyTypes;
2243+
2244+char Lua_GameType_Name[] = "game_type";
2245+typedef L_Enum<Lua_GameType_Name> Lua_GameType;
2246+
2247+char Lua_GameTypes_Name[] = "GameTypes";
2248+typedef L_EnumContainer<Lua_GameTypes_Name, Lua_GameType> Lua_GameTypes;
2249+
2250+char Lua_Game_Name[] = "Game";
2251+typedef L_Class<Lua_Game_Name> Lua_Game;
2252+
2253+char Lua_ScoringMode_Name[] = "scoring_mode";
2254+typedef L_Enum<Lua_ScoringMode_Name> Lua_ScoringMode;
2255+
2256+char Lua_ScoringModes_Name[] = "ScoringModes";
2257+typedef L_Container<Lua_ScoringModes_Name, Lua_ScoringMode> Lua_ScoringModes;
2258+
2259+static int Lua_Game_Get_Difficulty(lua_State *L)
2260+{
2261+ Lua_DifficultyType::Push(L, dynamic_world->game_information.difficulty_level);
2262+ return 1;
2263+}
2264+
2265+static int Lua_Game_Get_Kill_Limit(lua_State *L)
2266+{
2267+ lua_pushnumber(L, dynamic_world->game_information.kill_limit);
2268+ return 1;
2269+}
2270+
2271+static int Lua_Game_Get_Monsters_Replenish(lua_State* L)
2272+{
2273+ lua_pushboolean(L, dynamic_world->game_information.game_options & _monsters_replenish);
2274+ return 1;
2275+}
2276+
2277+static int Lua_Game_Get_Proper_Item_Accounting(lua_State* L)
2278+{
2279+ lua_pushboolean(L, L_Get_Proper_Item_Accounting(L));
2280+ return 1;
2281+}
2282+
2283+static int Lua_Game_Get_Time_Remaining(lua_State* L)
2284+{
2285+ if(dynamic_world->game_information.game_time_remaining > 999 * 30)
2286+ lua_pushnil(L);
2287+ else
2288+ lua_pushnumber(L, dynamic_world->game_information.game_time_remaining);
2289+ return 1;
2290+}
2291+
2292+static int Lua_Game_Get_Ticks(lua_State *L)
2293+{
2294+ lua_pushnumber(L, dynamic_world->tick_count);
2295+ return 1;
2296+}
2297+
2298+static int Lua_Game_Get_Type(lua_State *L)
2299+{
2300+ Lua_GameType::Push(L, GET_GAME_TYPE());
2301+ return 1;
2302+}
2303+
2304+extern int game_end_condition;
2305+extern int game_scoring_mode;
2306+
2307+static int Lua_Game_Get_Scoring_Mode(lua_State *L)
2308+{
2309+ Lua_ScoringMode::Push(L, game_scoring_mode);
2310+ return 1;
2311+}
2312+
2313+static int Lua_Game_Get_Version(lua_State *L)
2314+{
2315+ lua_pushstring(L, A1_DATE_VERSION);
2316+ return 1;
2317+}
2318+
2319+static int Lua_Game_Set_Proper_Item_Accounting(lua_State* L)
2320+{
2321+ if (!lua_isboolean(L, 2))
2322+ luaL_error(L, "proper_item_accounting: incorrect argument type");
2323+ L_Set_Proper_Item_Accounting(L, lua_toboolean(L, 2));
2324+ return 0;
2325+}
2326+
2327+static int Lua_Game_Set_Scoring_Mode(lua_State *L)
2328+{
2329+ int mode = Lua_ScoringMode::ToIndex(L, 2);
2330+ game_scoring_mode = mode;
2331+ // TODO: set network stats to dirty
2332+ return 0;
2333+}
2334+
2335+static int Lua_Game_Set_Monsters_Replenish(lua_State* L)
2336+{
2337+ if (!lua_isboolean(L, 2))
2338+ luaL_error(L, "monsters_replenish: incorrect argument type");
2339+
2340+ bool replenish = lua_toboolean(L, 2);
2341+ if (replenish)
2342+ {
2343+ dynamic_world->game_information.game_options |= _monsters_replenish;
2344+ }
2345+ else
2346+ {
2347+ dynamic_world->game_information.game_options &= ~_monsters_replenish;
2348+ }
2349+ return 0;
2350+}
2351+
2352+static int Lua_Game_Set_Over(lua_State *L)
2353+{
2354+ if(lua_isnil(L, 2)) game_end_condition = _game_normal_end_condition;
2355+ else game_end_condition = lua_toboolean(L, 2) ? _game_end_now_condition : _game_no_end_condition;
2356+ return 0;
2357+}
2358+
2359+extern GM_Random lua_random_generator;
2360+
2361+int Lua_Game_Better_Random(lua_State *L)
2362+{
2363+ if (lua_isnumber(L, 1))
2364+ {
2365+ lua_pushnumber(L, lua_random_generator.KISS() % static_cast<uint32>(lua_tonumber(L, 1)));
2366+ }
2367+ else
2368+ {
2369+ lua_pushnumber(L, lua_random_generator.KISS());
2370+ }
2371+ return 1;
2372+}
2373+
2374+int Lua_Game_Global_Random(lua_State *L)
2375+{
2376+ if (lua_isnumber(L, 1))
2377+ {
2378+ lua_pushnumber(L, ::global_random() % static_cast<uint16>(lua_tonumber(L, 1)));
2379+ }
2380+ else
2381+ {
2382+ lua_pushnumber(L, ::global_random());
2383+ }
2384+ return 1;
2385+}
2386+
2387+int Lua_Game_Local_Random(lua_State *L)
2388+{
2389+ if (lua_isnumber(L, 1))
2390+ {
2391+ lua_pushnumber(L, ::local_random() % static_cast<uint16>(lua_tonumber(L, 1)));
2392+ }
2393+ else
2394+ {
2395+ lua_pushnumber(L, ::local_random());
2396+ }
2397+ return 1;
2398+}
2399+
2400+int Lua_Game_Save(lua_State *L)
2401+{
2402+ if (!game_is_networked)
2403+ save_game();
2404+
2405+ return 0;
2406+}
2407+
2408+extern int L_Restore_Passed(lua_State *);
2409+extern int L_Restore_Saved(lua_State *);
2410+
2411+const luaL_reg Lua_Game_Get[] = {
2412+ {"difficulty", Lua_Game_Get_Difficulty},
2413+ {"global_random", L_TableFunction<Lua_Game_Global_Random>},
2414+ {"kill_limit", Lua_Game_Get_Kill_Limit},
2415+ {"time_remaining", Lua_Game_Get_Time_Remaining},
2416+ {"local_random", L_TableFunction<Lua_Game_Local_Random>},
2417+ {"monsters_replenish", Lua_Game_Get_Monsters_Replenish},
2418+ {"proper_item_accounting", Lua_Game_Get_Proper_Item_Accounting},
2419+ {"random", L_TableFunction<Lua_Game_Better_Random>},
2420+ {"restore_passed", L_TableFunction<L_Restore_Passed>},
2421+ {"restore_saved", L_TableFunction<L_Restore_Saved>},
2422+ {"ticks", Lua_Game_Get_Ticks},
2423+ {"type", Lua_Game_Get_Type},
2424+ {"save", L_TableFunction<Lua_Game_Save>},
2425+ {"scoring_mode", Lua_Game_Get_Scoring_Mode},
2426+ {"version", Lua_Game_Get_Version},
2427+ {0, 0}
2428+};
2429+
2430+const luaL_reg Lua_Game_Set[] = {
2431+ {"monsters_replenish", Lua_Game_Set_Monsters_Replenish},
2432+ {"proper_item_accounting", Lua_Game_Set_Proper_Item_Accounting},
2433+ {"scoring_mode", Lua_Game_Set_Scoring_Mode},
2434+ {"over", Lua_Game_Set_Over},
2435+ {0, 0}
2436+};
2437+
2438+char Lua_Music_Name[] = "Music";
2439+typedef L_Class<Lua_Music_Name> Lua_Music;
2440+
2441+int Lua_Music_Clear(lua_State *L)
2442+{
2443+ Music::instance()->ClearLevelMusic();
2444+ return 0;
2445+}
2446+
2447+int Lua_Music_Fade(lua_State *L)
2448+{
2449+ int duration;
2450+ if (!lua_isnumber(L, 1))
2451+ duration = 1000;
2452+ else
2453+ duration = static_cast<int>(lua_tonumber(L, 1) * 1000);
2454+ Music::instance()->FadeOut(duration);
2455+ Music::instance()->ClearLevelMusic();
2456+ return 0;
2457+}
2458+
2459+int Lua_Music_Play(lua_State *L)
2460+{
2461+ bool restart_music;
2462+ restart_music = !Music::instance()->IsLevelMusicActive() && !Music::instance()->Playing();
2463+ for (int n = 1; n <= lua_gettop(L); n++)
2464+ {
2465+ if (!lua_isstring(L, n))
2466+ return luaL_error(L, "play: invalid file specifier");
2467+
2468+ std::string search_path = L_Get_Search_Path(L);
2469+
2470+ FileSpecifier file;
2471+ if (search_path.size())
2472+ {
2473+ if (!file.SetNameWithPath(lua_tostring(L, n), search_path))
2474+ Music::instance()->PushBackLevelMusic(file);
2475+ }
2476+ else
2477+ {
2478+ if (file.SetNameWithPath(lua_tostring(L, n)))
2479+ Music::instance()->PushBackLevelMusic(file);
2480+ }
2481+ }
2482+
2483+ if (restart_music)
2484+ Music::instance()->PreloadLevelMusic();
2485+ return 0;
2486+}
2487+
2488+int Lua_Music_Stop(lua_State *L)
2489+{
2490+ Music::instance()->ClearLevelMusic();
2491+ Music::instance()->StopLevelMusic();
2492+
2493+ return 0;
2494+}
2495+
2496+int Lua_Music_Valid(lua_State* L) {
2497+ int top = lua_gettop(L);
2498+ for(int n = 1; n <= top; n++) {
2499+ if(!lua_isstring(L, n))
2500+ return luaL_error(L, "valid: invalid file specifier");
2501+ FileSpecifier path;
2502+ if(path.SetNameWithPath(lua_tostring(L, n))) {
2503+ StreamDecoder* stream = StreamDecoder::Get(path);
2504+ if(stream) {
2505+ lua_pushboolean(L, true);
2506+ delete stream;
2507+ } else lua_pushboolean(L, false);
2508+ } else lua_pushboolean(L, false);
2509+ }
2510+ return top;
2511+}
2512+
2513+const luaL_reg Lua_Music_Get[] = {
2514+ {"clear", L_TableFunction<Lua_Music_Clear>},
2515+ {"fade", L_TableFunction<Lua_Music_Fade>},
2516+ {"play", L_TableFunction<Lua_Music_Play>},
2517+ {"stop", L_TableFunction<Lua_Music_Stop>},
2518+ {"valid", L_TableFunction<Lua_Music_Valid>},
2519+ {0, 0}
2520+};
2521+
2522+static void Lua_Player_load_compatibility(lua_State *L);
2523+
2524+int Lua_Player_register (lua_State *L)
2525+{
2526+ Lua_Action_Flags::Register(L, Lua_Action_Flags_Get, Lua_Action_Flags_Set);
2527+
2528+ Lua_Camera_Path_Angles::Register(L, Lua_Camera_Path_Angles_Get);
2529+ Lua_Camera_Path_Points::Register(L, Lua_Camera_Path_Points_Get);
2530+ Lua_Camera::Register(L, Lua_Camera_Get);
2531+ Lua_Camera::Valid = Lua_Camera_Valid;
2532+
2533+ Lua_Cameras::Register(L, Lua_Cameras_Methods);
2534+ Lua_Cameras::Length = Lua_Cameras_Length;
2535+
2536+ Lua_Crosshairs::Register(L, Lua_Crosshairs_Get, Lua_Crosshairs_Set);
2537+ Lua_Player_Compass::Register(L, Lua_Player_Compass_Get, Lua_Player_Compass_Set);
2538+ Lua_Player_Items::Register(L, 0, 0, Lua_Player_Items_Metatable);
2539+ Lua_Player_Kills::Register(L, 0, 0, Lua_Player_Kills_Metatable);
2540+
2541+ Lua_InternalVelocity::Register(L, Lua_InternalVelocity_Get);
2542+ Lua_ExternalVelocity::Register(L, Lua_ExternalVelocity_Get, Lua_ExternalVelocity_Set);
2543+ Lua_FadeType::Register(L, 0, 0, 0, Lua_FadeType_Mnemonics);
2544+ Lua_FadeType::Valid = Lua_FadeType::ValidRange(NUMBER_OF_FADE_TYPES);
2545+
2546+ Lua_FadeTypes::Register(L);
2547+ Lua_FadeTypes::Length = Lua_FadeTypes::ConstantLength((int16) NUMBER_OF_FADE_TYPES);
2548+
2549+ Lua_Texture_Palette_Slot::Register(L, Lua_Texture_Palette_Slot_Get, Lua_Texture_Palette_Slot_Set);
2550+ Lua_Texture_Palette_Slots::Register(L, 0, 0, Lua_Texture_Palette_Slots_Metatable);
2551+ Lua_Texture_Palette::Register(L, Lua_Texture_Palette_Get, Lua_Texture_Palette_Set);
2552+
2553+ Lua_WeaponType::Register(L, 0, 0, 0, Lua_WeaponType_Mnemonics);
2554+ Lua_WeaponType::Valid = Lua_WeaponType::ValidRange(MAXIMUM_NUMBER_OF_WEAPONS);
2555+
2556+ Lua_WeaponTypes::Register(L);
2557+ Lua_WeaponTypes::Length = Lua_WeaponTypes::ConstantLength((int16) MAXIMUM_NUMBER_OF_WEAPONS);
2558+
2559+ Lua_Player_Weapon::Register(L, Lua_Player_Weapon_Get);
2560+ Lua_Player_Weapon::Valid = Lua_Player_Weapon::ValidRange(MAXIMUM_NUMBER_OF_WEAPONS);
2561+
2562+ Lua_Player_Weapons::Register(L, 0, 0, Lua_Player_Weapons_Metatable);
2563+ Lua_Player_Weapons::Valid = Lua_Player_Valid;
2564+
2565+ Lua_Player_Weapon_Trigger::Register(L, Lua_Player_Weapon_Trigger_Get);
2566+ Lua_Player_Weapon_Trigger::Valid = Lua_Player_Weapon_Trigger::ValidRange((int) _secondary_weapon + 1);
2567+
2568+ Lua_OverlayColor::Register(L, 0, 0, 0, Lua_OverlayColor_Mnemonics);
2569+ Lua_OverlayColor::Valid = Lua_OverlayColor::ValidRange(8);
2570+
2571+ Lua_Overlays::Register(L, 0, 0, Lua_Overlays_Metatable);
2572+ Lua_Overlays::Valid = Lua_Player_Valid;
2573+
2574+ Lua_Overlay::Register(L, Lua_Overlay_Get, Lua_Overlay_Set);
2575+ Lua_Overlay::Valid = Lua_Overlay::ValidRange(MAXIMUM_NUMBER_OF_SCRIPT_HUD_ELEMENTS);
2576+
2577+ Lua_PlayerColor::Register(L, 0, 0, 0, Lua_PlayerColor_Mnemonics);
2578+ Lua_PlayerColor::Valid = Lua_PlayerColor::ValidRange(NUMBER_OF_TEAM_COLORS);
2579+
2580+ Lua_PlayerColors::Register(L);
2581+ Lua_PlayerColors::Length = Lua_PlayerColors::ConstantLength((int16) NUMBER_OF_TEAM_COLORS);
2582+
2583+ Lua_Player::Register(L, Lua_Player_Get, Lua_Player_Set);
2584+ Lua_Player::Valid = Lua_Player_Valid;
2585+
2586+ Lua_Players::Register(L, Lua_Players_Methods);
2587+ Lua_Players::Length = Lua_Players_Length;
2588+
2589+ Lua_Game::Register(L, Lua_Game_Get, Lua_Game_Set);
2590+
2591+ Lua_GameType::Register(L, 0, 0, 0, Lua_GameType_Mnemonics);
2592+ Lua_GameType::Valid = Lua_GameType::ValidRange(NUMBER_OF_GAME_TYPES);
2593+
2594+ Lua_GameTypes::Register(L);
2595+ Lua_GameTypes::Length = Lua_GameTypes::ConstantLength(NUMBER_OF_GAME_TYPES);
2596+
2597+ Lua_ScoringMode::Register(L, 0, 0, 0, Lua_ScoringMode_Mnemonics);
2598+ Lua_ScoringMode::Valid = Lua_ScoringMode::ValidRange(NUMBER_OF_GAME_SCORING_MODES);
2599+
2600+ Lua_ScoringModes::Register(L);
2601+ Lua_ScoringModes::Length = Lua_ScoringModes::ConstantLength(NUMBER_OF_GAME_SCORING_MODES);
2602+
2603+ Lua_DifficultyType::Register(L, 0, 0, 0, Lua_DifficultyType_Mnemonics);
2604+ Lua_DifficultyType::Valid = Lua_DifficultyType::ValidRange(NUMBER_OF_GAME_DIFFICULTY_LEVELS);
2605+
2606+ Lua_DifficultyTypes::Register(L);
2607+ Lua_DifficultyTypes::Length = Lua_DifficultyTypes::ConstantLength(NUMBER_OF_GAME_DIFFICULTY_LEVELS);
2608+
2609+ Lua_TextureType::Register(L, 0, 0, 0, Lua_TextureType_Mnemonics);
2610+ Lua_TextureType::Valid = Lua_TextureType::ValidRange(NUMBER_OF_LUA_TEXTURE_TYPES);
2611+
2612+ Lua_TextureTypes::Register(L);
2613+ Lua_TextureTypes::Length = Lua_TextureTypes::ConstantLength(NUMBER_OF_LUA_TEXTURE_TYPES);
2614+
2615+ Lua_Music::Register(L, Lua_Music_Get);
2616+
2617+ // register one Game userdatum globally
2618+ Lua_Game::Push(L, 0);
2619+ lua_setglobal(L, Lua_Game_Name);
2620+
2621+ // register one Music userdatum
2622+ Lua_Music::Push(L, 0);
2623+ lua_setglobal(L, Lua_Music_Name);
2624+
2625+ Lua_Player_load_compatibility(L);
2626+
2627+ return 0;
2628+}
2629+
2630+static const char *compatibility_script = ""
2631+ "function accelerate_player(player, vertical_velocity, direction, velocity) Players[player]:accelerate(direction, velocity, vertical_velocity) end\n"
2632+ "function activate_camera(player, camera) Cameras[camera]:activate(player) end\n"
2633+ "function activate_terminal(player, text) Players[player]:activate_terminal(text) end\n"
2634+ "function add_item(player, item_type) Players[player].items[item_type] = Players[player].items[item_type] + 1 end\n"
2635+ "function add_path_angle(camera, yaw, pitch, time) Cameras[camera].path_angles:new(yaw, pitch, time) end\n"
2636+ "function add_path_point(camera, polygon, x, y, z, time) Cameras[camera].path_points:new(x, y, z, polygon, time) end\n"
2637+ "function award_kills(player, slain_player, amount) if player == -1 then Players[slain_player].deaths = Players[slain_player].deaths + amount else Players[player].kills[slain_player] = Players[player].kills[slain_player] + amount end end\n"
2638+ "function add_to_player_external_velocity(player, x, y, z) Players[player].external_velocity.i = Players[player].external_velocity.i + x Players[player].external_velocity.j = Players[player].external_velocity.j + y Players[player].external_velocity.k = Players[player].external_velocity.k + z end\n"
2639+ "function award_points(player, amount) Players[player].points = Players[player].points + amount end\n"
2640+ "function better_random() return Game.random() end\n"
2641+ "function clear_camera(camera) Cameras[camera]:clear() end\n"
2642+ "function clear_music() Music.clear() end\n"
2643+ "function count_item(player, item_type) return Players[player].items[item_type] end\n"
2644+ "function create_camera() return Cameras.new().index end\n"
2645+"function crosshairs_active(player) return 0 end\n" // Players[player].crosshairs.active end\n"
2646+ "function deactivate_camera(camera) Cameras[camera]:deactivate() end\n"
2647+ "function destroy_ball(player) for i in ItemTypes() do if i.ball then Players[player].items[i] = 0 end end end\n"
2648+ "function fade_music(duration) if duration then Music.fade(duration * 60 / 1000) else Music.fade(60 / 1000) end end\n"
2649+ "function get_game_difficulty() return Game.difficulty.index end\n"
2650+ "function get_game_type() return Game.type.index end\n"
2651+ "function get_kills(player, slain_player) if player == -1 then return Players[slain_player].deaths else return Players[player].kills[slain_player] end end\n"
2652+ "function get_kill_limit() return Game.kill_limit end\n"
2653+ "function get_life(player) return Players[player].energy end\n"
2654+ "function get_motion_sensor_state(player) return Players[player].motion_sensor_active end\n"
2655+ "function get_oxygen(player) return Players[player].oxygen end\n"
2656+ "function get_player_angle(player) return Players[player].yaw, Players[player].pitch end\n"
2657+ "function get_player_color(player) return Players[player].color.index end\n"
2658+ "function get_player_external_velocity(player) return Players[player].external_velocity.i * 1024, Players[player].external_velocity.j * 1024, Players[player].external_velocity.k * 1024 end\n"
2659+ "function get_player_internal_velocity(player) return Players[player].internal_velocity.forward * 65536, Players[player].internal_velocity.perpendicular * 65536 end\n"
2660+ "function get_player_name(player) return Players[player].name end\n"
2661+ "function get_player_polygon(player) return Players[player].polygon.index end\n"
2662+ "function get_player_position(player) return Players[player].x, Players[player].y, Players[player].z end\n"
2663+ "function get_player_powerup_duration(player, powerup) if powerup == _powerup_invisibility then return Players[player].invisibility_duration elseif powerup == _powerup_invincibility then return Players[player].invincibility_duration elseif powerup == _powerup_infravision then return Players[player].infravision_duratiohn elseif powerup == _powerup_extravision then return Players[player].extravision_duration end end\n"
2664+ "function get_player_team(player) return Players[player].team.index end\n"
2665+ "function get_player_weapon(player) if Players[player].weapons.current then return Players[player].weapons.current.index else return nil end end\n"
2666+ "function get_points(player) return Players[player].points end\n"
2667+ "function global_random() return Game.global_random() end\n"
2668+ "function inflict_damage(player, amount, type) if (type) then Players[player]:damage(amount, type) else Players[player]:damage(amount) end end\n"
2669+ "function local_player_index() for p in Players() do if p.local_ then return p.index end end end\n"
2670+ "function local_random() return Game.local_random() end\n"
2671+ "function number_of_players() return # Players end\n"
2672+ "function play_music(...) Music.play(...) end\n"
2673+ "function player_is_dead(player) return Players[player].dead end\n"
2674+ "function player_media(player) if Players[player].head_below_media then return Players[player].polygon.media.index else return nil end end\n"
2675+ "function player_to_monster_index(player) return Players[player].monster.index end\n"
2676+ "function play_sound(player, sound, pitch) Players[player]:play_sound(sound, pitch) end\n"
2677+ "function remove_item(player, item_type) if Players[player].items[item_type] > 0 then Players[player].items[item_type] = Players[player].items[item_type] - 1 end end\n"
2678+ "function screen_fade(player, fade) if fade then Players[player]:fade_screen(fade) else for p in Players() do p:fade_screen(player) end end end\n"
2679+ "function screen_print(player, message) if message then if Players[player] then Players[player]:print(message) end else Players.print(player) end end\n"
2680+ "function select_weapon(player, weapon) Players[player].weapons[weapon]:select() end\n"
2681+ "function set_crosshairs_state(player, state) Players[player].crosshairs.active = state end\n"
2682+ "function set_kills(player, slain_player, amount) if player == -1 then Players[slain_player].deaths = amount else Players[player].kills[slain_player] = amount end end\n"
2683+ "function set_life(player, shield) Players[player].energy = shield end\n"
2684+ "function set_lua_compass_beacon(player, x, y) Players[player].compass.x = x Players[player].compass.y = y end\n"
2685+ "function set_lua_compass_state(player, state) if state > 15 then Players[player].compass.beacon = true state = state % 16 else Players[player].compass.beacon = false end if state > 7 then Players[player].compass.se = true state = state - 8 else Players[player].compass.se = false end if state > 3 then Players[player].compass.sw = true state = state - 4 else Players[player].compass.sw = false end if state > 1 then Players[player].compass.ne = true state = state - 2 else Players[player].compass.ne = false end if state == 1 then Players[player].compass.nw = true else Players[player].compass.nw = false end end\n"
2686+ "function set_motion_sensor_state(player, state) Players[player].motion_sensor_active = state end\n"
2687+ "function set_overlay_color(overlay, color) for p in Players() do if p.local_ then p.overlays[overlay].color = color end end end\n"
2688+ "function set_overlay_icon(overlay, icon) for p in Players() do if p.local_ then p.overlays[overlay].icon = icon end end end\n"
2689+ "function set_overlay_icon_by_color(overlay, color) for p in Players() do if p.local_ then p.overlays[overlay]:fill_icon(color) end end end\n"
2690+ "function set_overlay_text(overlay, text) for p in Players() do if p.local_ then p.overlays[overlay].text = text end end end\n"
2691+ "function set_oxygen(player, oxygen) Players[player].oxygen = oxygen end\n"
2692+ "function set_player_angle(player, yaw, pitch) Players[player].yaw = yaw Players[player].pitch = pitch + 360.0 end\n"
2693+ "function set_player_color(player, color) Players[player].color = color end\n"
2694+ "function set_player_external_velocity(player, x, y, z) Players[player].external_velocity.i = x / 1024 Players[player].external_velocity.j = y / 1024 Players[player].external_velocity.k = z / 1024 end\n"
2695+ "function set_player_position(player, x, y, z, polygon) Players[player]:position(x, y, z, polygon) end\n"
2696+ "function set_player_powerup_duration(player, powerup, duration) if powerup == _powerup_invisibility then Players[player].invisibility_duration = duration elseif powerup == _powerup_invincibility then Players[player].invincibility_duration = duration elseif powerup == _powerup_infravision then Players[player].infravision_duration = duration elseif powerup == _powerup_extravision then Players[player].extravision_duration = duration end end\n"
2697+ "function set_player_team(player, team) Players[player].team = team end\n"
2698+ "function set_points(player, amount) Players[player].points = amount end\n"
2699+ "function stop_music() Music.stop() end\n"
2700+ "function set_zoom_state(player, state) Players[player].zoom_active = state end\n"
2701+ "function teleport_player(player, polygon) Players[player]:teleport(polygon) end\n"
2702+ "function teleport_player_to_level(player, level) Players[player]:teleport_to_level(level) end\n"
2703+ "function use_lua_compass(player, state) if state ~= nil then Players[player].compass.lua = state else for p in Players() do p.compass.lua = player end end end\n"
2704+ "function zoom_active(player) return Players[player].zoom_active end\n"
2705+ ;
2706+
2707+static void Lua_Player_load_compatibility(lua_State *L)
2708+{
2709+ luaL_loadbuffer(L, compatibility_script, strlen(compatibility_script), "player_compatibility");
2710+ lua_pcall(L, 0, 0, 0);
2711+};
2712+
2713+#endif
--- marathon/trunk/Source_Files/RenderOther/images.cpp (revision 499)
+++ marathon/trunk/Source_Files/RenderOther/images.cpp (revision 500)
@@ -1,1690 +1,1704 @@
1-/*
2- images.c
3-
4- Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
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- Thursday, July 20, 1995 3:29:30 PM- rdm created.
22-
23-Feb. 4, 2000 (Loren Petrich):
24- Changed halt() to assert(false) for better debugging
25-
26-Feb. 5, 2000 (Loren Petrich):
27- Better handling of case of no scenario-file resource fork
28-
29-Aug 21, 2000 (Loren Petrich):
30- Added object-oriented file handling
31-
32- LoadedResource handles are assumed to always be locked,
33- and HLock() and HUnlock() have been suppressed for that reason.
34-
35-Jul 6, 2001 (Loren Petrich):
36- Added Thomas Herzog's changes for loading Win32-version image chunks
37-
38-Jan 25, 2002 (Br'fin (Jeremy Parsons)):
39- Added TARGET_API_MAC_CARBON for Quicktime.h
40-
41-Jul 31, 2002 (Loren Petrich)
42- Added text-resource access in analogy with others' image- and sound-resource access;
43- this is for supporting the M2-Win95 file format
44- */
45-
46-#include "cseries.h"
47-#include "FileHandler.h"
48-
49-#include <stdlib.h>
50-
51-#if defined(mac)
52-#if defined(EXPLICIT_CARBON_HEADER)
53-# include <quicktime/Quicktime.h>
54-#else
55-# include <Movies.h>
56-#endif
57-#endif
58-
59-#include "interface.h"
60-#include "shell.h"
61-#include "images.h"
62-#include "screen.h"
63-#include "wad.h"
64-#include "screen_drawing.h"
65-#include "Logging.h"
66-
67-#include "render.h"
68-#include "OGL_Render.h"
69-#include "OGL_Blitter.h"
70-
71-
72-// Constants
73-enum {
74- _images_file_delta16= 1000,
75- _images_file_delta32= 2000,
76- _scenario_file_delta16= 10000,
77- _scenario_file_delta32= 20000
78-};
79-
80-// Structure for open image file
81-class image_file_t {
82-public:
83- image_file_t() {}
84- ~image_file_t() {close_file();}
85-
86- bool open_file(FileSpecifier &file);
87- void close_file(void);
88- bool is_open(void);
89-
90- int determine_pict_resource_id(int base_id, int delta16, int delta32);
91-
92- bool has_pict(int id);
93- bool has_clut(int id);
94-
95- bool get_pict(int id, LoadedResource &rsrc);
96- bool get_clut(int id, LoadedResource &rsrc);
97- bool get_snd(int id, LoadedResource &rsrc);
98- bool get_text(int id, LoadedResource &rsrc);
99-
100-private:
101- bool has_rsrc(uint32 rsrc_type, uint32 wad_type, int id);
102- bool get_rsrc(uint32 rsrc_type, uint32 wad_type, int id, LoadedResource &rsrc);
103-
104- bool make_rsrc_from_pict(void *data, size_t length, LoadedResource &rsrc, void *clut_data, size_t clut_length);
105- bool make_rsrc_from_clut(void *data, size_t length, LoadedResource &rsrc);
106-
107- OpenedResourceFile rsrc_file;
108- OpenedFile wad_file;
109- wad_header wad_hdr;
110-};
111-
112-#ifdef mac
113-// M2/Win picture structures (do not use in portable code)
114-typedef struct pict_head {
115- screen_rectangle bounds; /* screen_rectangle from screen_drawing.h */
116- short depth; /* 8 or 16 */
117- /* pixel data follows here */
118-} pict_head;
119-
120-typedef struct clut_record {
121- short count;
122- short unknown;
123- short id;
124- rgb_color colors[256]; /* rgb_color from cscluts.h */
125-} clut_record;
126-#endif
127-
128-// Global variables
129-static image_file_t ImagesFile;
130-static image_file_t ScenarioFile;
131-
132-// Prototypes
133-static void shutdown_images_handler(void);
134-static void draw_picture(LoadedResource &PictRsrc);
135-
136-
137-#include <SDL_endian.h>
138-
139-#ifdef HAVE_SDL_IMAGE_H
140-#include <SDL_image.h>
141-#endif
142-
143-#include "byte_swapping.h"
144-#include "screen_drawing.h"
145-
146-
147-// From screen_sdl.cpp
148-extern short interface_bit_depth;
149-
150-// From screen_drawing_sdl.cpp
151-extern bool draw_clip_rect_active;
152-extern screen_rectangle draw_clip_rect;
153-
154-
155-/*
156- * Uncompress picture data, returns size of compressed image data that was read
157- */
158-
159-// Uncompress (and endian-correct) scan line compressed by PackBits RLE algorithm
160-template <class T>
161-static const uint8 *unpack_bits(const uint8 *src, int row_bytes, T *dst)
162-{
163- // Read source count
164- int src_count;
165- if (row_bytes > 250) {
166- src_count = (src[0] << 8) | src[1];
167- src += 2;
168- } else
169- src_count = *src++;
170-
171- while (src_count > 0) {
172-
173- // Read flag/count byte
174- int c = (int8)*src++;
175- src_count--;
176- if (c < 0) {
177-
178- // RLE compressed run
179- int size = -c + 1;
180- T data;
181- if (sizeof(T) == 1) {
182- data = *src++;
183- src_count--;
184- } else {
185- data = (src[0] << 8) | src[1];
186- src += 2;
187- src_count -= 2;
188- }
189- for (int i=0; i<size; i++)
190- *dst++ = data;
191-
192- } else {
193-
194- // Uncompressed run
195- int size = c + 1;
196- for (int i=0; i<size; i++) {
197- T data;
198- if (sizeof(T) == 1) {
199- data = *src++;
200- src_count--;
201- } else {
202- data = (src[0] << 8) | src[1];
203- src += 2;
204- src_count -= 2;
205- }
206- *dst++ = data;
207- }
208- }
209- }
210- return src;
211-}
212-
213-// 8-bit picture, one scan line at a time
214-static int uncompress_rle8(const uint8 *src, int row_bytes, uint8 *dst, int dst_pitch, int height)
215-{
216- const uint8 *start = src;
217- for (int y=0; y<height; y++) {
218- src = unpack_bits(src, row_bytes, dst);
219- dst += dst_pitch;
220- }
221- return static_cast<int>(src - start);
222-}
223-
224-// 16-bit picture, one scan line at a time, 16-bit chunks
225-static int uncompress_rle16(const uint8 *src, int row_bytes, uint8 *dst, int dst_pitch, int height)
226-{
227- const uint8 *start = src;
228- for (int y=0; y<height; y++) {
229- src = unpack_bits(src, row_bytes, (uint16 *)dst);
230- dst += dst_pitch;
231- }
232- return static_cast<int>(src - start);
233-}
234-
235-static void copy_component_into_surface(const uint8 *src, uint8 *dst, int count, int component)
236-{
237-#ifdef ALEPHONE_LITTLE_ENDIAN
238- dst += 2 - component;
239-#else
240- dst += component + 1;
241-#endif
242- while (count--) {
243- *dst = *src++;
244- dst += 4;
245- }
246-}
247-
248-// 32-bit picture, one scan line, one component at a time
249-static int uncompress_rle32(const uint8 *src, int row_bytes, uint8 *dst, int dst_pitch, int height)
250-{
251- uint8 *tmp = (uint8 *)malloc(row_bytes);
252- if (tmp == NULL)
253- return -1;
254-
255- const uint8 *start = src;
256-
257- int width = row_bytes / 4;
258- for (int y=0; y<height; y++) {
259- src = unpack_bits(src, row_bytes, tmp);
260-
261- // "tmp" now contains "width" bytes of red, followed by "width"
262- // bytes of green and "width" bytes of blue, so we have to copy them
263- // into the surface in the right order
264- copy_component_into_surface(tmp, dst, width, 0);
265- copy_component_into_surface(tmp + width, dst, width, 1);
266- copy_component_into_surface(tmp + width * 2, dst, width, 2);
267-
268- dst += dst_pitch;
269- }
270-
271- free(tmp);
272-
273- return static_cast<int>(src - start);
274-}
275-
276-static int uncompress_picture(const uint8 *src, int row_bytes, uint8 *dst, int dst_pitch, int depth, int height, int pack_type)
277-{
278- // Depths <8 have to be color expanded to depth 8 after uncompressing,
279- // so we uncompress into a temporary buffer
280- uint8 *orig_dst = dst;
281- int orig_dst_pitch = dst_pitch;
282- if (depth < 8) {
283- dst = (uint8 *)malloc(row_bytes * height);
284- dst_pitch = row_bytes;
285- if (dst == NULL)
286- return -1;
287- }
288-
289- int data_size = 0;
290-
291- if (row_bytes < 8) {
292-
293- // Uncompressed data
294- const uint8 *p = src;
295- uint8 *q = dst;
296- for (int y=0; y<height; y++) {
297- memcpy(q, p, MIN(row_bytes, dst_pitch));
298- p += row_bytes;
299- q += dst_pitch;
300- }
301- data_size = row_bytes * height;
302-
303- } else {
304-
305- // Compressed data
306- if (depth <= 8) {
307-
308- // Indexed color
309- if (pack_type == 1)
310- goto no_packing;
311- data_size = uncompress_rle8(src, row_bytes, dst, dst_pitch, height);
312-
313- } else {
314-
315- // Direct color
316- if (pack_type == 0) {
317- if (depth == 16)
318- pack_type = 3;
319- else if (depth == 32)
320- pack_type = 4;
321-
322- }
323- switch (pack_type) {
324- case 1: { // No packing
325-no_packing: const uint8 *p = src;
326- uint8 *q = dst;
327- for (int y=0; y<height; y++) {
328- memcpy(q, p, MIN(row_bytes, dst_pitch));
329- p += row_bytes;
330- q += dst_pitch;
331- }
332- data_size = row_bytes * height;
333- if (depth == 16)
334- byte_swap_memory(dst, _2byte, dst_pitch * height / 2);
335- else if (depth == 32)
336- byte_swap_memory(dst, _4byte, dst_pitch * height / 4);
337- break;
338- }
339- case 3: // Run-length encoding by 16-bit chunks
340- data_size = uncompress_rle16(src, row_bytes, dst, dst_pitch, height);
341- break;
342- case 4: // Run-length encoding one component at a time
343- data_size = uncompress_rle32(src, row_bytes, dst, dst_pitch, height);
344- break;
345- default:
346- fprintf(stderr, "Unimplemented packing type %d (depth %d) in PICT resource\n", pack_type, depth);
347- data_size = -1;
348- break;
349- }
350- }
351- }
352-
353- // Color expansion 1/2/4->8 bits
354- if (depth < 8) {
355- const uint8 *p = dst;
356- uint8 *q = orig_dst;
357-
358- // Source and destination may have different alignment restrictions,
359- // don't run off the right of either
360- int x_max = row_bytes;
361- while (x_max * 8 / depth > orig_dst_pitch)
362- x_max--;
363-
364- switch (depth) {
365- case 1:
366- for (int y=0; y<height; y++) {
367- for (int x=0; x<x_max; x++) {
368- uint8 b = p[x];
369- q[x*8+0] = (b & 0x80) ? 0x01 : 0x00;
370- q[x*8+1] = (b & 0x40) ? 0x01 : 0x00;
371- q[x*8+2] = (b & 0x20) ? 0x01 : 0x00;
372- q[x*8+3] = (b & 0x10) ? 0x01 : 0x00;
373- q[x*8+4] = (b & 0x08) ? 0x01 : 0x00;
374- q[x*8+5] = (b & 0x04) ? 0x01 : 0x00;
375- q[x*8+6] = (b & 0x02) ? 0x01 : 0x00;
376- q[x*8+7] = (b & 0x01) ? 0x01 : 0x00;
377- }
378- p += row_bytes;
379- q += orig_dst_pitch;
380- }
381- break;
382- case 2:
383- for (int y=0; y<height; y++) {
384- for (int x=0; x<x_max; x++) {
385- uint8 b = p[x];
386- q[x*4+0] = (b >> 6) & 0x03;
387- q[x*4+1] = (b >> 4) & 0x03;
388- q[x*4+2] = (b >> 2) & 0x03;
389- q[x*4+3] = b & 0x03;
390- }
391- p += row_bytes;
392- q += orig_dst_pitch;
393- }
394- break;
395- case 4:
396- for (int y=0; y<height; y++) {
397- for (int x=0; x<x_max; x++) {
398- uint8 b = p[x];
399- q[x*2+0] = (b >> 4) & 0x0f;
400- q[x*2+1] = b & 0x0f;
401- }
402- p += row_bytes;
403- q += orig_dst_pitch;
404- }
405- break;
406- }
407- free(dst);
408- }
409-
410- return data_size;
411-}
412-
413-int get_pict_header_width(LoadedResource &rsrc)
414-{
415- SDL_RWops *p = SDL_RWFromMem(rsrc.GetPointer(), (int) rsrc.GetLength());
416- if (p)
417- {
418- SDL_RWseek(p, 8, SEEK_CUR);
419- int width = SDL_ReadBE16(p);
420- SDL_RWclose(p);
421- return width;
422- }
423- return -1;
424-}
425-
426-/*
427- * Convert picture resource to SDL surface
428- */
429-
430-SDL_Surface *picture_to_surface(LoadedResource &rsrc)
431-{
432- if (!rsrc.IsLoaded())
433- return NULL;
434-
435- SDL_Surface *s = NULL;
436-
437- // Open stream to picture resource
438- SDL_RWops *p = SDL_RWFromMem(rsrc.GetPointer(), (int)rsrc.GetLength());
439- if (p == NULL)
440- return NULL;
441- SDL_RWseek(p, 6, SEEK_CUR); // picSize/top/left
442- int pic_height = SDL_ReadBE16(p);
443- int pic_width = SDL_ReadBE16(p);
444- //printf("pic_width %d, pic_height %d\n", pic_width, pic_height);
445-
446- // Read and parse picture opcodes
447- bool done = false;
448- while (!done) {
449- uint16 opcode = SDL_ReadBE16(p);
450- //printf("%04x\n", opcode);
451- switch (opcode) {
452-
453- case 0x0000: // NOP
454- case 0x0011: // VersionOp
455- case 0x001c: // HiliteMode
456- case 0x001e: // DefHilite
457- case 0x0038: // FrameSameRect
458- case 0x0039: // PaintSameRect
459- case 0x003a: // EraseSameRect
460- case 0x003b: // InvertSameRect
461- case 0x003c: // FillSameRect
462- case 0x02ff: // Version
463- break;
464-
465- case 0x00ff: // OpEndPic
466- done = true;
467- break;
468-
469- case 0x0001: { // Clipping region
470- uint16 size = SDL_ReadBE16(p);
471- if (size & 1)
472- size++;
473- SDL_RWseek(p, size - 2, SEEK_CUR);
474- break;
475- }
476-
477- case 0x0003: // TxFont
478- case 0x0004: // TxFace
479- case 0x0005: // TxMode
480- case 0x0008: // PnMode
481- case 0x000d: // TxSize
482- case 0x0015: // PnLocHFrac
483- case 0x0016: // ChExtra
484- case 0x0023: // ShortLineFrom
485- case 0x00a0: // ShortComment
486- SDL_RWseek(p, 2, SEEK_CUR);
487- break;
488-
489- case 0x0006: // SpExtra
490- case 0x0007: // PnSize
491- case 0x000b: // OvSize
492- case 0x000c: // Origin
493- case 0x000e: // FgColor
494- case 0x000f: // BgColor
495- case 0x0021: // LineFrom
496- SDL_RWseek(p, 4, SEEK_CUR);
497- break;
498-
499- case 0x001a: // RGBFgCol
500- case 0x001b: // RGBBkCol
501- case 0x001d: // HiliteColor
502- case 0x001f: // OpColor
503- case 0x0022: // ShortLine
504- SDL_RWseek(p, 6, SEEK_CUR);
505- break;
506-
507- case 0x0002: // BkPat
508- case 0x0009: // PnPat
509- case 0x000a: // FillPat
510- case 0x0010: // TxRatio
511- case 0x0020: // Line
512- case 0x0030: // FrameRect
513- case 0x0031: // PaintRect
514- case 0x0032: // EraseRect
515- case 0x0033: // InvertRect
516- case 0x0034: // FillRect
517- SDL_RWseek(p, 8, SEEK_CUR);
518- break;
519-
520- case 0x0c00: // HeaderOp
521- SDL_RWseek(p, 24, SEEK_CUR);
522- break;
523-
524- case 0x00a1: { // LongComment
525- SDL_RWseek(p, 2, SEEK_CUR);
526- int size = SDL_ReadBE16(p);
527- if (size & 1)
528- size++;
529- SDL_RWseek(p, size, SEEK_CUR);
530- break;
531- }
532-
533- case 0x0098: // Packed CopyBits
534- case 0x0099: // Packed CopyBits with clipping region
535- case 0x009a: // Direct CopyBits
536- case 0x009b: { // Direct CopyBits with clipping region
537- // 1. PixMap
538- if (opcode == 0x009a || opcode == 0x009b)
539- SDL_RWseek(p, 4, SEEK_CUR); // pmBaseAddr
540- uint16 row_bytes = SDL_ReadBE16(p); // the upper 2 bits are flags
541- //printf(" row_bytes %04x\n", row_bytes);
542- bool is_pixmap = ((row_bytes & 0x8000) != 0);
543- row_bytes &= 0x3fff;
544- uint16 top = SDL_ReadBE16(p);
545- uint16 left = SDL_ReadBE16(p);
546- uint16 height = SDL_ReadBE16(p) - top;
547- uint16 width = SDL_ReadBE16(p) - left;
548- uint16 pack_type, pixel_size;
549- if (is_pixmap) {
550- SDL_RWseek(p, 2, SEEK_CUR); // pmVersion
551- pack_type = SDL_ReadBE16(p);
552- SDL_RWseek(p, 14, SEEK_CUR); // packSize/hRes/vRes/pixelType
553- pixel_size = SDL_ReadBE16(p);
554- SDL_RWseek(p, 16, SEEK_CUR); // cmpCount/cmpSize/planeBytes/pmTable/pmReserved
555- } else {
556- pack_type = 0;
557- pixel_size = 1;
558- }
559- //printf(" width %d, height %d, row_bytes %d, depth %d, pack_type %d\n", width, height, row_bytes, pixel_size, pack_type);
560-
561- // Allocate surface for picture
562- uint32 Rmask = 0, Gmask = 0, Bmask = 0;
563- int surface_depth = 8;
564- switch (pixel_size) {
565- case 1:
566- case 2:
567- case 4:
568- case 8:
569- Rmask = Gmask = Bmask = 0xff;
570- surface_depth = 8; // SDL surfaces must be at least 8 bits depth, so we expand 1/2/4-bit pictures to 8-bit
571- break;
572- case 16:
573- Rmask = 0x7c00;
574- Gmask = 0x03e0;
575- Bmask = 0x001f;
576- surface_depth = 16;
577- break;
578- case 32:
579- Rmask = 0x00ff0000;
580- Gmask = 0x0000ff00;
581- Bmask = 0x000000ff;
582- surface_depth = 32;
583- break;
584- default:
585- fprintf(stderr, "Unsupported PICT depth %d\n", pixel_size);
586- done = true;
587- break;
588- }
589- if (done)
590- break;
591- SDL_Surface *bm = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, surface_depth, Rmask, Gmask, Bmask, 0);
592- if (bm == NULL) {
593- done = true;
594- break;
595- }
596-
597- // 2. ColorTable
598- if (is_pixmap && (opcode == 0x0098 || opcode == 0x0099)) {
599- SDL_Color colors[256];
600- SDL_RWseek(p, 4, SEEK_CUR); // ctSeed
601- uint16 flags = SDL_ReadBE16(p);
602- int num_colors = SDL_ReadBE16(p) + 1;
603- for (int i=0; i<num_colors; i++) {
604- uint8 value = SDL_ReadBE16(p) & 0xff;
605- if (flags & 0x8000)
606- value = i;
607- colors[value].r = SDL_ReadBE16(p) >> 8;
608- colors[value].g = SDL_ReadBE16(p) >> 8;
609- colors[value].b = SDL_ReadBE16(p) >> 8;
610- }
611- SDL_SetColors(bm, colors, 0, 256);
612- }
613-
614- // 3. source/destination Rect and transfer mode
615- SDL_RWseek(p, 18, SEEK_CUR);
616-
617- // 4. clipping region
618- if (opcode == 0x0099 || opcode == 0x009b) {
619- uint16 rgn_size = SDL_ReadBE16(p);
620- SDL_RWseek(p, rgn_size - 2, SEEK_CUR);
621- }
622-
623- // 5. graphics data
624- int data_size = uncompress_picture((uint8 *)rsrc.GetPointer() + SDL_RWtell(p), row_bytes, (uint8 *)bm->pixels, bm->pitch, pixel_size, height, pack_type);
625- if (data_size < 0) {
626- done = true;
627- break;
628- }
629- if (data_size & 1)
630- data_size++;
631- SDL_RWseek(p, data_size, SEEK_CUR);
632-
633- // If there's already a surface, throw away the decoded image
634- // (actually, we could have skipped this entire opcode, but the
635- // only way to do this is to decode the image data).
636- // So we only draw the first image we encounter.
637- if (s)
638- SDL_FreeSurface(bm);
639- else
640- s = bm;
641- break;
642- }
643-
644-#ifdef HAVE_SDL_IMAGE
645- case 0x8200: { // Compressed QuickTime image (we only handle JPEG compression)
646- // 1. Header
647- uint32 opcode_size = SDL_ReadBE32(p);
648- if (opcode_size & 1)
649- opcode_size++;
650- uint32 opcode_start = SDL_RWtell(p);
651- SDL_RWseek(p, 26, SEEK_CUR); // version/matrix (hom. part)
652- int offset_x = SDL_ReadBE16(p);
653- SDL_RWseek(p, 2, SEEK_CUR);
654- int offset_y = SDL_ReadBE16(p);
655- SDL_RWseek(p, 6, SEEK_CUR); // matrix (remaining part)
656- uint32 matte_size = SDL_ReadBE32(p);
657- SDL_RWseek(p, 22, SEEK_CUR); // matteRec/mode/srcRect/accuracy
658- uint32 mask_size = SDL_ReadBE32(p);
659-
660- // 2. Matte image description
661- if (matte_size) {
662- uint32 matte_id_size = SDL_ReadBE32(p);
663- SDL_RWseek(p, matte_id_size - 4, SEEK_CUR);
664- }
665-
666- // 3. Matte data
667- SDL_RWseek(p, matte_size, SEEK_CUR);
668-
669- // 4. Mask region
670- SDL_RWseek(p, mask_size, SEEK_CUR);
671-
672- // 5. Image description
673- uint32 id_start = SDL_RWtell(p);
674- uint32 id_size = SDL_ReadBE32(p);
675- uint32 codec_type = SDL_ReadBE32(p);
676- if (codec_type != FOUR_CHARS_TO_INT('j','p','e','g')) {
677- fprintf(stderr, "Unsupported codec type %c%c%c%c\n", codec_type >> 24, codec_type >> 16, codec_type >> 8, codec_type);
678- done = true;
679- break;
680- }
681- SDL_RWseek(p, 36, SEEK_CUR); // resvd1/resvd2/dataRefIndex/version/revisionLevel/vendor/temporalQuality/spatialQuality/width/height/hRes/vRes
682- uint32 data_size = SDL_ReadBE32(p);
683- SDL_RWseek(p, id_start + id_size, SEEK_SET);
684-
685- // Allocate surface for complete (but possibly banded) picture
686- if (s == NULL) {
687- s = SDL_CreateRGBSurface(SDL_SWSURFACE, pic_width, pic_height, 32,
688-#ifdef ALEPHONE_LITTLE_ENDIAN
689- 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
690-#else
691- 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff
692-#endif
693- );
694- if (s == NULL) {
695- done = true;
696- break;
697- }
698- }
699-
700- // 6. Compressed image data
701- SDL_RWops *img = SDL_RWFromMem((uint8 *)rsrc.GetPointer() + SDL_RWtell(p), data_size);
702- if (img == NULL) {
703- done = true;
704- break;
705- }
706- SDL_Surface *bm = IMG_LoadTyped_RW(img, true, const_cast<char*>("JPG"));
707-
708- // Copy image (band) into surface
709- if (bm) {
710- SDL_Rect dst_rect = {offset_x, offset_y, bm->w, bm->h};
711- SDL_BlitSurface(bm, NULL, s, &dst_rect);
712- SDL_FreeSurface(bm);
713- }
714-
715- SDL_RWseek(p, opcode_start + opcode_size, SEEK_SET);
716- break;
717- }
718-#endif
719-
720- default:
721- if (opcode >= 0x0300 && opcode < 0x8000)
722- SDL_RWseek(p, (opcode >> 8) * 2, SEEK_CUR);
723- else if (opcode >= 0x8000 && opcode < 0x8100)
724- break;
725- else {
726- fprintf(stderr, "Unimplemented opcode %04x in PICT resource\n", opcode);
727- done = true;
728- }
729- break;
730- }
731- }
732-
733- // Close stream, return surface
734- SDL_RWclose(p);
735- return s;
736-}
737-
738-
739-/*
740- * Rescale surface to given dimensions
741- */
742-
743-template <class T>
744-static void rescale(T *src_pixels, int src_pitch, T *dst_pixels, int dst_pitch, int width, int height, uint32 dx, uint32 dy)
745-{
746- // Brute-force rescaling, no interpolation
747- uint32 sy = 0;
748- for (int y=0; y<height; y++) {
749- T *p = src_pixels + src_pitch / sizeof(T) * (sy >> 16);
750- uint32 sx = 0;
751- for (int x=0; x<width; x++) {
752- dst_pixels[x] = p[sx >> 16];
753- sx += dx;
754- }
755- dst_pixels += dst_pitch / sizeof(T);
756- sy += dy;
757- }
758-}
759-
760-SDL_Surface *rescale_surface(SDL_Surface *s, int width, int height)
761-{
762- if (s == NULL)
763- return NULL;
764-
765- SDL_Surface *s2 = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, s->format->BitsPerPixel, s->format->Rmask, s->format->Gmask, s->format->Bmask, s->format->Amask);
766- if (s2 == NULL)
767- return NULL;
768-
769- uint32 dx = (s->w << 16) / width;
770- uint32 dy = (s->h << 16) / height;
771-
772- switch (s->format->BytesPerPixel) {
773- case 1:
774- rescale((pixel8 *)s->pixels, s->pitch, (pixel8 *)s2->pixels, s2->pitch, width, height, dx, dy);
775- break;
776- case 2:
777- rescale((pixel16 *)s->pixels, s->pitch, (pixel16 *)s2->pixels, s2->pitch, width, height, dx, dy);
778- break;
779- case 4:
780- rescale((pixel32 *)s->pixels, s->pitch, (pixel32 *)s2->pixels, s2->pitch, width, height, dx, dy);
781- break;
782- }
783-
784- if (s->format->palette)
785- SDL_SetColors(s2, s->format->palette->colors, 0, s->format->palette->ncolors);
786-
787- return s2;
788-}
789-
790-
791-/*
792- * Tile surface to fill given dimensions
793- */
794-
795-template <class T>
796-static void tile(T *src_pixels, int src_pitch, T *dst_pixels, int dst_pitch, int src_width, int src_height, int dst_width, int dst_height)
797-{
798- T *p = src_pixels;
799- int sy = 0;
800- for (int y=0; y<dst_height; y++) {
801- int sx = 0;
802- for (int x=0; x<dst_width; x++) {
803- dst_pixels[x] = p[sx];
804- sx++;
805- if (sx == src_width)
806- sx = 0;
807- }
808- dst_pixels += dst_pitch / sizeof(T);
809- sy++;
810- if (sy == src_height) {
811- sy = 0;
812- p = src_pixels;
813- } else
814- p += src_pitch / sizeof(T);
815- }
816-}
817-
818-SDL_Surface *tile_surface(SDL_Surface *s, int width, int height)
819-{
820- if (s == NULL)
821- return NULL;
822-
823- SDL_Surface *s2 = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, s->format->BitsPerPixel, s->format->Rmask, s->format->Gmask, s->format->Bmask, s->format->Amask);
824- if (s2 == NULL)
825- return NULL;
826-
827- switch (s->format->BytesPerPixel) {
828- case 1:
829- tile((pixel8 *)s->pixels, s->pitch, (pixel8 *)s2->pixels, s2->pitch, s->w, s->h, width, height);
830- break;
831- case 2:
832- tile((pixel16 *)s->pixels, s->pitch, (pixel16 *)s2->pixels, s2->pitch, s->w, s->h, width, height);
833- break;
834- case 3:
835- tile((pixel8 *)s->pixels, s->pitch, (pixel8 *)s2->pixels, s2->pitch, s->w * 3, s->h, width * 3, height);
836- break;
837- case 4:
838- tile((pixel32 *)s->pixels, s->pitch, (pixel32 *)s2->pixels, s2->pitch, s->w, s->h, width, height);
839- break;
840- }
841-
842- if (s->format->palette)
843- SDL_SetColors(s2, s->format->palette->colors, 0, s->format->palette->ncolors);
844-
845- return s2;
846-}
847-
848-
849-/*
850- * Draw picture resource centered on screen
851- */
852-
853-extern SDL_Surface *draw_surface; // from screen_drawing.cpp
854-//void draw_intro_screen(void); // from screen.cpp
855-
856-static void draw_picture(LoadedResource &rsrc)
857-{
858- // Convert picture resource to surface, free resource
859- SDL_Surface *s = picture_to_surface(rsrc);
860- if (s == NULL)
861- return;
862- _set_port_to_intro();
863- SDL_Surface *video = draw_surface;
864-
865- // Default source rectangle
866- SDL_Rect src_rect = {0, 0, MIN(s->w, 640), MIN(s->h, 480)};
867-
868- // Center picture on screen
869- SDL_Rect dst_rect = {(video->w - src_rect.w) / 2, (video->h - src_rect.h) / 2, s->w, s->h};
870- if (dst_rect.x < 0)
871- dst_rect.x = 0;
872- if (dst_rect.y < 0)
873- dst_rect.y = 0;
874-
875- // Clip if desired (only used for menu buttons)
876- if (draw_clip_rect_active) {
877- src_rect.w = dst_rect.w = draw_clip_rect.right - draw_clip_rect.left;
878- src_rect.h = dst_rect.h = draw_clip_rect.bottom - draw_clip_rect.top;
879- src_rect.x = draw_clip_rect.left - (640 - s->w) / 2;
880- src_rect.y = draw_clip_rect.top - (480 - s->h) / 2;
881- dst_rect.x += draw_clip_rect.left- (640 - s->w) / 2;
882- dst_rect.y += draw_clip_rect.top - (480 - s->h) / 2;
883- } else {
884- // Clear destination to black
885- SDL_FillRect(video, NULL, SDL_MapRGB(video->format, 0, 0, 0));
886- }
887-
888- SDL_BlitSurface(s, &src_rect, video, &dst_rect);
889- _restore_port();
890- draw_intro_screen();
891-}
892-
893-
894-/*
895- * Get system color table
896- */
897-
898-struct color_table *build_8bit_system_color_table(void)
899-{
900- // 6*6*6 RGB color cube
901- color_table *table = new color_table;
902- table->color_count = 6*6*6;
903- int index = 0;
904- for (int red=0; red<6; red++) {
905- for (int green=0; green<6; green++) {
906- for (int blue=0; blue<6; blue++) {
907- uint8 r = red * 0x33;
908- uint8 g = green * 0x33;
909- uint8 b = blue * 0x33;
910- table->colors[index].red = (r << 8) | r;
911- table->colors[index].green = (g << 8) | g;
912- table->colors[index].blue = (b << 8) | b;
913- index++;
914- }
915- }
916- }
917- return table;
918-}
919-
920-
921-/*
922- * Scroll image across screen
923- */
924-
925-#define SCROLLING_SPEED (MACHINE_TICKS_PER_SECOND / 20)
926-
927-void scroll_full_screen_pict_resource_from_scenario(int pict_resource_number, bool text_block)
928-{
929- // Convert picture resource to surface, free resource
930- LoadedResource rsrc;
931- get_picture_resource_from_scenario(pict_resource_number, rsrc);
932- SDL_Surface *s = picture_to_surface(rsrc);
933- if (s == NULL)
934- return;
935-
936- // Find out in which direction to scroll
937- int picture_width = s->w;
938- int picture_height = s->h;
939- int screen_width = 640;
940- int screen_height = 480;
941- bool scroll_horizontal = picture_width > screen_width;
942- bool scroll_vertical = picture_height > screen_height;
943-
944- if (scroll_horizontal || scroll_vertical) {
945-
946- // Flush events
947- SDL_Event event;
948- while (SDL_PollEvent(&event)) ;
949-
950- // Prepare source and destination rectangles
951- SDL_Rect src_rect = {0, 0, scroll_horizontal ? screen_width : picture_width, scroll_vertical ? screen_height : picture_height};
952- SDL_Rect dst_rect = {0, 0, screen_width, screen_height};
953-
954- // Scroll loop
955- bool done = false, aborted = false;
956- uint32 start_tick = SDL_GetTicks();
957- do {
958-
959- int32 delta = (SDL_GetTicks() - start_tick) / (text_block ? (2 * SCROLLING_SPEED) : SCROLLING_SPEED);
960- if (scroll_horizontal && delta > picture_width - screen_width) {
961- delta = picture_width - screen_width;
962- done = true;
963- }
964- if (scroll_vertical && delta > picture_height - screen_height) {
965- delta = picture_height - screen_height;
966- done = true;
967- }
968-
969- // Blit part of picture
970- src_rect.x = scroll_horizontal ? delta : 0;
971- src_rect.y = scroll_vertical ? delta : 0;
972- _set_port_to_intro();
973- SDL_BlitSurface(s, &src_rect, draw_surface, &dst_rect);
974- _restore_port();
975- draw_intro_screen();
976-
977- // Give system time
978- global_idle_proc();
979- SDL_Delay(10);
980-
981- // Check for events to abort
982- event.type = SDL_NOEVENT;
983- SDL_PollEvent(&event);
984- switch (event.type) {
985- case SDL_MOUSEBUTTONDOWN:
986- case SDL_KEYDOWN:
987- aborted = true;
988- break;
989- }
990-
991- } while (!done && !aborted);
992- }
993-
994- // Free surface
995- SDL_FreeSurface(s);
996-}
997-
998-
999-/*
1000- * Initialize image manager, open Images file
1001- */
1002-
1003-void initialize_images_manager(void)
1004-{
1005- FileSpecifier file;
1006-
1007- logContext("loading Images...");
1008-
1009- file.SetNameWithPath(getcstr(temporary, strFILENAMES, filenameIMAGES)); // _typecode_images
1010-
1011- if (!file.Exists())
1012- alert_user(fatalError, strERRORS, badExtraFileLocations, fnfErr);
1013-
1014- if (!ImagesFile.open_file(file))
1015- alert_user(fatalError, strERRORS, badExtraFileLocations, -1);
1016-
1017- atexit(shutdown_images_handler);
1018-}
1019-
1020-
1021-/*
1022- * Shutdown image manager
1023- */
1024-
1025-static void shutdown_images_handler(void)
1026-{
1027- ScenarioFile.close_file();
1028- ImagesFile.close_file();
1029-}
1030-
1031-
1032-/*
1033- * Set map file to load images from
1034- */
1035-
1036-void set_scenario_images_file(FileSpecifier &file)
1037-{
1038- ScenarioFile.open_file(file);
1039-}
1040-
1041-
1042-/*
1043- * Open/close image file
1044- */
1045-
1046-bool image_file_t::open_file(FileSpecifier &file)
1047-{
1048- close_file();
1049-
1050- // Try to open as a resource file
1051- if (!file.Open(rsrc_file)) {
1052-
1053- // This failed, maybe it's a wad file (M2 Win95 style)
1054- if (!open_wad_file_for_reading(file, wad_file)
1055- || !read_wad_header(wad_file, &wad_hdr)) {
1056-
1057- // This also failed, bail out
1058- wad_file.Close();
1059- return false;
1060- }
1061- } // Try to open wad file, too
1062- else if (!wad_file.IsOpen()) {
1063- if (open_wad_file_for_reading(file, wad_file)) {
1064- if (!read_wad_header(wad_file, &wad_hdr)) {
1065-
1066- wad_file.Close();
1067- }
1068- }
1069- }
1070-
1071- return true;
1072-}
1073-
1074-void image_file_t::close_file(void)
1075-{
1076- rsrc_file.Close();
1077- wad_file.Close();
1078-}
1079-
1080-bool image_file_t::is_open(void)
1081-{
1082- return rsrc_file.IsOpen() || wad_file.IsOpen();
1083-}
1084-
1085-
1086-/*
1087- * Get resource from file
1088- */
1089-
1090-bool image_file_t::has_rsrc(uint32 rsrc_type, uint32 wad_type, int id)
1091-{
1092- // Check for resource in resource file
1093- if (rsrc_file.IsOpen())
1094- {
1095- if (rsrc_file.Check(rsrc_type, id))
1096- return true;
1097- }
1098-
1099- // Check for resource in wad file
1100- if (wad_file.IsOpen()) {
1101- wad_data *d = read_indexed_wad_from_file(wad_file, &wad_hdr, id, true);
1102- if (d) {
1103- bool success = false;
1104- size_t len;
1105- if (extract_type_from_wad(d, wad_type, &len))
1106- success = true;
1107- free_wad(d);
1108- return success;
1109- }
1110- }
1111-
1112- return false;
1113-}
1114-
1115-bool image_file_t::has_pict(int id)
1116-{
1117- return has_rsrc(FOUR_CHARS_TO_INT('P','I','C','T'), FOUR_CHARS_TO_INT('P','I','C','T'), id) || has_rsrc(FOUR_CHARS_TO_INT('P','I','C','T'), FOUR_CHARS_TO_INT('p','i','c','t'), id);
1118-}
1119-
1120-bool image_file_t::has_clut(int id)
1121-{
1122- return has_rsrc(FOUR_CHARS_TO_INT('c','l','u','t'), FOUR_CHARS_TO_INT('c','l','u','t'), id);
1123-}
1124-
1125-bool image_file_t::get_rsrc(uint32 rsrc_type, uint32 wad_type, int id, LoadedResource &rsrc)
1126-{
1127- // Get resource from resource file
1128- if (rsrc_file.IsOpen())
1129- {
1130- if (rsrc_file.Get(rsrc_type, id, rsrc))
1131- return true;
1132- }
1133-
1134- // Get resource from wad file
1135- if (wad_file.IsOpen()) {
1136- wad_data *d = read_indexed_wad_from_file(wad_file, &wad_hdr, id, true);
1137- if (d) {
1138- bool success = false;
1139- size_t raw_length;
1140- void *raw = extract_type_from_wad(d, wad_type, &raw_length);
1141- if (raw)
1142- {
1143- if (rsrc_type == FOUR_CHARS_TO_INT('P','I','C','T'))
1144- {
1145- if (wad_type == FOUR_CHARS_TO_INT('P','I','C','T'))
1146- {
1147- void *pict_data = malloc(raw_length);
1148- memcpy(pict_data, raw, raw_length);
1149- rsrc.SetData(pict_data, raw_length);
1150- success = true;
1151- }
1152- else
1153- {
1154- size_t clut_length;
1155- void *clut_data = extract_type_from_wad(d, FOUR_CHARS_TO_INT('c','l','u','t'), &clut_length);
1156- success = make_rsrc_from_pict(raw, raw_length, rsrc, clut_data, clut_length);
1157- }
1158- }
1159- else if (rsrc_type == FOUR_CHARS_TO_INT('c','l','u','t'))
1160- success = make_rsrc_from_clut(raw, raw_length, rsrc);
1161- else if (rsrc_type == FOUR_CHARS_TO_INT('s','n','d',' '))
1162- {
1163- void *snd_data = malloc(raw_length);
1164- memcpy(snd_data, raw, raw_length);
1165- rsrc.SetData(snd_data, raw_length);
1166- success = true;
1167- }
1168- else if (rsrc_type == FOUR_CHARS_TO_INT('T','E','X','T'))
1169- {
1170- void *text_data = malloc(raw_length);
1171- memcpy(text_data, raw, raw_length);
1172- rsrc.SetData(text_data, raw_length);
1173- success = true;
1174- }
1175- }
1176- free_wad(d);
1177- return success;
1178- }
1179- }
1180-
1181- return false;
1182-}
1183-
1184-bool image_file_t::get_pict(int id, LoadedResource &rsrc)
1185-{
1186- return get_rsrc(FOUR_CHARS_TO_INT('P','I','C','T'), FOUR_CHARS_TO_INT('P','I','C','T'), id, rsrc) || get_rsrc(FOUR_CHARS_TO_INT('P','I','C','T'), FOUR_CHARS_TO_INT('p','i','c','t'), id, rsrc);
1187-}
1188-
1189-bool image_file_t::get_clut(int id, LoadedResource &rsrc)
1190-{
1191- return get_rsrc(FOUR_CHARS_TO_INT('c','l','u','t'), FOUR_CHARS_TO_INT('c','l','u','t'), id, rsrc);
1192-}
1193-
1194-bool image_file_t::get_snd(int id, LoadedResource &rsrc)
1195-{
1196- return get_rsrc(FOUR_CHARS_TO_INT('s','n','d',' '), FOUR_CHARS_TO_INT('s','n','d',' '), id, rsrc);
1197-}
1198-
1199-bool image_file_t::get_text(int id, LoadedResource &rsrc)
1200-{
1201- return get_rsrc(FOUR_CHARS_TO_INT('T','E','X','T'), FOUR_CHARS_TO_INT('t','e','x','t'), id, rsrc);
1202-}
1203-
1204-
1205-/*
1206- * Get/draw image from Images file
1207- */
1208-
1209-bool get_picture_resource_from_images(int base_resource, LoadedResource &PictRsrc)
1210-{
1211- assert(ImagesFile.is_open());
1212-
1213- int RsrcID = ImagesFile.determine_pict_resource_id(
1214- base_resource, _images_file_delta16, _images_file_delta32);
1215- return ImagesFile.get_pict(RsrcID, PictRsrc);
1216-}
1217-
1218-bool images_picture_exists(int base_resource)
1219-{
1220- assert(ImagesFile.is_open());
1221-
1222- int RsrcID = ImagesFile.determine_pict_resource_id(
1223- base_resource, _images_file_delta16, _images_file_delta32);
1224- return ImagesFile.has_pict(RsrcID);
1225-}
1226-
1227-void draw_full_screen_pict_resource_from_images(int pict_resource_number)
1228-{
1229- LoadedResource PictRsrc;
1230- get_picture_resource_from_images(pict_resource_number, PictRsrc);
1231- draw_picture(PictRsrc);
1232-}
1233-
1234-
1235-/*
1236- * Get/draw image from scenario
1237- */
1238-
1239-bool get_picture_resource_from_scenario(int base_resource, LoadedResource &PictRsrc)
1240-{
1241- if (!ScenarioFile.is_open())
1242- return false;
1243-
1244- int RsrcID = ScenarioFile.determine_pict_resource_id(
1245- base_resource, _scenario_file_delta16, _scenario_file_delta32);
1246-
1247- bool success = ScenarioFile.get_pict(RsrcID, PictRsrc);
1248-#ifdef mac
1249- if (success) {
1250- Handle PictHdl = PictRsrc.GetHandle();
1251- if (PictHdl) HNoPurge(PictHdl);
1252- }
1253-#endif
1254- return success;
1255-}
1256-
1257-bool scenario_picture_exists(int base_resource)
1258-{
1259- if (!ScenarioFile.is_open())
1260- return false;
1261-
1262- int RsrcID = ScenarioFile.determine_pict_resource_id(
1263- base_resource, _scenario_file_delta16, _scenario_file_delta32);
1264- return ScenarioFile.has_pict(RsrcID);
1265-}
1266-
1267-void draw_full_screen_pict_resource_from_scenario(int pict_resource_number)
1268-{
1269- LoadedResource PictRsrc;
1270- get_picture_resource_from_scenario(pict_resource_number, PictRsrc);
1271- draw_picture(PictRsrc);
1272-}
1273-
1274-
1275-/*
1276- * Get sound resource from scenario
1277- */
1278-
1279-bool get_sound_resource_from_scenario(int resource_number, LoadedResource &SoundRsrc)
1280-{
1281- if (!ScenarioFile.is_open())
1282- return false;
1283-
1284- bool success = ScenarioFile.get_snd(resource_number, SoundRsrc);
1285-#ifdef mac
1286- if (success) {
1287- Handle SndHdl = SoundRsrc.GetHandle();
1288- if (SndHdl) HNoPurge(SndHdl);
1289- }
1290-#endif
1291- return success;
1292-}
1293-
1294-
1295-// LP: do the same for text resources
1296-
1297-bool get_text_resource_from_scenario(int resource_number, LoadedResource &TextRsrc)
1298-{
1299- if (!ScenarioFile.is_open())
1300- return false;
1301-
1302- bool success = ScenarioFile.get_text(resource_number, TextRsrc);
1303-#ifdef mac
1304- if (success) {
1305- Handle TxtHdl = TextRsrc.GetHandle();
1306- if (TxtHdl) HNoPurge(TxtHdl);
1307- }
1308-#endif
1309- return success;
1310-}
1311-
1312-
1313-/*
1314- * Calculate color table for image
1315- */
1316-
1317-struct color_table *calculate_picture_clut(int CLUTSource, int pict_resource_number)
1318-{
1319- struct color_table *picture_table = NULL;
1320-
1321- // Select the source
1322- image_file_t *OFilePtr = NULL;
1323- switch (CLUTSource) {
1324- case CLUTSource_Images:
1325- OFilePtr = &ImagesFile;
1326- break;
1327-
1328- case CLUTSource_Scenario:
1329- OFilePtr = &ScenarioFile;
1330- break;
1331-
1332- default:
1333- vassert(false, csprintf(temporary, "Invalid resource-file selector: %d", CLUTSource));
1334- break;
1335- }
1336-
1337- // Load CLUT resource
1338- LoadedResource CLUT_Rsrc;
1339- if (OFilePtr->get_clut(pict_resource_number, CLUT_Rsrc)) {
1340-
1341-#ifdef mac
1342- Handle resource = CLUT_Rsrc.GetHandle();
1343- HNoPurge(resource);
1344-#endif
1345-
1346- // Allocate color table
1347- picture_table = new color_table;
1348-
1349- // Convert MacOS CLUT resource to color table
1350- if (interface_bit_depth == 8)
1351- build_color_table(picture_table, CLUT_Rsrc);
1352- else
1353- build_direct_color_table(picture_table, interface_bit_depth);
1354- }
1355-
1356- return picture_table;
1357-}
1358-
1359-
1360-/*
1361- * Determine ID for picture resource
1362- */
1363-
1364-int image_file_t::determine_pict_resource_id(int base_id, int delta16, int delta32)
1365-{
1366- int actual_id = base_id;
1367- bool done = false;
1368- int bit_depth = interface_bit_depth;
1369-
1370- while (!done) {
1371- int next_bit_depth;
1372-
1373- actual_id = base_id;
1374- switch(bit_depth) {
1375- case 8:
1376- next_bit_depth = 0;
1377- break;
1378-
1379- case 16:
1380- next_bit_depth = 8;
1381- actual_id += delta16;
1382- break;
1383-
1384- case 32:
1385- next_bit_depth = 16;
1386- actual_id += delta32;
1387- break;
1388-
1389- default:
1390- assert(false);
1391- break;
1392- }
1393-
1394- if (has_pict(actual_id))
1395- done = true;
1396-
1397- if (!done) {
1398- if (next_bit_depth)
1399- bit_depth = next_bit_depth;
1400- else {
1401- // Didn't find it. Return the 8 bit version and bail..
1402- done = true;
1403- }
1404- }
1405- }
1406- return actual_id;
1407-}
1408-
1409-
1410-/*
1411- * Convert picture and CLUT data from wad file to PICT resource
1412- */
1413-
1414-#ifdef mac
1415-
1416-// MacOS version
1417-bool image_file_t::make_rsrc_from_pict(void *data, size_t length, LoadedResource &rsrc, void *clut_data, size_t clut_length)
1418-{
1419- pict_head *head;
1420- PicHandle picture;
1421- Rect bounds;
1422- short i;
1423- GWorldPtr gworld;
1424- PixMapHandle pixmap;
1425- void *pict_data;
1426- void *clut;
1427- uint8 *p, *q;
1428- CTabHandle clut_handle;
1429- CGrafPtr saveport;
1430-
1431- if (length < 10)
1432- return false;
1433-
1434- head = (pict_head *)data;
1435-
1436- bounds.left = head->bounds.left;
1437- bounds.top = head->bounds.top;
1438- bounds.right = head->bounds.right;
1439- bounds.bottom = head->bounds.bottom;
1440-
1441- if (head->depth == 8)
1442- {
1443-
1444- clut = malloc(8 + 256 * 8);
1445-
1446- memset(clut, 0, 8 + 256 * 8);
1447-
1448- p = (uint8 *)clut_data;
1449- q = (uint8 *)clut;
1450-
1451- // 1. Header
1452- q[6] = p[0]; // color count
1453- q[7] = p[1];
1454- p += 6;
1455- q += 8;
1456-
1457- // 2. Color table
1458- for (i = 0; i < 256; i++)
1459- {
1460- q++;
1461- *q++ = i; // value
1462- *q++ = *p++; // red
1463- *q++ = *p++;
1464- *q++ = *p++; // green
1465- *q++ = *p++;
1466- *q++ = *p++; // blue
1467- *q++ = *p++;
1468- }
1469-
1470- clut_handle = (CTabHandle)NewHandleClear(8 + 256 * 8);
1471-
1472- PtrToHand(clut, (Handle *)&clut_handle, 8 + 256 * 8);
1473-
1474- QTNewGWorldFromPtr(&gworld, k8IndexedPixelFormat, &bounds, clut_handle, NULL, 0, (uint8 *)data + 10, head->bounds.right - head->bounds.left);
1475-
1476- free(clut);
1477- DisposeHandle((Handle)clut_handle);
1478- }
1479- else if (head->depth == 16)
1480- {
1481- QTNewGWorldFromPtr(&gworld, k16BE555PixelFormat, &bounds, NULL, NULL, 0, (uint8 *)data + 10, (head->bounds.right - head->bounds.left) * 2);
1482- }
1483- else if (head->depth == 24)
1484- {
1485- QTNewGWorldFromPtr(&gworld, k24RGBPixelFormat, &bounds, NULL, NULL, 0, (uint8 *)data + 10, (head->bounds.right - head->bounds.left) * 3);
1486- }
1487- else if (head->depth == 32)
1488- {
1489- QTNewGWorldFromPtr(&gworld, k32ARGBPixelFormat, &bounds, NULL, NULL, 0, (uint8 *)data + 10, (head->bounds.right - head->bounds.left) * 4);
1490- }
1491- else
1492- {
1493- return false;
1494- }
1495-
1496- PenNormal();
1497-
1498- GetGWorld(&saveport, NULL);
1499- SetGWorld(gworld, NULL);
1500-
1501- ForeColor(blackColor);
1502- BackColor(whiteColor);
1503-
1504- pixmap = GetGWorldPixMap(gworld);
1505- LockPixels(pixmap);
1506-
1507- picture = OpenPicture(&bounds);
1508-
1509- if (picture != NULL)
1510- {
1511- CopyBits((BitMap *)*pixmap, (BitMap *)*pixmap, &bounds, &bounds, srcCopy, NULL);
1512- ClosePicture();
1513- }
1514-
1515- if (picture != NULL)
1516- {
1517- UnlockPixels(pixmap);
1518- SetGWorld(saveport, NULL);
1519- DisposeGWorld(gworld);
1520-
1521- HLock((Handle)picture);
1522- pict_data = malloc(GetHandleSize((Handle)picture));
1523- memcpy(pict_data, *picture, GetHandleSize((Handle)picture));
1524-
1525- rsrc.SetData(pict_data, GetHandleSize((Handle)picture));
1526- KillPicture(picture);
1527- }
1528-
1529- return true;
1530-}
1531-
1532-#else
1533-
1534-// SDL version
1535-bool image_file_t::make_rsrc_from_pict(void *data, size_t length, LoadedResource &rsrc, void *clut_data, size_t clut_length)
1536-{
1537- if (length < 10)
1538- return false;
1539-
1540- // Extract size and depth
1541- uint8 *p = (uint8 *)data;
1542- int height = (p[4] << 8) + p[5];
1543- int width = (p[6] << 8) + p[7];
1544- int depth = (p[8] << 8) + p[9];
1545- if (depth != 8 && depth != 16)
1546- return false;
1547-
1548- // 8-bit depth requires CLUT
1549- if (depth == 8) {
1550- if (clut_data == NULL || clut_length != 6 + 256 * 6)
1551- return false;
1552- }
1553-
1554- // size(2), rect(8), versionOp(2), version(2), headerOp(26)
1555- int output_length = 2 + 8 + 2 + 2 + 26;
1556- int row_bytes;
1557- if (depth == 8) {
1558- // opcode(2), pixMap(46), colorTable(8+256*8), srcRect/dstRect/mode(18), data(variable)
1559- row_bytes = width;
1560- output_length += 2 + 46 + 8+256*8 + 18;
1561- } else {
1562- // opcode(2), pixMap(50), srcRect/dstRect/mode(18), data(variable)
1563- row_bytes = width * 2;
1564- output_length += 2 + 50 + 18;
1565- }
1566- // data(variable), opEndPic(2)
1567- output_length += row_bytes * height + 2;
1568-
1569- // Allocate memory for Mac PICT resource
1570- void *pict_rsrc = malloc(output_length);
1571- if (pict_rsrc == NULL)
1572- return false;
1573- memset(pict_rsrc, 0, output_length);
1574-
1575- // Convert pict tag to Mac PICT resource
1576- uint8 *q = (uint8 *)pict_rsrc;
1577-
1578- // 1. PICT header
1579- q[0] = output_length >> 8;
1580- q[1] = output_length;
1581- memcpy(q + 2, p, 8);
1582- q += 10;
1583-
1584- // 2. VersionOp/Version/HeaderOp
1585- q[0] = 0x00; q[1] = 0x11; // versionOp
1586- q[2] = 0x02; q[3] = 0xff; // version
1587- q[4] = 0x0c; q[5] = 0x00; // headerOp
1588- q[6] = 0xff; q[7] = 0xfe; // header version
1589- q[11] = 0x48; // hRes
1590- q[15] = 0x48; // vRes
1591- memcpy(q + 18, p, 8);
1592- q += 30;
1593-
1594- // 3. opcode
1595- if (depth == 8) {
1596- q[0] = 0x00; q[1] = 0x98; // PackBitsRect
1597- q += 2;
1598- } else {
1599- q[0] = 0x00; q[1] = 0x9a; // DirectBitsRect
1600- q += 6; // skip pmBaseAddr
1601- }
1602-
1603- // 4. PixMap
1604- q[0] = (row_bytes >> 8) | 0x80;
1605- q[1] = row_bytes;
1606- memcpy(q + 2, p, 8);
1607- q[13] = 0x01; // packType = unpacked
1608- q[19] = 0x48; // hRes
1609- q[23] = 0x48; // vRes
1610- q[27] = (depth == 8 ? 0 : 0x10); // pixelType
1611- q[29] = depth; // pixelSize
1612- q[31] = (depth == 8 ? 1 : 3); // cmpCount
1613- q[33] = (depth == 8 ? 8 : 5); // cmpSize
1614- q += 46;
1615-
1616- // 5. ColorTable
1617- if (depth == 8) {
1618- q[7] = 0xff; // ctSize
1619- q += 8;
1620- uint8 *p = (uint8 *)clut_data + 6;
1621- for (int i=0; i<256; i++) {
1622- q++;
1623- *q++ = i; // value
1624- *q++ = *p++; // red
1625- *q++ = *p++;
1626- *q++ = *p++; // green
1627- *q++ = *p++;
1628- *q++ = *p++; // blue
1629- *q++ = *p++;
1630- }
1631- }
1632-
1633- // 6. source/destination Rect and transfer mode
1634- memcpy(q, p, 8);
1635- memcpy(q + 8, p, 8);
1636- q += 18;
1637-
1638- // 7. graphics data
1639- memcpy(q, p + 10, row_bytes * height);
1640- q += row_bytes * height;
1641-
1642- // 8. OpEndPic
1643- q[0] = 0x00;
1644- q[1] = 0xff;
1645-
1646- rsrc.SetData(pict_rsrc, output_length);
1647- return true;
1648-}
1649-
1650-#endif
1651-
1652-bool image_file_t::make_rsrc_from_clut(void *data, size_t length, LoadedResource &rsrc)
1653-{
1654- const size_t input_length = 6 + 256 * 6; // 6 bytes header, 256 entries with 6 bytes each
1655- const size_t output_length = 8 + 256 * 8; // 8 bytes header, 256 entries with 8 bytes each
1656-
1657- if (length != input_length)
1658- return false;
1659-
1660- // Allocate memory for Mac CLUT resource
1661- void *clut_rsrc = malloc(output_length);
1662- if (clut_rsrc == NULL)
1663- return false;
1664- memset(clut_rsrc, 0, output_length);
1665-
1666- // Convert clut tag to Mac CLUT resource
1667- uint8 *p = (uint8 *)data;
1668- uint8 *q = (uint8 *)clut_rsrc;
1669-
1670- // 1. Header
1671- q[6] = p[0]; // color count
1672- q[7] = p[1];
1673- p += 6;
1674- q += 8;
1675-
1676- // 2. Color table
1677- for (int i=0; i<256; i++) {
1678- q++;
1679- *q++ = i; // value
1680- *q++ = *p++; // red
1681- *q++ = *p++;
1682- *q++ = *p++; // green
1683- *q++ = *p++;
1684- *q++ = *p++; // blue
1685- *q++ = *p++;
1686- }
1687-
1688- rsrc.SetData(clut_rsrc, output_length);
1689- return true;
1690-}
1+/*
2+ images.c
3+
4+ Copyright (C) 1991-2001 and beyond by Bungie Studios, Inc.
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+ Thursday, July 20, 1995 3:29:30 PM- rdm created.
22+
23+Feb. 4, 2000 (Loren Petrich):
24+ Changed halt() to assert(false) for better debugging
25+
26+Feb. 5, 2000 (Loren Petrich):
27+ Better handling of case of no scenario-file resource fork
28+
29+Aug 21, 2000 (Loren Petrich):
30+ Added object-oriented file handling
31+
32+ LoadedResource handles are assumed to always be locked,
33+ and HLock() and HUnlock() have been suppressed for that reason.
34+
35+Jul 6, 2001 (Loren Petrich):
36+ Added Thomas Herzog's changes for loading Win32-version image chunks
37+
38+Jan 25, 2002 (Br'fin (Jeremy Parsons)):
39+ Added TARGET_API_MAC_CARBON for Quicktime.h
40+
41+Jul 31, 2002 (Loren Petrich)
42+ Added text-resource access in analogy with others' image- and sound-resource access;
43+ this is for supporting the M2-Win95 file format
44+ */
45+
46+#include "cseries.h"
47+#include "FileHandler.h"
48+
49+#include <stdlib.h>
50+
51+#if defined(mac)
52+#if defined(EXPLICIT_CARBON_HEADER)
53+# include <quicktime/Quicktime.h>
54+#else
55+# include <Movies.h>
56+#endif
57+#endif
58+
59+#include "interface.h"
60+#include "shell.h"
61+#include "images.h"
62+#include "screen.h"
63+#include "wad.h"
64+#include "screen_drawing.h"
65+#include "Logging.h"
66+
67+#include "render.h"
68+#include "OGL_Render.h"
69+#include "OGL_Blitter.h"
70+
71+
72+// Constants
73+enum {
74+ _images_file_delta16= 1000,
75+ _images_file_delta32= 2000,
76+ _scenario_file_delta16= 10000,
77+ _scenario_file_delta32= 20000
78+};
79+
80+// Structure for open image file
81+class image_file_t {
82+public:
83+ image_file_t() {}
84+ ~image_file_t() {close_file();}
85+
86+ bool open_file(FileSpecifier &file);
87+ void close_file(void);
88+ bool is_open(void);
89+
90+ int determine_pict_resource_id(int base_id, int delta16, int delta32);
91+
92+ bool has_pict(int id);
93+ bool has_clut(int id);
94+
95+ bool get_pict(int id, LoadedResource &rsrc);
96+ bool get_clut(int id, LoadedResource &rsrc);
97+ bool get_snd(int id, LoadedResource &rsrc);
98+ bool get_text(int id, LoadedResource &rsrc);
99+
100+private:
101+ bool has_rsrc(uint32 rsrc_type, uint32 wad_type, int id);
102+ bool get_rsrc(uint32 rsrc_type, uint32 wad_type, int id, LoadedResource &rsrc);
103+
104+ bool make_rsrc_from_pict(void *data, size_t length, LoadedResource &rsrc, void *clut_data, size_t clut_length);
105+ bool make_rsrc_from_clut(void *data, size_t length, LoadedResource &rsrc);
106+
107+ OpenedResourceFile rsrc_file;
108+ OpenedFile wad_file;
109+ wad_header wad_hdr;
110+};
111+
112+#ifdef mac
113+// M2/Win picture structures (do not use in portable code)
114+typedef struct pict_head {
115+ screen_rectangle bounds; /* screen_rectangle from screen_drawing.h */
116+ short depth; /* 8 or 16 */
117+ /* pixel data follows here */
118+} pict_head;
119+
120+typedef struct clut_record {
121+ short count;
122+ short unknown;
123+ short id;
124+ rgb_color colors[256]; /* rgb_color from cscluts.h */
125+} clut_record;
126+#endif
127+
128+// Global variables
129+static image_file_t ImagesFile;
130+static image_file_t ScenarioFile;
131+
132+// Prototypes
133+static void shutdown_images_handler(void);
134+static void draw_picture(LoadedResource &PictRsrc);
135+
136+
137+#include <SDL_endian.h>
138+
139+#ifdef HAVE_SDL_IMAGE_H
140+#include <SDL_image.h>
141+#endif
142+
143+#include "byte_swapping.h"
144+#include "screen_drawing.h"
145+
146+
147+// From screen_sdl.cpp
148+extern short interface_bit_depth;
149+
150+// From screen_drawing_sdl.cpp
151+extern bool draw_clip_rect_active;
152+extern screen_rectangle draw_clip_rect;
153+
154+
155+/*
156+ * Uncompress picture data, returns size of compressed image data that was read
157+ */
158+
159+// Uncompress (and endian-correct) scan line compressed by PackBits RLE algorithm
160+template <class T>
161+static const uint8 *unpack_bits(const uint8 *src, int row_bytes, T *dst)
162+{
163+ // Read source count
164+ int src_count;
165+ if (row_bytes > 250) {
166+ src_count = (src[0] << 8) | src[1];
167+ src += 2;
168+ } else
169+ src_count = *src++;
170+
171+ while (src_count > 0) {
172+
173+ // Read flag/count byte
174+ int c = (int8)*src++;
175+ src_count--;
176+ if (c < 0) {
177+
178+ // RLE compressed run
179+ int size = -c + 1;
180+ T data;
181+ if (sizeof(T) == 1) {
182+ data = *src++;
183+ src_count--;
184+ } else {
185+ data = (src[0] << 8) | src[1];
186+ src += 2;
187+ src_count -= 2;
188+ }
189+ for (int i=0; i<size; i++)
190+ *dst++ = data;
191+
192+ } else {
193+
194+ // Uncompressed run
195+ int size = c + 1;
196+ for (int i=0; i<size; i++) {
197+ T data;
198+ if (sizeof(T) == 1) {
199+ data = *src++;
200+ src_count--;
201+ } else {
202+ data = (src[0] << 8) | src[1];
203+ src += 2;
204+ src_count -= 2;
205+ }
206+ *dst++ = data;
207+ }
208+ }
209+ }
210+ return src;
211+}
212+
213+// 8-bit picture, one scan line at a time
214+static int uncompress_rle8(const uint8 *src, int row_bytes, uint8 *dst, int dst_pitch, int height)
215+{
216+ const uint8 *start = src;
217+ for (int y=0; y<height; y++) {
218+ src = unpack_bits(src, row_bytes, dst);
219+ dst += dst_pitch;
220+ }
221+ return static_cast<int>(src - start);
222+}
223+
224+// 16-bit picture, one scan line at a time, 16-bit chunks
225+static int uncompress_rle16(const uint8 *src, int row_bytes, uint8 *dst, int dst_pitch, int height)
226+{
227+ const uint8 *start = src;
228+ for (int y=0; y<height; y++) {
229+ src = unpack_bits(src, row_bytes, (uint16 *)dst);
230+ dst += dst_pitch;
231+ }
232+ return static_cast<int>(src - start);
233+}
234+
235+static void copy_component_into_surface(const uint8 *src, uint8 *dst, int count, int component)
236+{
237+#ifdef ALEPHONE_LITTLE_ENDIAN
238+ dst += 2 - component;
239+#else
240+ dst += component + 1;
241+#endif
242+ while (count--) {
243+ *dst = *src++;
244+ dst += 4;
245+ }
246+}
247+
248+// 32-bit picture, one scan line, one component at a time
249+static int uncompress_rle32(const uint8 *src, int row_bytes, uint8 *dst, int dst_pitch, int height)
250+{
251+ uint8 *tmp = (uint8 *)malloc(row_bytes);
252+ if (tmp == NULL)
253+ return -1;
254+
255+ const uint8 *start = src;
256+
257+ int width = row_bytes / 4;
258+ for (int y=0; y<height; y++) {
259+ src = unpack_bits(src, row_bytes, tmp);
260+
261+ // "tmp" now contains "width" bytes of red, followed by "width"
262+ // bytes of green and "width" bytes of blue, so we have to copy them
263+ // into the surface in the right order
264+ copy_component_into_surface(tmp, dst, width, 0);
265+ copy_component_into_surface(tmp + width, dst, width, 1);
266+ copy_component_into_surface(tmp + width * 2, dst, width, 2);
267+
268+ dst += dst_pitch;
269+ }
270+
271+ free(tmp);
272+
273+ return static_cast<int>(src - start);
274+}
275+
276+static int uncompress_picture(const uint8 *src, int row_bytes, uint8 *dst, int dst_pitch, int depth, int height, int pack_type)
277+{
278+ // Depths <8 have to be color expanded to depth 8 after uncompressing,
279+ // so we uncompress into a temporary buffer
280+ uint8 *orig_dst = dst;
281+ int orig_dst_pitch = dst_pitch;
282+ if (depth < 8) {
283+ dst = (uint8 *)malloc(row_bytes * height);
284+ dst_pitch = row_bytes;
285+ if (dst == NULL)
286+ return -1;
287+ }
288+
289+ int data_size = 0;
290+
291+ if (row_bytes < 8) {
292+
293+ // Uncompressed data
294+ const uint8 *p = src;
295+ uint8 *q = dst;
296+ for (int y=0; y<height; y++) {
297+ memcpy(q, p, MIN(row_bytes, dst_pitch));
298+ p += row_bytes;
299+ q += dst_pitch;
300+ }
301+ data_size = row_bytes * height;
302+
303+ } else {
304+
305+ // Compressed data
306+ if (depth <= 8) {
307+
308+ // Indexed color
309+ if (pack_type == 1)
310+ goto no_packing;
311+ data_size = uncompress_rle8(src, row_bytes, dst, dst_pitch, height);
312+
313+ } else {
314+
315+ // Direct color
316+ if (pack_type == 0) {
317+ if (depth == 16)
318+ pack_type = 3;
319+ else if (depth == 32)
320+ pack_type = 4;
321+
322+ }
323+ switch (pack_type) {
324+ case 1: { // No packing
325+no_packing: const uint8 *p = src;
326+ uint8 *q = dst;
327+ for (int y=0; y<height; y++) {
328+ memcpy(q, p, MIN(row_bytes, dst_pitch));
329+ p += row_bytes;
330+ q += dst_pitch;
331+ }
332+ data_size = row_bytes * height;
333+ if (depth == 16)
334+ byte_swap_memory(dst, _2byte, dst_pitch * height / 2);
335+ else if (depth == 32)
336+ byte_swap_memory(dst, _4byte, dst_pitch * height / 4);
337+ break;
338+ }
339+ case 3: // Run-length encoding by 16-bit chunks
340+ data_size = uncompress_rle16(src, row_bytes, dst, dst_pitch, height);
341+ break;
342+ case 4: // Run-length encoding one component at a time
343+ data_size = uncompress_rle32(src, row_bytes, dst, dst_pitch, height);
344+ break;
345+ default:
346+ fprintf(stderr, "Unimplemented packing type %d (depth %d) in PICT resource\n", pack_type, depth);
347+ data_size = -1;
348+ break;
349+ }
350+ }
351+ }
352+
353+ // Color expansion 1/2/4->8 bits
354+ if (depth < 8) {
355+ const uint8 *p = dst;
356+ uint8 *q = orig_dst;
357+
358+ // Source and destination may have different alignment restrictions,
359+ // don't run off the right of either
360+ int x_max = row_bytes;
361+ while (x_max * 8 / depth > orig_dst_pitch)
362+ x_max--;
363+
364+ switch (depth) {
365+ case 1:
366+ for (int y=0; y<height; y++) {
367+ for (int x=0; x<x_max; x++) {
368+ uint8 b = p[x];
369+ q[x*8+0] = (b & 0x80) ? 0x01 : 0x00;
370+ q[x*8+1] = (b & 0x40) ? 0x01 : 0x00;
371+ q[x*8+2] = (b & 0x20) ? 0x01 : 0x00;
372+ q[x*8+3] = (b & 0x10) ? 0x01 : 0x00;
373+ q[x*8+4] = (b & 0x08) ? 0x01 : 0x00;
374+ q[x*8+5] = (b & 0x04) ? 0x01 : 0x00;
375+ q[x*8+6] = (b & 0x02) ? 0x01 : 0x00;
376+ q[x*8+7] = (b & 0x01) ? 0x01 : 0x00;
377+ }
378+ p += row_bytes;
379+ q += orig_dst_pitch;
380+ }
381+ break;
382+ case 2:
383+ for (int y=0; y<height; y++) {
384+ for (int x=0; x<x_max; x++) {
385+ uint8 b = p[x];
386+ q[x*4+0] = (b >> 6) & 0x03;
387+ q[x*4+1] = (b >> 4) & 0x03;
388+ q[x*4+2] = (b >> 2) & 0x03;
389+ q[x*4+3] = b & 0x03;
390+ }
391+ p += row_bytes;
392+ q += orig_dst_pitch;
393+ }
394+ break;
395+ case 4:
396+ for (int y=0; y<height; y++) {
397+ for (int x=0; x<x_max; x++) {
398+ uint8 b = p[x];
399+ q[x*2+0] = (b >> 4) & 0x0f;
400+ q[x*2+1] = b & 0x0f;
401+ }
402+ p += row_bytes;
403+ q += orig_dst_pitch;
404+ }
405+ break;
406+ }
407+ free(dst);
408+ }
409+
410+ return data_size;
411+}
412+
413+int get_pict_header_width(LoadedResource &rsrc)
414+{
415+ SDL_RWops *p = SDL_RWFromMem(rsrc.GetPointer(), (int) rsrc.GetLength());
416+ if (p)
417+ {
418+ SDL_RWseek(p, 8, SEEK_CUR);
419+ int width = SDL_ReadBE16(p);
420+ SDL_RWclose(p);
421+ return width;
422+ }
423+ return -1;
424+}
425+
426+/*
427+ * Convert picture resource to SDL surface
428+ */
429+
430+SDL_Surface *picture_to_surface(LoadedResource &rsrc)
431+{
432+ if (!rsrc.IsLoaded())
433+ return NULL;
434+
435+ SDL_Surface *s = NULL;
436+
437+ // Open stream to picture resource
438+ SDL_RWops *p = SDL_RWFromMem(rsrc.GetPointer(), (int)rsrc.GetLength());
439+ if (p == NULL)
440+ return NULL;
441+ SDL_RWseek(p, 2 /* 6 */, SEEK_CUR); // picSize/top/left
442+ int top = SDL_ReadBE16(p), left = SDL_ReadBE16(p), bottom = SDL_ReadBE16(p), right = SDL_ReadBE16(p);
443+ int pic_height = /* SDL_ReadBE16(p) */ bottom - top;
444+ int pic_width = /* SDL_ReadBE16(p) */ right - left;
445+ //printf("pic_width %d, pic_height %d\n", pic_width, pic_height);
446+
447+ // Read and parse picture opcodes
448+ bool done = false;
449+ while (!done) {
450+ uint16 opcode = SDL_ReadBE16(p);
451+ //printf("%04x\n", opcode);
452+ switch (opcode) {
453+
454+ case 0x0000: // NOP
455+ case 0x0011: // VersionOp
456+ case 0x001c: // HiliteMode
457+ case 0x001e: // DefHilite
458+ case 0x0038: // FrameSameRect
459+ case 0x0039: // PaintSameRect
460+ case 0x003a: // EraseSameRect
461+ case 0x003b: // InvertSameRect
462+ case 0x003c: // FillSameRect
463+ case 0x02ff: // Version
464+ break;
465+
466+ case 0x00ff: // OpEndPic
467+ done = true;
468+ break;
469+
470+ case 0x0001: { // Clipping region
471+ uint16 size = SDL_ReadBE16(p);
472+ if (size & 1)
473+ size++;
474+ SDL_RWseek(p, size - 2, SEEK_CUR);
475+ break;
476+ }
477+
478+ case 0x0003: // TxFont
479+ case 0x0004: // TxFace
480+ case 0x0005: // TxMode
481+ case 0x0008: // PnMode
482+ case 0x000d: // TxSize
483+ case 0x0015: // PnLocHFrac
484+ case 0x0016: // ChExtra
485+ case 0x0023: // ShortLineFrom
486+ case 0x00a0: // ShortComment
487+ SDL_RWseek(p, 2, SEEK_CUR);
488+ break;
489+
490+ case 0x0006: // SpExtra
491+ case 0x0007: // PnSize
492+ case 0x000b: // OvSize
493+ case 0x000c: // Origin
494+ case 0x000e: // FgColor
495+ case 0x000f: // BgColor
496+ case 0x0021: // LineFrom
497+ SDL_RWseek(p, 4, SEEK_CUR);
498+ break;
499+
500+ case 0x001a: // RGBFgCol
501+ case 0x001b: // RGBBkCol
502+ case 0x001d: // HiliteColor
503+ case 0x001f: // OpColor
504+ case 0x0022: // ShortLine
505+ SDL_RWseek(p, 6, SEEK_CUR);
506+ break;
507+
508+ case 0x0002: // BkPat
509+ case 0x0009: // PnPat
510+ case 0x000a: // FillPat
511+ case 0x0010: // TxRatio
512+ case 0x0020: // Line
513+ case 0x0030: // FrameRect
514+ case 0x0031: // PaintRect
515+ case 0x0032: // EraseRect
516+ case 0x0033: // InvertRect
517+ case 0x0034: // FillRect
518+ SDL_RWseek(p, 8, SEEK_CUR);
519+ break;
520+
521+ case 0x0c00: // HeaderOp
522+ SDL_RWseek(p, 24, SEEK_CUR);
523+ break;
524+
525+ case 0x00a1: { // LongComment
526+ SDL_RWseek(p, 2, SEEK_CUR);
527+ int size = SDL_ReadBE16(p);
528+ if (size & 1)
529+ size++;
530+ SDL_RWseek(p, size, SEEK_CUR);
531+ break;
532+ }
533+
534+ case 0x0098: // Packed CopyBits
535+ case 0x0099: // Packed CopyBits with clipping region
536+ case 0x009a: // Direct CopyBits
537+ case 0x009b: { // Direct CopyBits with clipping region
538+ // 1. PixMap
539+ if (opcode == 0x009a || opcode == 0x009b)
540+ SDL_RWseek(p, 4, SEEK_CUR); // pmBaseAddr
541+ uint16 row_bytes = SDL_ReadBE16(p); // the upper 2 bits are flags
542+ //printf(" row_bytes %04x\n", row_bytes);
543+ bool is_pixmap = ((row_bytes & 0x8000) != 0);
544+ row_bytes &= 0x3fff;
545+ uint16 top = SDL_ReadBE16(p);
546+ uint16 left = SDL_ReadBE16(p);
547+ uint16 height = SDL_ReadBE16(p) - top;
548+ uint16 width = SDL_ReadBE16(p) - left;
549+ uint16 pack_type, pixel_size;
550+ if (is_pixmap) {
551+ SDL_RWseek(p, 2, SEEK_CUR); // pmVersion
552+ pack_type = SDL_ReadBE16(p);
553+ SDL_RWseek(p, 14, SEEK_CUR); // packSize/hRes/vRes/pixelType
554+ pixel_size = SDL_ReadBE16(p);
555+ SDL_RWseek(p, 16, SEEK_CUR); // cmpCount/cmpSize/planeBytes/pmTable/pmReserved
556+ } else {
557+ pack_type = 0;
558+ pixel_size = 1;
559+ }
560+ //printf(" width %d, height %d, row_bytes %d, depth %d, pack_type %d\n", width, height, row_bytes, pixel_size, pack_type);
561+
562+ // Allocate surface for picture
563+ uint32 Rmask = 0, Gmask = 0, Bmask = 0;
564+ int surface_depth = 8;
565+ switch (pixel_size) {
566+ case 1:
567+ case 2:
568+ case 4:
569+ case 8:
570+ Rmask = Gmask = Bmask = 0xff;
571+ surface_depth = 8; // SDL surfaces must be at least 8 bits depth, so we expand 1/2/4-bit pictures to 8-bit
572+ break;
573+ case 16:
574+ Rmask = 0x7c00;
575+ Gmask = 0x03e0;
576+ Bmask = 0x001f;
577+ surface_depth = 16;
578+ break;
579+ case 32:
580+ Rmask = 0x00ff0000;
581+ Gmask = 0x0000ff00;
582+ Bmask = 0x000000ff;
583+ surface_depth = 32;
584+ break;
585+ default:
586+ fprintf(stderr, "Unsupported PICT depth %d\n", pixel_size);
587+ done = true;
588+ break;
589+ }
590+ if (done)
591+ break;
592+ SDL_Surface *bm = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, surface_depth, Rmask, Gmask, Bmask, 0);
593+ if (bm == NULL) {
594+ done = true;
595+ break;
596+ }
597+
598+ // 2. ColorTable
599+ if (is_pixmap && (opcode == 0x0098 || opcode == 0x0099)) {
600+ SDL_Color colors[256];
601+ SDL_RWseek(p, 4, SEEK_CUR); // ctSeed
602+ uint16 flags = SDL_ReadBE16(p);
603+ int num_colors = SDL_ReadBE16(p) + 1;
604+ for (int i=0; i<num_colors; i++) {
605+ uint8 value = SDL_ReadBE16(p) & 0xff;
606+ if (flags & 0x8000)
607+ value = i;
608+ colors[value].r = SDL_ReadBE16(p) >> 8;
609+ colors[value].g = SDL_ReadBE16(p) >> 8;
610+ colors[value].b = SDL_ReadBE16(p) >> 8;
611+ }
612+ SDL_SetColors(bm, colors, 0, 256);
613+ }
614+
615+ // 3. source/destination Rect and transfer mode
616+ SDL_RWseek(p, 18, SEEK_CUR);
617+
618+ // 4. clipping region
619+ if (opcode == 0x0099 || opcode == 0x009b) {
620+ uint16 rgn_size = SDL_ReadBE16(p);
621+ SDL_RWseek(p, rgn_size - 2, SEEK_CUR);
622+ }
623+
624+ // 5. graphics data
625+ int data_size = uncompress_picture((uint8 *)rsrc.GetPointer() + SDL_RWtell(p), row_bytes, (uint8 *)bm->pixels, bm->pitch, pixel_size, height, pack_type);
626+ if (data_size < 0) {
627+ done = true;
628+ break;
629+ }
630+ if (data_size & 1)
631+ data_size++;
632+ SDL_RWseek(p, data_size, SEEK_CUR);
633+
634+ // If there's already a surface, throw away the decoded image
635+ // (actually, we could have skipped this entire opcode, but the
636+ // only way to do this is to decode the image data).
637+ // So we only draw the first image we encounter.
638+ if( ! s ) {
639+ int real = width > pic_width ? width : pic_width;
640+ s = SDL_CreateRGBSurface(SDL_SWSURFACE, real, pic_height, 32,
641+#ifdef ALEPHONE_LITTLE_ENDIAN
642+ 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
643+#else
644+ 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff
645+#endif
646+ );
647+ }
648+ SDL_Rect R = {left, top, width, height };
649+ SDL_BlitSurface(bm, NULL, s, &R);
650+ SDL_FreeSurface(bm);
651+ // if (s)
652+ // SDL_FreeSurface(bm);
653+ // else
654+ // s = bm;
655+ break;
656+ }
657+
658+#ifdef HAVE_SDL_IMAGE
659+ case 0x8200: { // Compressed QuickTime image (we only handle JPEG compression)
660+ // 1. Header
661+ uint32 opcode_size = SDL_ReadBE32(p);
662+ if (opcode_size & 1)
663+ opcode_size++;
664+ uint32 opcode_start = SDL_RWtell(p);
665+ SDL_RWseek(p, 26, SEEK_CUR); // version/matrix (hom. part)
666+ int offset_x = SDL_ReadBE16(p);
667+ SDL_RWseek(p, 2, SEEK_CUR);
668+ int offset_y = SDL_ReadBE16(p);
669+ SDL_RWseek(p, 6, SEEK_CUR); // matrix (remaining part)
670+ uint32 matte_size = SDL_ReadBE32(p);
671+ SDL_RWseek(p, 22, SEEK_CUR); // matteRec/mode/srcRect/accuracy
672+ uint32 mask_size = SDL_ReadBE32(p);
673+
674+ // 2. Matte image description
675+ if (matte_size) {
676+ uint32 matte_id_size = SDL_ReadBE32(p);
677+ SDL_RWseek(p, matte_id_size - 4, SEEK_CUR);
678+ }
679+
680+ // 3. Matte data
681+ SDL_RWseek(p, matte_size, SEEK_CUR);
682+
683+ // 4. Mask region
684+ SDL_RWseek(p, mask_size, SEEK_CUR);
685+
686+ // 5. Image description
687+ uint32 id_start = SDL_RWtell(p);
688+ uint32 id_size = SDL_ReadBE32(p);
689+ uint32 codec_type = SDL_ReadBE32(p);
690+ if (codec_type != FOUR_CHARS_TO_INT('j','p','e','g')) {
691+ fprintf(stderr, "Unsupported codec type %c%c%c%c\n", codec_type >> 24, codec_type >> 16, codec_type >> 8, codec_type);
692+ done = true;
693+ break;
694+ }
695+ SDL_RWseek(p, 36, SEEK_CUR); // resvd1/resvd2/dataRefIndex/version/revisionLevel/vendor/temporalQuality/spatialQuality/width/height/hRes/vRes
696+ uint32 data_size = SDL_ReadBE32(p);
697+ SDL_RWseek(p, id_start + id_size, SEEK_SET);
698+
699+ // Allocate surface for complete (but possibly banded) picture
700+ if (s == NULL) {
701+ s = SDL_CreateRGBSurface(SDL_SWSURFACE, pic_width, pic_height, 32,
702+#ifdef ALEPHONE_LITTLE_ENDIAN
703+ 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000
704+#else
705+ 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff
706+#endif
707+ );
708+ if (s == NULL) {
709+ done = true;
710+ break;
711+ }
712+ }
713+
714+ // 6. Compressed image data
715+ SDL_RWops *img = SDL_RWFromMem((uint8 *)rsrc.GetPointer() + SDL_RWtell(p), data_size);
716+ if (img == NULL) {
717+ done = true;
718+ break;
719+ }
720+ SDL_Surface *bm = IMG_LoadTyped_RW(img, true, const_cast<char*>("JPG"));
721+
722+ // Copy image (band) into surface
723+ if (bm) {
724+ SDL_Rect dst_rect = {offset_x, offset_y, bm->w, bm->h};
725+ SDL_BlitSurface(bm, NULL, s, &dst_rect);
726+ SDL_FreeSurface(bm);
727+ }
728+
729+ SDL_RWseek(p, opcode_start + opcode_size, SEEK_SET);
730+ break;
731+ }
732+#endif
733+
734+ default:
735+ if (opcode >= 0x0300 && opcode < 0x8000)
736+ SDL_RWseek(p, (opcode >> 8) * 2, SEEK_CUR);
737+ else if (opcode >= 0x8000 && opcode < 0x8100)
738+ break;
739+ else {
740+ fprintf(stderr, "Unimplemented opcode %04x in PICT resource\n", opcode);
741+ done = true;
742+ }
743+ break;
744+ }
745+ }
746+
747+ // Close stream, return surface
748+ SDL_RWclose(p);
749+ return s;
750+}
751+
752+
753+/*
754+ * Rescale surface to given dimensions
755+ */
756+
757+template <class T>
758+static void rescale(T *src_pixels, int src_pitch, T *dst_pixels, int dst_pitch, int width, int height, uint32 dx, uint32 dy)
759+{
760+ // Brute-force rescaling, no interpolation
761+ uint32 sy = 0;
762+ for (int y=0; y<height; y++) {
763+ T *p = src_pixels + src_pitch / sizeof(T) * (sy >> 16);
764+ uint32 sx = 0;
765+ for (int x=0; x<width; x++) {
766+ dst_pixels[x] = p[sx >> 16];
767+ sx += dx;
768+ }
769+ dst_pixels += dst_pitch / sizeof(T);
770+ sy += dy;
771+ }
772+}
773+
774+SDL_Surface *rescale_surface(SDL_Surface *s, int width, int height)
775+{
776+ if (s == NULL)
777+ return NULL;
778+
779+ SDL_Surface *s2 = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, s->format->BitsPerPixel, s->format->Rmask, s->format->Gmask, s->format->Bmask, s->format->Amask);
780+ if (s2 == NULL)
781+ return NULL;
782+
783+ uint32 dx = (s->w << 16) / width;
784+ uint32 dy = (s->h << 16) / height;
785+
786+ switch (s->format->BytesPerPixel) {
787+ case 1:
788+ rescale((pixel8 *)s->pixels, s->pitch, (pixel8 *)s2->pixels, s2->pitch, width, height, dx, dy);
789+ break;
790+ case 2:
791+ rescale((pixel16 *)s->pixels, s->pitch, (pixel16 *)s2->pixels, s2->pitch, width, height, dx, dy);
792+ break;
793+ case 4:
794+ rescale((pixel32 *)s->pixels, s->pitch, (pixel32 *)s2->pixels, s2->pitch, width, height, dx, dy);
795+ break;
796+ }
797+
798+ if (s->format->palette)
799+ SDL_SetColors(s2, s->format->palette->colors, 0, s->format->palette->ncolors);
800+
801+ return s2;
802+}
803+
804+
805+/*
806+ * Tile surface to fill given dimensions
807+ */
808+
809+template <class T>
810+static void tile(T *src_pixels, int src_pitch, T *dst_pixels, int dst_pitch, int src_width, int src_height, int dst_width, int dst_height)
811+{
812+ T *p = src_pixels;
813+ int sy = 0;
814+ for (int y=0; y<dst_height; y++) {
815+ int sx = 0;
816+ for (int x=0; x<dst_width; x++) {
817+ dst_pixels[x] = p[sx];
818+ sx++;
819+ if (sx == src_width)
820+ sx = 0;
821+ }
822+ dst_pixels += dst_pitch / sizeof(T);
823+ sy++;
824+ if (sy == src_height) {
825+ sy = 0;
826+ p = src_pixels;
827+ } else
828+ p += src_pitch / sizeof(T);
829+ }
830+}
831+
832+SDL_Surface *tile_surface(SDL_Surface *s, int width, int height)
833+{
834+ if (s == NULL)
835+ return NULL;
836+
837+ SDL_Surface *s2 = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, s->format->BitsPerPixel, s->format->Rmask, s->format->Gmask, s->format->Bmask, s->format->Amask);
838+ if (s2 == NULL)
839+ return NULL;
840+
841+ switch (s->format->BytesPerPixel) {
842+ case 1:
843+ tile((pixel8 *)s->pixels, s->pitch, (pixel8 *)s2->pixels, s2->pitch, s->w, s->h, width, height);
844+ break;
845+ case 2:
846+ tile((pixel16 *)s->pixels, s->pitch, (pixel16 *)s2->pixels, s2->pitch, s->w, s->h, width, height);
847+ break;
848+ case 3:
849+ tile((pixel8 *)s->pixels, s->pitch, (pixel8 *)s2->pixels, s2->pitch, s->w * 3, s->h, width * 3, height);
850+ break;
851+ case 4:
852+ tile((pixel32 *)s->pixels, s->pitch, (pixel32 *)s2->pixels, s2->pitch, s->w, s->h, width, height);
853+ break;
854+ }
855+
856+ if (s->format->palette)
857+ SDL_SetColors(s2, s->format->palette->colors, 0, s->format->palette->ncolors);
858+
859+ return s2;
860+}
861+
862+
863+/*
864+ * Draw picture resource centered on screen
865+ */
866+
867+extern SDL_Surface *draw_surface; // from screen_drawing.cpp
868+//void draw_intro_screen(void); // from screen.cpp
869+
870+static void draw_picture(LoadedResource &rsrc)
871+{
872+ // Convert picture resource to surface, free resource
873+ SDL_Surface *s = picture_to_surface(rsrc);
874+ if (s == NULL)
875+ return;
876+ _set_port_to_intro();
877+ SDL_Surface *video = draw_surface;
878+
879+ // Default source rectangle
880+ SDL_Rect src_rect = {0, 0, MIN(s->w, 640), MIN(s->h, 480)};
881+
882+ // Center picture on screen
883+ SDL_Rect dst_rect = {(video->w - src_rect.w) / 2, (video->h - src_rect.h) / 2, s->w, s->h};
884+ if (dst_rect.x < 0)
885+ dst_rect.x = 0;
886+ if (dst_rect.y < 0)
887+ dst_rect.y = 0;
888+
889+ // Clip if desired (only used for menu buttons)
890+ if (draw_clip_rect_active) {
891+ src_rect.w = dst_rect.w = draw_clip_rect.right - draw_clip_rect.left;
892+ src_rect.h = dst_rect.h = draw_clip_rect.bottom - draw_clip_rect.top;
893+ src_rect.x = draw_clip_rect.left - (640 - s->w) / 2;
894+ src_rect.y = draw_clip_rect.top - (480 - s->h) / 2;
895+ dst_rect.x += draw_clip_rect.left- (640 - s->w) / 2;
896+ dst_rect.y += draw_clip_rect.top - (480 - s->h) / 2;
897+ } else {
898+ // Clear destination to black
899+ SDL_FillRect(video, NULL, SDL_MapRGB(video->format, 0, 0, 0));
900+ }
901+
902+ SDL_BlitSurface(s, &src_rect, video, &dst_rect);
903+ _restore_port();
904+ draw_intro_screen();
905+}
906+
907+
908+/*
909+ * Get system color table
910+ */
911+
912+struct color_table *build_8bit_system_color_table(void)
913+{
914+ // 6*6*6 RGB color cube
915+ color_table *table = new color_table;
916+ table->color_count = 6*6*6;
917+ int index = 0;
918+ for (int red=0; red<6; red++) {
919+ for (int green=0; green<6; green++) {
920+ for (int blue=0; blue<6; blue++) {
921+ uint8 r = red * 0x33;
922+ uint8 g = green * 0x33;
923+ uint8 b = blue * 0x33;
924+ table->colors[index].red = (r << 8) | r;
925+ table->colors[index].green = (g << 8) | g;
926+ table->colors[index].blue = (b << 8) | b;
927+ index++;
928+ }
929+ }
930+ }
931+ return table;
932+}
933+
934+
935+/*
936+ * Scroll image across screen
937+ */
938+
939+#define SCROLLING_SPEED (MACHINE_TICKS_PER_SECOND / 20)
940+
941+void scroll_full_screen_pict_resource_from_scenario(int pict_resource_number, bool text_block)
942+{
943+ // Convert picture resource to surface, free resource
944+ LoadedResource rsrc;
945+ get_picture_resource_from_scenario(pict_resource_number, rsrc);
946+ SDL_Surface *s = picture_to_surface(rsrc);
947+ if (s == NULL)
948+ return;
949+
950+ // Find out in which direction to scroll
951+ int picture_width = s->w;
952+ int picture_height = s->h;
953+ int screen_width = 640;
954+ int screen_height = 480;
955+ bool scroll_horizontal = picture_width > screen_width;
956+ bool scroll_vertical = picture_height > screen_height;
957+
958+ if (scroll_horizontal || scroll_vertical) {
959+
960+ // Flush events
961+ SDL_Event event;
962+ while (SDL_PollEvent(&event)) ;
963+
964+ // Prepare source and destination rectangles
965+ SDL_Rect src_rect = {0, 0, scroll_horizontal ? screen_width : picture_width, scroll_vertical ? screen_height : picture_height};
966+ SDL_Rect dst_rect = {0, 0, screen_width, screen_height};
967+
968+ // Scroll loop
969+ bool done = false, aborted = false;
970+ uint32 start_tick = SDL_GetTicks();
971+ do {
972+
973+ int32 delta = (SDL_GetTicks() - start_tick) / (text_block ? (2 * SCROLLING_SPEED) : SCROLLING_SPEED);
974+ if (scroll_horizontal && delta > picture_width - screen_width) {
975+ delta = picture_width - screen_width;
976+ done = true;
977+ }
978+ if (scroll_vertical && delta > picture_height - screen_height) {
979+ delta = picture_height - screen_height;
980+ done = true;
981+ }
982+
983+ // Blit part of picture
984+ src_rect.x = scroll_horizontal ? delta : 0;
985+ src_rect.y = scroll_vertical ? delta : 0;
986+ _set_port_to_intro();
987+ SDL_BlitSurface(s, &src_rect, draw_surface, &dst_rect);
988+ _restore_port();
989+ draw_intro_screen();
990+
991+ // Give system time
992+ global_idle_proc();
993+ SDL_Delay(10);
994+
995+ // Check for events to abort
996+ event.type = SDL_NOEVENT;
997+ SDL_PollEvent(&event);
998+ switch (event.type) {
999+ case SDL_MOUSEBUTTONDOWN:
1000+ case SDL_KEYDOWN:
1001+ aborted = true;
1002+ break;
1003+ }
1004+
1005+ } while (!done && !aborted);
1006+ }
1007+
1008+ // Free surface
1009+ SDL_FreeSurface(s);
1010+}
1011+
1012+
1013+/*
1014+ * Initialize image manager, open Images file
1015+ */
1016+
1017+void initialize_images_manager(void)
1018+{
1019+ FileSpecifier file;
1020+
1021+ logContext("loading Images...");
1022+
1023+ file.SetNameWithPath(getcstr(temporary, strFILENAMES, filenameIMAGES)); // _typecode_images
1024+
1025+ if (!file.Exists())
1026+ alert_user(fatalError, strERRORS, badExtraFileLocations, fnfErr);
1027+
1028+ if (!ImagesFile.open_file(file))
1029+ alert_user(fatalError, strERRORS, badExtraFileLocations, -1);
1030+
1031+ atexit(shutdown_images_handler);
1032+}
1033+
1034+
1035+/*
1036+ * Shutdown image manager
1037+ */
1038+
1039+static void shutdown_images_handler(void)
1040+{
1041+ ScenarioFile.close_file();
1042+ ImagesFile.close_file();
1043+}
1044+
1045+
1046+/*
1047+ * Set map file to load images from
1048+ */
1049+
1050+void set_scenario_images_file(FileSpecifier &file)
1051+{
1052+ ScenarioFile.open_file(file);
1053+}
1054+
1055+
1056+/*
1057+ * Open/close image file
1058+ */
1059+
1060+bool image_file_t::open_file(FileSpecifier &file)
1061+{
1062+ close_file();
1063+
1064+ // Try to open as a resource file
1065+ if (!file.Open(rsrc_file)) {
1066+
1067+ // This failed, maybe it's a wad file (M2 Win95 style)
1068+ if (!open_wad_file_for_reading(file, wad_file)
1069+ || !read_wad_header(wad_file, &wad_hdr)) {
1070+
1071+ // This also failed, bail out
1072+ wad_file.Close();
1073+ return false;
1074+ }
1075+ } // Try to open wad file, too
1076+ else if (!wad_file.IsOpen()) {
1077+ if (open_wad_file_for_reading(file, wad_file)) {
1078+ if (!read_wad_header(wad_file, &wad_hdr)) {
1079+
1080+ wad_file.Close();
1081+ }
1082+ }
1083+ }
1084+
1085+ return true;
1086+}
1087+
1088+void image_file_t::close_file(void)
1089+{
1090+ rsrc_file.Close();
1091+ wad_file.Close();
1092+}
1093+
1094+bool image_file_t::is_open(void)
1095+{
1096+ return rsrc_file.IsOpen() || wad_file.IsOpen();
1097+}
1098+
1099+
1100+/*
1101+ * Get resource from file
1102+ */
1103+
1104+bool image_file_t::has_rsrc(uint32 rsrc_type, uint32 wad_type, int id)
1105+{
1106+ // Check for resource in resource file
1107+ if (rsrc_file.IsOpen())
1108+ {
1109+ if (rsrc_file.Check(rsrc_type, id))
1110+ return true;
1111+ }
1112+
1113+ // Check for resource in wad file
1114+ if (wad_file.IsOpen()) {
1115+ wad_data *d = read_indexed_wad_from_file(wad_file, &wad_hdr, id, true);
1116+ if (d) {
1117+ bool success = false;
1118+ size_t len;
1119+ if (extract_type_from_wad(d, wad_type, &len))
1120+ success = true;
1121+ free_wad(d);
1122+ return success;
1123+ }
1124+ }
1125+
1126+ return false;
1127+}
1128+
1129+bool image_file_t::has_pict(int id)
1130+{
1131+ return has_rsrc(FOUR_CHARS_TO_INT('P','I','C','T'), FOUR_CHARS_TO_INT('P','I','C','T'), id) || has_rsrc(FOUR_CHARS_TO_INT('P','I','C','T'), FOUR_CHARS_TO_INT('p','i','c','t'), id);
1132+}
1133+
1134+bool image_file_t::has_clut(int id)
1135+{
1136+ return has_rsrc(FOUR_CHARS_TO_INT('c','l','u','t'), FOUR_CHARS_TO_INT('c','l','u','t'), id);
1137+}
1138+
1139+bool image_file_t::get_rsrc(uint32 rsrc_type, uint32 wad_type, int id, LoadedResource &rsrc)
1140+{
1141+ // Get resource from resource file
1142+ if (rsrc_file.IsOpen())
1143+ {
1144+ if (rsrc_file.Get(rsrc_type, id, rsrc))
1145+ return true;
1146+ }
1147+
1148+ // Get resource from wad file
1149+ if (wad_file.IsOpen()) {
1150+ wad_data *d = read_indexed_wad_from_file(wad_file, &wad_hdr, id, true);
1151+ if (d) {
1152+ bool success = false;
1153+ size_t raw_length;
1154+ void *raw = extract_type_from_wad(d, wad_type, &raw_length);
1155+ if (raw)
1156+ {
1157+ if (rsrc_type == FOUR_CHARS_TO_INT('P','I','C','T'))
1158+ {
1159+ if (wad_type == FOUR_CHARS_TO_INT('P','I','C','T'))
1160+ {
1161+ void *pict_data = malloc(raw_length);
1162+ memcpy(pict_data, raw, raw_length);
1163+ rsrc.SetData(pict_data, raw_length);
1164+ success = true;
1165+ }
1166+ else
1167+ {
1168+ size_t clut_length;
1169+ void *clut_data = extract_type_from_wad(d, FOUR_CHARS_TO_INT('c','l','u','t'), &clut_length);
1170+ success = make_rsrc_from_pict(raw, raw_length, rsrc, clut_data, clut_length);
1171+ }
1172+ }
1173+ else if (rsrc_type == FOUR_CHARS_TO_INT('c','l','u','t'))
1174+ success = make_rsrc_from_clut(raw, raw_length, rsrc);
1175+ else if (rsrc_type == FOUR_CHARS_TO_INT('s','n','d',' '))
1176+ {
1177+ void *snd_data = malloc(raw_length);
1178+ memcpy(snd_data, raw, raw_length);
1179+ rsrc.SetData(snd_data, raw_length);
1180+ success = true;
1181+ }
1182+ else if (rsrc_type == FOUR_CHARS_TO_INT('T','E','X','T'))
1183+ {
1184+ void *text_data = malloc(raw_length);
1185+ memcpy(text_data, raw, raw_length);
1186+ rsrc.SetData(text_data, raw_length);
1187+ success = true;
1188+ }
1189+ }
1190+ free_wad(d);
1191+ return success;
1192+ }
1193+ }
1194+
1195+ return false;
1196+}
1197+
1198+bool image_file_t::get_pict(int id, LoadedResource &rsrc)
1199+{
1200+ return get_rsrc(FOUR_CHARS_TO_INT('P','I','C','T'), FOUR_CHARS_TO_INT('P','I','C','T'), id, rsrc) || get_rsrc(FOUR_CHARS_TO_INT('P','I','C','T'), FOUR_CHARS_TO_INT('p','i','c','t'), id, rsrc);
1201+}
1202+
1203+bool image_file_t::get_clut(int id, LoadedResource &rsrc)
1204+{
1205+ return get_rsrc(FOUR_CHARS_TO_INT('c','l','u','t'), FOUR_CHARS_TO_INT('c','l','u','t'), id, rsrc);
1206+}
1207+
1208+bool image_file_t::get_snd(int id, LoadedResource &rsrc)
1209+{
1210+ return get_rsrc(FOUR_CHARS_TO_INT('s','n','d',' '), FOUR_CHARS_TO_INT('s','n','d',' '), id, rsrc);
1211+}
1212+
1213+bool image_file_t::get_text(int id, LoadedResource &rsrc)
1214+{
1215+ return get_rsrc(FOUR_CHARS_TO_INT('T','E','X','T'), FOUR_CHARS_TO_INT('t','e','x','t'), id, rsrc);
1216+}
1217+
1218+
1219+/*
1220+ * Get/draw image from Images file
1221+ */
1222+
1223+bool get_picture_resource_from_images(int base_resource, LoadedResource &PictRsrc)
1224+{
1225+ assert(ImagesFile.is_open());
1226+
1227+ int RsrcID = ImagesFile.determine_pict_resource_id(
1228+ base_resource, _images_file_delta16, _images_file_delta32);
1229+ return ImagesFile.get_pict(RsrcID, PictRsrc);
1230+}
1231+
1232+bool images_picture_exists(int base_resource)
1233+{
1234+ assert(ImagesFile.is_open());
1235+
1236+ int RsrcID = ImagesFile.determine_pict_resource_id(
1237+ base_resource, _images_file_delta16, _images_file_delta32);
1238+ return ImagesFile.has_pict(RsrcID);
1239+}
1240+
1241+void draw_full_screen_pict_resource_from_images(int pict_resource_number)
1242+{
1243+ LoadedResource PictRsrc;
1244+ get_picture_resource_from_images(pict_resource_number, PictRsrc);
1245+ draw_picture(PictRsrc);
1246+}
1247+
1248+
1249+/*
1250+ * Get/draw image from scenario
1251+ */
1252+
1253+bool get_picture_resource_from_scenario(int base_resource, LoadedResource &PictRsrc)
1254+{
1255+ if (!ScenarioFile.is_open())
1256+ return false;
1257+
1258+ int RsrcID = ScenarioFile.determine_pict_resource_id(
1259+ base_resource, _scenario_file_delta16, _scenario_file_delta32);
1260+
1261+ bool success = ScenarioFile.get_pict(RsrcID, PictRsrc);
1262+#ifdef mac
1263+ if (success) {
1264+ Handle PictHdl = PictRsrc.GetHandle();
1265+ if (PictHdl) HNoPurge(PictHdl);
1266+ }
1267+#endif
1268+ return success;
1269+}
1270+
1271+bool scenario_picture_exists(int base_resource)
1272+{
1273+ if (!ScenarioFile.is_open())
1274+ return false;
1275+
1276+ int RsrcID = ScenarioFile.determine_pict_resource_id(
1277+ base_resource, _scenario_file_delta16, _scenario_file_delta32);
1278+ return ScenarioFile.has_pict(RsrcID);
1279+}
1280+
1281+void draw_full_screen_pict_resource_from_scenario(int pict_resource_number)
1282+{
1283+ LoadedResource PictRsrc;
1284+ get_picture_resource_from_scenario(pict_resource_number, PictRsrc);
1285+ draw_picture(PictRsrc);
1286+}
1287+
1288+
1289+/*
1290+ * Get sound resource from scenario
1291+ */
1292+
1293+bool get_sound_resource_from_scenario(int resource_number, LoadedResource &SoundRsrc)
1294+{
1295+ if (!ScenarioFile.is_open())
1296+ return false;
1297+
1298+ bool success = ScenarioFile.get_snd(resource_number, SoundRsrc);
1299+#ifdef mac
1300+ if (success) {
1301+ Handle SndHdl = SoundRsrc.GetHandle();
1302+ if (SndHdl) HNoPurge(SndHdl);
1303+ }
1304+#endif
1305+ return success;
1306+}
1307+
1308+
1309+// LP: do the same for text resources
1310+
1311+bool get_text_resource_from_scenario(int resource_number, LoadedResource &TextRsrc)
1312+{
1313+ if (!ScenarioFile.is_open())
1314+ return false;
1315+
1316+ bool success = ScenarioFile.get_text(resource_number, TextRsrc);
1317+#ifdef mac
1318+ if (success) {
1319+ Handle TxtHdl = TextRsrc.GetHandle();
1320+ if (TxtHdl) HNoPurge(TxtHdl);
1321+ }
1322+#endif
1323+ return success;
1324+}
1325+
1326+
1327+/*
1328+ * Calculate color table for image
1329+ */
1330+
1331+struct color_table *calculate_picture_clut(int CLUTSource, int pict_resource_number)
1332+{
1333+ struct color_table *picture_table = NULL;
1334+
1335+ // Select the source
1336+ image_file_t *OFilePtr = NULL;
1337+ switch (CLUTSource) {
1338+ case CLUTSource_Images:
1339+ OFilePtr = &ImagesFile;
1340+ break;
1341+
1342+ case CLUTSource_Scenario:
1343+ OFilePtr = &ScenarioFile;
1344+ break;
1345+
1346+ default:
1347+ vassert(false, csprintf(temporary, "Invalid resource-file selector: %d", CLUTSource));
1348+ break;
1349+ }
1350+
1351+ // Load CLUT resource
1352+ LoadedResource CLUT_Rsrc;
1353+ if (OFilePtr->get_clut(pict_resource_number, CLUT_Rsrc)) {
1354+
1355+#ifdef mac
1356+ Handle resource = CLUT_Rsrc.GetHandle();
1357+ HNoPurge(resource);
1358+#endif
1359+
1360+ // Allocate color table
1361+ picture_table = new color_table;
1362+
1363+ // Convert MacOS CLUT resource to color table
1364+ if (interface_bit_depth == 8)
1365+ build_color_table(picture_table, CLUT_Rsrc);
1366+ else
1367+ build_direct_color_table(picture_table, interface_bit_depth);
1368+ }
1369+
1370+ return picture_table;
1371+}
1372+
1373+
1374+/*
1375+ * Determine ID for picture resource
1376+ */
1377+
1378+int image_file_t::determine_pict_resource_id(int base_id, int delta16, int delta32)
1379+{
1380+ int actual_id = base_id;
1381+ bool done = false;
1382+ int bit_depth = interface_bit_depth;
1383+
1384+ while (!done) {
1385+ int next_bit_depth;
1386+
1387+ actual_id = base_id;
1388+ switch(bit_depth) {
1389+ case 8:
1390+ next_bit_depth = 0;
1391+ break;
1392+
1393+ case 16:
1394+ next_bit_depth = 8;
1395+ actual_id += delta16;
1396+ break;
1397+
1398+ case 32:
1399+ next_bit_depth = 16;
1400+ actual_id += delta32;
1401+ break;
1402+
1403+ default:
1404+ assert(false);
1405+ break;
1406+ }
1407+
1408+ if (has_pict(actual_id))
1409+ done = true;
1410+
1411+ if (!done) {
1412+ if (next_bit_depth)
1413+ bit_depth = next_bit_depth;
1414+ else {
1415+ // Didn't find it. Return the 8 bit version and bail..
1416+ done = true;
1417+ }
1418+ }
1419+ }
1420+ return actual_id;
1421+}
1422+
1423+
1424+/*
1425+ * Convert picture and CLUT data from wad file to PICT resource
1426+ */
1427+
1428+#ifdef mac
1429+
1430+// MacOS version
1431+bool image_file_t::make_rsrc_from_pict(void *data, size_t length, LoadedResource &rsrc, void *clut_data, size_t clut_length)
1432+{
1433+ pict_head *head;
1434+ PicHandle picture;
1435+ Rect bounds;
1436+ short i;
1437+ GWorldPtr gworld;
1438+ PixMapHandle pixmap;
1439+ void *pict_data;
1440+ void *clut;
1441+ uint8 *p, *q;
1442+ CTabHandle clut_handle;
1443+ CGrafPtr saveport;
1444+
1445+ if (length < 10)
1446+ return false;
1447+
1448+ head = (pict_head *)data;
1449+
1450+ bounds.left = head->bounds.left;
1451+ bounds.top = head->bounds.top;
1452+ bounds.right = head->bounds.right;
1453+ bounds.bottom = head->bounds.bottom;
1454+
1455+ if (head->depth == 8)
1456+ {
1457+
1458+ clut = malloc(8 + 256 * 8);
1459+
1460+ memset(clut, 0, 8 + 256 * 8);
1461+
1462+ p = (uint8 *)clut_data;
1463+ q = (uint8 *)clut;
1464+
1465+ // 1. Header
1466+ q[6] = p[0]; // color count
1467+ q[7] = p[1];
1468+ p += 6;
1469+ q += 8;
1470+
1471+ // 2. Color table
1472+ for (i = 0; i < 256; i++)
1473+ {
1474+ q++;
1475+ *q++ = i; // value
1476+ *q++ = *p++; // red
1477+ *q++ = *p++;
1478+ *q++ = *p++; // green
1479+ *q++ = *p++;
1480+ *q++ = *p++; // blue
1481+ *q++ = *p++;
1482+ }
1483+
1484+ clut_handle = (CTabHandle)NewHandleClear(8 + 256 * 8);
1485+
1486+ PtrToHand(clut, (Handle *)&clut_handle, 8 + 256 * 8);
1487+
1488+ QTNewGWorldFromPtr(&gworld, k8IndexedPixelFormat, &bounds, clut_handle, NULL, 0, (uint8 *)data + 10, head->bounds.right - head->bounds.left);
1489+
1490+ free(clut);
1491+ DisposeHandle((Handle)clut_handle);
1492+ }
1493+ else if (head->depth == 16)
1494+ {
1495+ QTNewGWorldFromPtr(&gworld, k16BE555PixelFormat, &bounds, NULL, NULL, 0, (uint8 *)data + 10, (head->bounds.right - head->bounds.left) * 2);
1496+ }
1497+ else if (head->depth == 24)
1498+ {
1499+ QTNewGWorldFromPtr(&gworld, k24RGBPixelFormat, &bounds, NULL, NULL, 0, (uint8 *)data + 10, (head->bounds.right - head->bounds.left) * 3);
1500+ }
1501+ else if (head->depth == 32)
1502+ {
1503+ QTNewGWorldFromPtr(&gworld, k32ARGBPixelFormat, &bounds, NULL, NULL, 0, (uint8 *)data + 10, (head->bounds.right - head->bounds.left) * 4);
1504+ }
1505+ else
1506+ {
1507+ return false;
1508+ }
1509+
1510+ PenNormal();
1511+
1512+ GetGWorld(&saveport, NULL);
1513+ SetGWorld(gworld, NULL);
1514+
1515+ ForeColor(blackColor);
1516+ BackColor(whiteColor);
1517+
1518+ pixmap = GetGWorldPixMap(gworld);
1519+ LockPixels(pixmap);
1520+
1521+ picture = OpenPicture(&bounds);
1522+
1523+ if (picture != NULL)
1524+ {
1525+ CopyBits((BitMap *)*pixmap, (BitMap *)*pixmap, &bounds, &bounds, srcCopy, NULL);
1526+ ClosePicture();
1527+ }
1528+
1529+ if (picture != NULL)
1530+ {
1531+ UnlockPixels(pixmap);
1532+ SetGWorld(saveport, NULL);
1533+ DisposeGWorld(gworld);
1534+
1535+ HLock((Handle)picture);
1536+ pict_data = malloc(GetHandleSize((Handle)picture));
1537+ memcpy(pict_data, *picture, GetHandleSize((Handle)picture));
1538+
1539+ rsrc.SetData(pict_data, GetHandleSize((Handle)picture));
1540+ KillPicture(picture);
1541+ }
1542+
1543+ return true;
1544+}
1545+
1546+#else
1547+
1548+// SDL version
1549+bool image_file_t::make_rsrc_from_pict(void *data, size_t length, LoadedResource &rsrc, void *clut_data, size_t clut_length)
1550+{
1551+ if (length < 10)
1552+ return false;
1553+
1554+ // Extract size and depth
1555+ uint8 *p = (uint8 *)data;
1556+ int height = (p[4] << 8) + p[5];
1557+ int width = (p[6] << 8) + p[7];
1558+ int depth = (p[8] << 8) + p[9];
1559+ if (depth != 8 && depth != 16)
1560+ return false;
1561+
1562+ // 8-bit depth requires CLUT
1563+ if (depth == 8) {
1564+ if (clut_data == NULL || clut_length != 6 + 256 * 6)
1565+ return false;
1566+ }
1567+
1568+ // size(2), rect(8), versionOp(2), version(2), headerOp(26)
1569+ int output_length = 2 + 8 + 2 + 2 + 26;
1570+ int row_bytes;
1571+ if (depth == 8) {
1572+ // opcode(2), pixMap(46), colorTable(8+256*8), srcRect/dstRect/mode(18), data(variable)
1573+ row_bytes = width;
1574+ output_length += 2 + 46 + 8+256*8 + 18;
1575+ } else {
1576+ // opcode(2), pixMap(50), srcRect/dstRect/mode(18), data(variable)
1577+ row_bytes = width * 2;
1578+ output_length += 2 + 50 + 18;
1579+ }
1580+ // data(variable), opEndPic(2)
1581+ output_length += row_bytes * height + 2;
1582+
1583+ // Allocate memory for Mac PICT resource
1584+ void *pict_rsrc = malloc(output_length);
1585+ if (pict_rsrc == NULL)
1586+ return false;
1587+ memset(pict_rsrc, 0, output_length);
1588+
1589+ // Convert pict tag to Mac PICT resource
1590+ uint8 *q = (uint8 *)pict_rsrc;
1591+
1592+ // 1. PICT header
1593+ q[0] = output_length >> 8;
1594+ q[1] = output_length;
1595+ memcpy(q + 2, p, 8);
1596+ q += 10;
1597+
1598+ // 2. VersionOp/Version/HeaderOp<