FS2_Open
Open source remastering of the Freespace 2 engine
lua.cpp
Go to the documentation of this file.
1 #include "ai/ai.h"
2 #include "ai/aigoals.h"
3 #include "asteroid/asteroid.h"
4 #include "camera/camera.h"
5 #include "cfile/cfilesystem.h"
6 #include "cmdline/cmdline.h"
7 #include "cutscene/movie.h"
8 #include "debris/debris.h"
10 #include "freespace2/freespace.h"
12 #include "globalincs/linklist.h"
13 #include "graphics/2d.h"
14 #include "graphics/font.h"
16 #include "hud/hudbrackets.h"
17 #include "hud/hudconfig.h"
18 #include "hud/hudescort.h"
19 #include "hud/hudets.h"
20 #include "hud/hudgauges.h"
21 #include "hud/hudshield.h"
22 #include "iff_defs/iff_defs.h"
23 #include "io/joy.h"
24 #include "io/key.h"
25 #include "io/mouse.h"
26 #include "io/timer.h"
27 #include "jumpnode/jumpnode.h"
28 #include "lighting/lighting.h"
29 #include "menuui/credits.h"
31 #include "mission/missiongoals.h"
32 #include "mission/missionload.h"
33 #include "mission/missionlog.h"
34 #include "mission/missionmessage.h"
36 #include "missionui/missionbrief.h"
37 #include "model/model.h"
38 #include "network/multi.h"
39 #include "network/multimsgs.h"
40 #include "object/objectshield.h"
41 #include "object/waypoint.h"
42 #include "parse/lua.h"
43 #include "parse/parselo.h"
44 #include "parse/scripting.h"
45 #include "particle/particle.h"
46 #include "playerman/player.h"
47 #include "render/3d.h"
48 #include "render/3dinternal.h"
49 #include "ship/ship.h"
50 #include "ship/shipfx.h"
51 #include "ship/shiphit.h"
52 #include "sound/audiostr.h"
53 #include "sound/ds.h"
54 #include "weapon/beam.h"
55 #include "weapon/weapon.h"
56 
57 #define BMPMAN_INTERNAL
58 #include "bmpman/bm_internal.h"
59 
60 //*************************Lua globals*************************
62 
63 //*************************Lua classes************************
64 
65 //Library class
66 //This is what you define a variable of to make new libraries
67 class ade_lib : public ade_lib_handle {
68 public:
69  ade_lib(char *in_name, ade_lib_handle *parent=NULL, char *in_shortname=NULL, char *in_desc=NULL) {
70  ade_table_entry ate;
71 
72  ate.Name = in_name;
73  ate.ShortName = in_shortname;
74  ate.Instanced = true;
75 
76  //WMC - Here's a little hack.
77  //Lua did not work with __len on standard table objects.
78  //So instead, all FS2 libraries are now userdata.
79  //This means that no new functions can be added from
80  //within the scripting environment, but I don't think
81  //there will be any catastrophic consequences.
82  ate.Type = 'o';
83  ate.Value.Object.idx = Ade_table_entries.size();
84  ate.Value.Object.sig = NULL;
85  ate.Value.Object.buf = &Num_reinforcements; //WMC - I just chose Num_ship_classes randomly. MageKing17 - changed to Num_reinforcements, likewise at random, due to the removal of Num_ship_classes
86  ate.Value.Object.size = sizeof(Num_reinforcements);
87  ate.Description = in_desc;
88 
89  if(parent != NULL)
90  Ade_table_entries[parent->GetIdx()].AddSubentry(ate);
91  else
92  Ade_table_entries.push_back(ate);
93  LibIdx = Ade_table_entries.size()-1;
94  }
95 
96  char *GetName();
97 };
98 
100 {
101  if(GetIdx() == UINT_MAX)
102  return "<Invalid>";
103 
104  return Ade_table_entries[GetIdx()].GetName();
105 }
106 
107 //Function helper class
108 //Lets us add functions via its constructor
109 class ade_func : public ade_lib_handle {
110 public:
111  ade_func(char *name, lua_CFunction func, ade_lib_handle &parent, char *args=NULL, char *desc=NULL, char *ret_type=NULL, char*ret_desc=NULL) {
112  ade_table_entry ate;
113 
114  ate.Name = name;
115  ate.Instanced = true;
116  ate.Type = 'u';
117  ate.Value.Function = func;
118  ate.Arguments = args;
119  ate.Description = desc;
120  ate.ReturnType = ret_type;
121  ate.ReturnDescription = ret_desc;
122 
123  Ade_table_entries[parent.GetIdx()].AddSubentry(ate);
124  LibIdx = Ade_table_entries.size()-1;
125  }
126 };
127 
128 class ade_virtvar : public ade_lib_handle {
129 public:
130  ade_virtvar(char *name, lua_CFunction func, ade_lib_handle &parent, char *args=NULL, char *desc=NULL, char *ret_type=NULL, char*ret_desc=NULL) {
131  ade_table_entry ate;
132 
133  ate.Name = name;
134  ate.Instanced = true;
135  ate.Type = 'v';
136  ate.Value.Function = func;
137  ate.Arguments = args;
138  ate.Description = desc;
139  ate.ReturnType = ret_type;
140  ate.ReturnDescription = ret_desc;
141 
142  Ade_table_entries[parent.GetIdx()].AddSubentry(ate);
143  LibIdx = Ade_table_entries.size()-1;
144  }
145 };
146 
147 class ade_indexer : public ade_lib_handle {
148 public:
149  ade_indexer(lua_CFunction func, ade_lib_handle &parent, char *args=NULL, char *desc=NULL, char *ret_type=NULL, char*ret_desc=NULL) {
150  //Add function for meta
151  ade_table_entry ate;
152 
153  ate.Name = "__indexer";
154  ate.Instanced = true;
155  ate.Type = 'u';
156  ate.Value.Function = func;
157  ate.Arguments = args;
158  ate.Description = desc;
159  ate.ReturnType = ret_type;
160  ate.ReturnDescription = ret_desc;
161 
162  Ade_table_entries[parent.GetIdx()].AddSubentry(ate);
163  LibIdx = Ade_table_entries.size()-1;
164  }
165 };
166 
167 //Struct for converting one string for another. whee!
168 struct string_conv {
169  char *src;
170  char *dest;
171 };
172 
173 //*************************Lua operators*************************
174 //These are the various types of operators you can
175 //set in Lua. Use these as function name to activate.
176 //
177 //Format string should be "*o" or "o*", where "*" is the type of
178 //variable you want to deal with.
179 //The order varies with order of variables
181  {"__add", "+"}, //var + obj
182  {"__sub", "-"}, //var - obj
183  {"__mul", "*"}, //var * obj
184  {"__div", "/"}, //var / obj
185  {"__mod", "%"}, //var % obj
186  {"__pow", "^"}, //var ^ obj
187  {"__unm", "~"}, //var ~ obj
188  {"__concat", ".."}, //var .. obj
189  {"__len", "#"}, //#var
190  {"__eq", "=="}, //var == obj
191  {"__lt", "<"}, //var < obj
192  {"__le", "<="}, //var <= obj
193  {"__newindex", "="}, //var = obj
194  {"__call", ""}, //*shrug*
195  {"__gc", "__gc"}, //Lua's equivelant of a destructor
196  //WMC - Used with tostring() lua operator.
197  {"__tostring", "(string)"}, //tostring(var)
198  //WMC - This is NOT a Lua type, but for the LUA_INDEXER define
199  {"__indexer", "[]"}, //obj[var]
200 };
201 
203 
204 int ade_get_operator(char *tablename)
205 {
206  for(int i = 0; i < ade_Num_operators; i++)
207  {
208  if(!strcmp(tablename, ade_Operators[i].src))
209  return i;
210  }
211 
212  return -1;
213 }
214 
215 const size_t INVALID_ID = (size_t) -1; // Use -1 to get highest possible unsigned number
216 
217 //*************************Lua helpers*************************
218 //Function macro
219 //This is what you call to make new functions
220 #define ADE_FUNC(name, parent, args, desc, ret_type, ret_desc) \
221  static int parent##_##name##_f(lua_State *L); \
222  ade_func parent##_##name(#name, parent##_##name##_f, parent, args, desc, ret_type, ret_desc); \
223  static int parent##_##name##_f(lua_State *L)
224 
225 //Use this to handle forms of type vec.x and vec['x']. Basically an indexer for a specific variable.
226 //Format string should be "o*%", where * is indexing value, and % is the value to set to when LUA_SETTTING_VAR is set
227 #define ADE_VIRTVAR(name, parent, args, desc, ret_type, ret_desc) \
228  static int parent##_##name##_f(lua_State *L); \
229  ade_virtvar parent##_##name(#name, parent##_##name##_f, parent, args, desc, ret_type, ret_desc); \
230  static int parent##_##name##_f(lua_State *L)
231 
232 //Use this with objects to deal with forms such as vec.x, vec['x'], vec[0]
233 //Format string should be "o*%", where * is indexing value, and % is the value to set to when LUA_SETTTING_VAR is set
234 #define ADE_INDEXER(parent, args, desc, ret_type, ret_desc) \
235  static int parent##___indexer_f(lua_State *L); \
236  ade_indexer parent##___indexer(parent##___indexer_f, parent, args, desc, ret_type, ret_desc); \
237  static int parent##___indexer_f(lua_State *L)
238 
239 //Checks to determine whether ADE_VIRTVAR or LUA_INDEXER should set the variable
240 #define ADE_FUNCNAME_UPVALUE_INDEX 1
241 #define ADE_SETTING_UPVALUE_INDEX 2
242 #define ADE_SETTING_VAR lua_toboolean(L,lua_upvalueindex(ADE_SETTING_UPVALUE_INDEX))
243 
244 //*************************Lua return values*************************
245 #define ADE_RETURN_NIL 0
246 #define ADE_RETURN_TRUE ade_set_args(L, "b", true)
247 #define ADE_RETURN_FALSE ade_set_args(L, "b", false)
248 #define ade_set_error ade_set_args
249 
250 //*************************Begin non-lowlevel stuff*************************
251 //*************************Helper function declarations*********************
252 //WMC - Sets object handle with proper type
253 int ade_set_object_with_breed(lua_State *L, int obj_idx);
254 
255 //**********Handles
256 /*ade_obj<int> l_Camera("camera", "Camera handle");
257 ade_obj<int> l_Cmission("cmission", "Campaign mission handle"); //WMC - We can get away with a pointer right now, but if it ever goes dynamic, it'd be a prob
258 ade_obj<enum_h> l_Enum("enumeration", "Enumeration object");
259 ade_obj<int> l_Event("event", "Mission event handle");
260 ade_obj<int> l_Font("font", "font handle");
261 ade_obj<matrix_h> l_Matrix("orientation", "Orientation matrix object");
262 ade_obj<int> l_Model("model", "3D Model (POF) handle");
263 ade_obj<object_h> l_Object("object", "Object handle");
264 ade_obj<physics_info_h> l_Physics("physics", "Physics handle");
265 ade_obj<int> l_Player("player", "Player handle");
266 ade_obj<object_h> l_Shields("shields", "Shields handle");
267 ade_obj<object_h> l_Ship("ship", "Ship handle", &l_Object);
268 ade_obj<int> l_Shipclass("shipclass", "Ship class handle");
269 ade_obj<object_h> l_ShipTextures("shiptextures", "Ship textures handle");
270 ade_obj<int> l_Shiptype("shiptype", "Ship type handle");
271 ade_obj<int> l_Species("species", "Species handle");
272 ade_obj<ship_subsys_h> l_Subsystem("subsystem", "Ship subsystem handle");
273 ade_obj<int> l_Team("team", "Team handle");
274 ade_obj<int> l_Texture("texture", "Texture handle");
275 ade_obj<int> l_Wing("wing", "Wing handle");
276 ade_obj<vec3d> l_Vector("vector", "Vector object");
277 ade_obj<object_h> l_Weapon("weapon", "Weapon handle", &l_Object);
278 ade_obj<ship_bank_h> l_WeaponBank("weaponbank", "Ship/subystem weapons bank handle");
279 ade_obj<ship_banktype_h> l_WeaponBankType("weaponbanktype", "Ship/subsystem weapons bank type handle");
280 ade_obj<int> l_Weaponclass("weaponclass", "Weapon class handle");
281 */
282 //###########################################################
283 //########################<IMPORTANT>########################
284 //###########################################################
285 //If you are a coder who wants to add libraries, functions,
286 //or objects to Lua, then you want to be below this point.
287 //###########################################################
288 //########################</IMPORTANT>#######################
289 //###########################################################
290 
291 //**********OBJECT: orientation matrix
292 //WMC - So matrix can use vector, I define it up here.
293 ade_obj<vec3d> l_Vector("vector", "Vector object");
294 //WMC - Due to the exorbitant times required to store matrix data,
295 //I initially store the matrix in this struct.
296 #define MH_FINE 0
297 #define MH_MATRIX_OUTOFDATE 1
298 #define MH_ANGLES_OUTOFDATE 2
299 struct matrix_h {
300 private:
301  int status;
302 
303  matrix mtx;
304  angles ang;
305 
306  //WMC - Call these to make sure what you want
307  //is up to date
308  void ValidateAngles() {
309  if(status == MH_ANGLES_OUTOFDATE) {
310  vm_extract_angles_matrix(&ang, &mtx);
311  status = MH_FINE;
312  }
313  }
314 
315  void ValidateMatrix() {
316  if(status == MH_MATRIX_OUTOFDATE) {
317  vm_angles_2_matrix(&mtx, &ang);
318  status = MH_FINE;
319  }
320  }
321 public:
323  matrix_h(matrix *in){mtx = *in; status = MH_ANGLES_OUTOFDATE;}
324  matrix_h(angles *in){ang = *in; status = MH_MATRIX_OUTOFDATE;}
325 
327  {
328  this->ValidateAngles();
329  return &ang;
330  }
331 
333  {
334  this->ValidateMatrix();
335  return &mtx;
336  }
337 
338  void SetStatus(int n_status)
339  {
340  status = n_status;
341  }
342 
343  //LOOK LOOK LOOK LOOK LOOK LOOK
344  //IMPORTANT!!!:
345  //LOOK LOOK LOOK LOOK LOOK LOOK
346  //Don't forget to set status appropriately when you change ang or mtx.
347 };
348 ade_obj<matrix_h> l_Matrix("orientation", "Orientation matrix object");
349 
350 ADE_INDEXER(l_Matrix, "p,b,h or 1-9", "Orientation component - pitch, bank, heading, or index into 3x3 matrix (1-9)", "number", "Number at the specified index, or 0 if index is invalid.")
351 {
352  matrix_h *mh;
353  char *s = NULL;
354  float newval = 0.0f;
355  int numargs = ade_get_args(L, "os|f", l_Matrix.GetPtr(&mh), &s, &newval);
356 
357  if(!numargs || s[1] != '\0')
358  return ade_set_error(L, "f", 0.0f);
359 
360  int idx=0;
361  if(s[0]=='p')
362  idx = -1;
363  else if(s[0]=='b')
364  idx = -2;
365  else if(s[0]=='h')
366  idx = -3;
367  else if(atoi(s))
368  idx = atoi(s);
369 
370  if(idx < -3 || idx==0 || idx > 9)
371  return ade_set_error(L, "f", 0.0f);
372 
373  //Handle out of date stuff.
374  float *val = NULL;
375  if(idx < 0)
376  {
377  angles *ang = mh->GetAngles();
378 
379  if(idx == -1)
380  val = &ang->p;
381  if(idx == -2)
382  val = &ang->b;
383  if(idx == -3)
384  val = &ang->h;
385  }
386  else
387  {
388  idx--; //Lua->FS2
389  val = &mh->GetMatrix()->a1d[idx];
390  }
391 
392  if(ADE_SETTING_VAR && *val != newval)
393  {
394  //WMC - I figure this is quicker
395  //than just assuming matrix or angles is diff
396  //and recalculating every time.
397 
398  if(idx < 0)
400  else
402 
403  //Might as well put this here
404  *val = newval;
405  }
406 
407  return ade_set_args(L, "f", *val);
408 }
409 
410 ADE_FUNC(__mul, l_Matrix, "orientation", "Multiplies two matrix objects)", "orientation", "matrix, or empty matrix if unsuccessful")
411 {
412  matrix_h *mha=NULL, *mhb=NULL;
413  if(!ade_get_args(L, "oo", l_Matrix.GetPtr(&mha), l_Matrix.GetPtr(&mhb)))
414  return ade_set_error(L, "o", l_Matrix.Set(matrix_h()));
415 
416  matrix mr;
417 
418  vm_matrix_x_matrix(&mr, mha->GetMatrix(), mhb->GetMatrix());
419 
420  return ade_set_args(L, "o", l_Matrix.Set(matrix_h(&mr)));
421 }
422 
423 ADE_FUNC(__tostring, l_Matrix, NULL, "Converts a matrix to a string with format \"[r1c1 r2c1 r3c1 | r1c2 r2c2 r3c2| r1c3 r2c3 r3c3]\"", "string", "Formatted string or \"<NULL\"")
424 {
425  matrix_h *mh;
426  if(!ade_get_args(L, "o", l_Matrix.GetPtr(&mh)))
427  return ade_set_error(L, "s", "<NULL>");
428 
429  char buf[128];
430  float *a = &mh->GetMatrix()->a1d[0];
431  sprintf(buf, "[%f %f %f | %f %f %f | %f %f %f]", a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]);
432 
433  return ade_set_args(L, "s", buf);
434 }
435 
436 ADE_FUNC(getInterpolated, l_Matrix, "orientation Final, number Factor", "Returns orientation that has been interpolated to Final by Factor (0.0-1.0)", "orientation", "Interpolated orientation, or null orientation on failure")
437 {
438  matrix_h *oriA = NULL;
439  matrix_h *oriB = NULL;
440  float factor = 0.0f;
441  if(!ade_get_args(L, "oof", l_Matrix.GetPtr(&oriA), l_Matrix.GetPtr(&oriB), &factor))
442  return ade_set_error(L, "o", l_Matrix.Set(matrix_h()));
443 
444  matrix *A = oriA->GetMatrix();
445  matrix *B = oriB->GetMatrix();
447 
448  //matrix subtraction & scaling
449  for(int i = 0; i < 9; i++)
450  {
451  final.a1d[i] = A->a1d[i] + (B->a1d[i] - A->a1d[i])*factor;
452  }
453 
454  return ade_set_args(L, "o", l_Matrix.Set(matrix_h(&final)));
455 }
456 
457 ADE_FUNC(getTranspose, l_Matrix, NULL, "Returns a transpose version of the specified orientation", "orientation", "Transpose matrix, or null orientation on failure")
458 {
459  matrix_h *mh = NULL;
460  if(!ade_get_args(L, "o", l_Matrix.GetPtr(&mh)))
461  return ade_set_error(L, "o", l_Matrix.Set(matrix_h()));
462 
463  matrix final = *mh->GetMatrix();
464  vm_transpose(&final);
465 
466  return ade_set_args(L, "o", l_Matrix.Set(matrix_h(&final)));
467 }
468 
469 
470 ADE_FUNC(rotateVector, l_Matrix, "vector Input", "Returns rotated version of given vector", "vector", "Rotated vector, or empty vector on error")
471 {
472  matrix_h *mh;
473  vec3d *v3;
474  if(!ade_get_args(L, "oo", l_Matrix.GetPtr(&mh), l_Vector.GetPtr(&v3)))
475  return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
476 
477  vec3d v3r;
478  vm_vec_rotate(&v3r, v3, mh->GetMatrix());
479 
480  return ade_set_args(L, "o", l_Vector.Set(v3r));
481 }
482 
483 ADE_FUNC(unrotateVector, l_Matrix, "vector Input", "Returns unrotated version of given vector", "vector", "Unrotated vector, or empty vector on error")
484 {
485  matrix_h *mh;
486  vec3d *v3;
487  if(!ade_get_args(L, "oo", l_Matrix.GetPtr(&mh), l_Vector.GetPtr(&v3)))
488  return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
489 
490  vec3d v3r;
491  vm_vec_unrotate(&v3r, v3, mh->GetMatrix());
492 
493  return ade_set_args(L, "o", l_Vector.Set(v3r));
494 }
495 
496 ADE_FUNC(getUvec, l_Matrix, NULL, "Returns the vector that points up (0,1,0 unrotated by this matrix)", "vector", "Vector or null vector on error")
497 {
498  matrix_h *mh = NULL;
499  if(!ade_get_args(L, "o", l_Matrix.GetPtr(&mh)))
500  return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
501 
502  return ade_set_args(L, "o", l_Vector.Set(mh->GetMatrix()->vec.uvec));
503 }
504 
505 ADE_FUNC(getFvec, l_Matrix, NULL, "Returns the vector that points to the front (0,0,1 unrotated by this matrix)", "vector", "Vector or null vector on error")
506 {
507  matrix_h *mh = NULL;
508  if(!ade_get_args(L, "o", l_Matrix.GetPtr(&mh)))
509  return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
510 
511  return ade_set_args(L, "o", l_Vector.Set(mh->GetMatrix()->vec.fvec));
512 }
513 
514 ADE_FUNC(getRvec, l_Matrix, NULL, "Returns the vector that points to the right (1,0,0 unrotated by this matrix)", "vector", "Vector or null vector on error")
515 {
516  matrix_h *mh = NULL;
517  if(!ade_get_args(L, "o", l_Matrix.GetPtr(&mh)))
518  return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
519 
520  return ade_set_args(L, "o", l_Vector.Set(mh->GetMatrix()->vec.rvec));
521 }
522 
523 //**********OBJECT: constant class
524 //WMC NOTE -
525 //While you can have enumeration indexes in any order, make sure
526 //that any new enumerations have indexes of NEXT INDEX (see below)
527 //or after. Don't forget to increment NEXT INDEX after you're done.
528 //=====================================
529 static const int ENUM_NEXT_INDEX = 74; // <<<<<<<<<<<<<<<<<<<<<<
530 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
531 static flag_def_list Enumerations[] = {
532  #define LE_ALPHABLEND_FILTER 14
533  { "ALPHABLEND_FILTER", LE_ALPHABLEND_FILTER, 0},
534 
535  #define LE_ALPHABLEND_NONE 27
536  { "ALPHABLEND_NONE", LE_ALPHABLEND_NONE, 0},
537 
538  #define LE_CFILE_TYPE_NORMAL 20
539  { "CFILE_TYPE_NORMAL", LE_CFILE_TYPE_NORMAL, 0},
540 
541  #define LE_CFILE_TYPE_MEMORY_MAPPED 21
542  { "CFILE_TYPE_MEMORY_MAPPED", LE_CFILE_TYPE_MEMORY_MAPPED, 0},
543 
544  #define LE_MOUSE_LEFT_BUTTON 1
545  { "MOUSE_LEFT_BUTTON", LE_MOUSE_LEFT_BUTTON, 0},
546 
547  #define LE_MOUSE_RIGHT_BUTTON 2
548  { "MOUSE_RIGHT_BUTTON", LE_MOUSE_RIGHT_BUTTON, 0},
549 
550  #define LE_MOUSE_MIDDLE_BUTTON 3
551  { "MOUSE_MIDDLE_BUTTON", LE_MOUSE_MIDDLE_BUTTON, 0},
552 
553  #define LE_ORDER_ATTACK 28
554  { "ORDER_ATTACK", LE_ORDER_ATTACK, 0},
555 
556  #define LE_ORDER_ATTACK_ANY 29
557  { "ORDER_ATTACK_ANY", LE_ORDER_ATTACK_ANY, 0},
558 
559  #define LE_ORDER_DEPART 30
560  { "ORDER_DEPART", LE_ORDER_DEPART, 0},
561 
562  #define LE_ORDER_DISABLE 31
563  { "ORDER_DISABLE", LE_ORDER_DISABLE, 0},
564 
565  #define LE_ORDER_DISARM 32
566  { "ORDER_DISARM", LE_ORDER_DISARM, 0},
567 
568  #define LE_ORDER_DOCK 33
569  { "ORDER_DOCK", LE_ORDER_DOCK, 0},
570 
571  #define LE_ORDER_EVADE 34
572  { "ORDER_EVADE", LE_ORDER_EVADE, 0},
573 
574  #define LE_ORDER_FLY_TO 35
575  { "ORDER_FLY_TO", LE_ORDER_FLY_TO, 0},
576 
577  #define LE_ORDER_FORM_ON_WING 36
578  { "ORDER_FORM_ON_WING", LE_ORDER_FORM_ON_WING, 0},
579 
580  #define LE_ORDER_GUARD 37
581  { "ORDER_GUARD", LE_ORDER_GUARD, 0},
582 
583  #define LE_ORDER_IGNORE 38
584  { "ORDER_IGNORE_SHIP", LE_ORDER_IGNORE, 0},
585 
586  #define LE_ORDER_KEEP_SAFE_DISTANCE 39
587  { "ORDER_KEEP_SAFE_DISTANCE", LE_ORDER_KEEP_SAFE_DISTANCE, 0},
588 
589  #define LE_ORDER_PLAY_DEAD 40
590  { "ORDER_PLAY_DEAD", LE_ORDER_PLAY_DEAD, 0},
591 
592  #define LE_ORDER_REARM 41
593  { "ORDER_REARM", LE_ORDER_REARM, 0},
594 
595  #define LE_ORDER_STAY_NEAR 42
596  { "ORDER_STAY_NEAR", LE_ORDER_STAY_NEAR, 0},
597 
598  #define LE_ORDER_STAY_STILL 43
599  { "ORDER_STAY_STILL", LE_ORDER_STAY_STILL, 0},
600 
601  #define LE_ORDER_UNDOCK 44
602  { "ORDER_UNDOCK", LE_ORDER_UNDOCK, 0},
603 
604  #define LE_ORDER_WAYPOINTS 45
605  { "ORDER_WAYPOINTS", LE_ORDER_WAYPOINTS, 0},
606 
607  #define LE_ORDER_WAYPOINTS_ONCE 46
608  { "ORDER_WAYPOINTS_ONCE", LE_ORDER_WAYPOINTS_ONCE, 0},
609 
610  #define LE_ORDER_ATTACK_WING 69
611  { "ORDER_ATTACK_WING", LE_ORDER_ATTACK_WING, 0},
612 
613  #define LE_ORDER_GUARD_WING 70
614  { "ORDER_GUARD_WING", LE_ORDER_GUARD_WING, 0},
615 
616  #define LE_PARTICLE_DEBUG 4
617  { "PARTICLE_DEBUG", LE_PARTICLE_DEBUG, 0},
618 
619  #define LE_PARTICLE_BITMAP 5
620  { "PARTICLE_BITMAP", LE_PARTICLE_BITMAP, 0},
621 
622  #define LE_PARTICLE_FIRE 6
623  { "PARTICLE_FIRE", LE_PARTICLE_FIRE, 0},
624 
625  #define LE_PARTICLE_SMOKE 7
626  { "PARTICLE_SMOKE", LE_PARTICLE_SMOKE, 0},
627 
628  #define LE_PARTICLE_SMOKE2 8
629  { "PARTICLE_SMOKE2", LE_PARTICLE_SMOKE2, 0},
630 
631  #define LE_PARTICLE_PERSISTENT_BITMAP 9
632  { "PARTICLE_PERSISTENT_BITMAP", LE_PARTICLE_PERSISTENT_BITMAP, 0},
633 
634  #define LE_SEXPVAR_CAMPAIGN_PERSISTENT 22
635  { "SEXPVAR_CAMPAIGN_PERSISTENT", LE_SEXPVAR_CAMPAIGN_PERSISTENT, 0},
636 
637  #define LE_SEXPVAR_NOT_PERSISTENT 23
638  { "SEXPVAR_NOT_PERSISTENT", LE_SEXPVAR_NOT_PERSISTENT, 0},
639 
640  #define LE_SEXPVAR_PLAYER_PERSISTENT 24
641  { "SEXPVAR_PLAYER_PERSISTENT", LE_SEXPVAR_PLAYER_PERSISTENT, 0},
642 
643  #define LE_SEXPVAR_TYPE_NUMBER 25
644  { "SEXPVAR_TYPE_NUMBER", LE_SEXPVAR_TYPE_NUMBER, 0},
645 
646  #define LE_SEXPVAR_TYPE_STRING 26
647  { "SEXPVAR_TYPE_STRING", LE_SEXPVAR_TYPE_STRING, 0},
648 
649  #define LE_TEXTURE_STATIC 10
650  { "TEXTURE_STATIC", LE_TEXTURE_STATIC, 0},
651 
652  #define LE_TEXTURE_DYNAMIC 11
653  { "TEXTURE_DYNAMIC", LE_TEXTURE_DYNAMIC, 0},
654 
655  #define LE_LOCK 12
656  { "LOCK", LE_LOCK, 0},
657 
658  #define LE_UNLOCK 13
659  { "UNLOCK", LE_UNLOCK, 0},
660 
661  #define LE_NONE 15
662  { "NONE", LE_NONE, 0},
663 
664  #define LE_SHIELD_FRONT 16
665  { "SHIELD_FRONT", LE_SHIELD_FRONT, 0},
666 
667  #define LE_SHIELD_LEFT 17
668  { "SHIELD_LEFT", LE_SHIELD_LEFT, 0},
669 
670  #define LE_SHIELD_RIGHT 18
671  { "SHIELD_RIGHT", LE_SHIELD_RIGHT, 0},
672 
673  #define LE_SHIELD_BACK 19
674  { "SHIELD_BACK", LE_SHIELD_BACK, 0},
675 
676  #define LE_MISSION_REPEAT 47
677  { "MISSION_REPEAT", LE_MISSION_REPEAT, 0},
678 
679  #define LE_NORMAL_CONTROLS 48
680  { "NORMAL_CONTROLS", LE_NORMAL_CONTROLS, 0},
681 
682  #define LE_LUA_STEERING_CONTROLS 49
683  { "LUA_STEERING_CONTROLS", LE_LUA_STEERING_CONTROLS, 0},
684 
685  #define LE_LUA_FULL_CONTROLS 50
686  { "LUA_FULL_CONTROLS", LE_LUA_FULL_CONTROLS, 0},
687 
688  #define LE_NORMAL_BUTTON_CONTROLS 51
689  { "NORMAL_BUTTON_CONTROLS", LE_NORMAL_BUTTON_CONTROLS, 0},
690 
691  #define LE_LUA_ADDITIVE_BUTTON_CONTROL 52
692  { "LUA_ADDITIVE_BUTTON_CONTROL", LE_LUA_ADDITIVE_BUTTON_CONTROL, 0},
693 
694  #define LE_LUA_OVERRIDE_BUTTON_CONTROL 53
695  { "LUA_OVERRIDE_BUTTON_CONTROL", LE_LUA_OVERRIDE_BUTTON_CONTROL, 0},
696 
697  #define LE_VM_INTERNAL 54
698  { "VM_INTERNAL", LE_VM_INTERNAL, 0},
699 
700  #define LE_VM_EXTERNAL 55
701  { "VM_EXTERNAL", LE_VM_EXTERNAL, 0},
702 
703  #define LE_VM_TRACK 56
704  { "VM_TRACK", LE_VM_TRACK, 0},
705 
706  #define LE_VM_DEAD_VIEW 57
707  { "VM_DEAD_VIEW", LE_VM_DEAD_VIEW, 0},
708 
709  #define LE_VM_CHASE 58
710  { "VM_CHASE", LE_VM_CHASE, 0},
711 
712  #define LE_VM_OTHER_SHIP 59
713  { "VM_OTHER_SHIP", LE_VM_OTHER_SHIP, 0},
714 
715  #define LE_VM_EXTERNAL_CAMERA_LOCKED 60
716  { "VM_EXTERNAL_CAMERA_LOCKED", LE_VM_EXTERNAL_CAMERA_LOCKED, 0},
717 
718  #define LE_VM_WARP_CHASE 61
719  { "VM_WARP_CHASE", LE_VM_WARP_CHASE, 0},
720 
721  #define LE_VM_PADLOCK_UP 62
722  { "VM_PADLOCK_UP", LE_VM_PADLOCK_UP, 0},
723 
724  #define LE_VM_PADLOCK_REAR 63
725  { "VM_PADLOCK_REAR", LE_VM_PADLOCK_REAR, 0},
726 
727  #define LE_VM_PADLOCK_LEFT 64
728  { "VM_PADLOCK_LEFT", LE_VM_PADLOCK_LEFT, 0},
729 
730  #define LE_VM_PADLOCK_RIGHT 65
731  { "VM_PADLOCK_RIGHT", LE_VM_PADLOCK_RIGHT, 0},
732 
733  #define LE_VM_WARPIN_ANCHOR 66
734  { "VM_WARPIN_ANCHOR", LE_VM_WARPIN_ANCHOR, 0},
735 
736  #define LE_VM_TOPDOWN 67
737  { "VM_TOPDOWN", LE_VM_TOPDOWN, 0},
738 
739  #define LE_VM_FREECAMERA 68
740  { "VM_FREECAMERA", LE_VM_FREECAMERA, 0},
741 
742  #define LE_MESSAGE_PRIORITY_LOW 71
743  { "MESSAGE_PRIORITY_LOW", LE_MESSAGE_PRIORITY_LOW, 0},
744 
745  #define LE_MESSAGE_PRIORITY_NORMAL 72
746  { "MESSAGE_PRIORITY_NORMAL", LE_MESSAGE_PRIORITY_NORMAL, 0},
747 
748  #define LE_MESSAGE_PRIORITY_HIGH 73
749  { "MESSAGE_PRIORITY_HIGH", LE_MESSAGE_PRIORITY_HIGH, 0},
750 };
751 
752 //DO NOT FORGET to increment NEXT INDEX: !!!!!!!!!!!!!
753 
754 static uint Num_enumerations = sizeof(Enumerations) / sizeof(flag_def_list);
755 
757  { "TARGET_NEXT", TARGET_NEXT, 0 },
758  { "TARGET_PREV", TARGET_PREV, 0 },
759  { "TARGET_NEXT_CLOSEST_HOSTILE", TARGET_NEXT_CLOSEST_HOSTILE, 0 },
760  { "TARGET_PREV_CLOSEST_HOSTILE", TARGET_PREV_CLOSEST_HOSTILE, 0 },
761  { "TOGGLE_AUTO_TARGETING", TOGGLE_AUTO_TARGETING, 0 },
762  { "TARGET_NEXT_CLOSEST_FRIENDLY", TARGET_NEXT_CLOSEST_FRIENDLY, 0 },
763  { "TARGET_PREV_CLOSEST_FRIENDLY", TARGET_PREV_CLOSEST_FRIENDLY, 0 },
764  { "TARGET_SHIP_IN_RETICLE", TARGET_SHIP_IN_RETICLE, 0 },
765  { "TARGET_CLOSEST_SHIP_ATTACKING_TARGET", TARGET_CLOSEST_SHIP_ATTACKING_TARGET, 0 },
766  { "TARGET_LAST_TRANMISSION_SENDER", TARGET_LAST_TRANMISSION_SENDER, 0 },
767  { "STOP_TARGETING_SHIP", STOP_TARGETING_SHIP, 0 },
768  { "TARGET_SUBOBJECT_IN_RETICLE", TARGET_SUBOBJECT_IN_RETICLE, 0 },
769  { "TARGET_NEXT_SUBOBJECT", TARGET_NEXT_SUBOBJECT, 0 },
770  { "TARGET_PREV_SUBOBJECT", TARGET_PREV_SUBOBJECT, 0 },
771  { "STOP_TARGETING_SUBSYSTEM", STOP_TARGETING_SUBSYSTEM, 0 },
772  { "MATCH_TARGET_SPEED", MATCH_TARGET_SPEED, 0 },
773  { "TOGGLE_AUTO_MATCH_TARGET_SPEED", TOGGLE_AUTO_MATCH_TARGET_SPEED, 0 },
774  { "FIRE_PRIMARY", FIRE_PRIMARY, 0 },
775  { "FIRE_SECONDARY", FIRE_SECONDARY, 0 },
776  { "CYCLE_NEXT_PRIMARY", CYCLE_NEXT_PRIMARY, 0 },
777  { "CYCLE_PREV_PRIMARY", CYCLE_PREV_PRIMARY, 0 },
778  { "CYCLE_SECONDARY", CYCLE_SECONDARY, 0 },
779  { "CYCLE_NUM_MISSLES", CYCLE_NUM_MISSLES, 0 },
780  { "LAUNCH_COUNTERMEASURE", LAUNCH_COUNTERMEASURE, 0 },
781  { "FORWARD_THRUST", FORWARD_THRUST, 0 },
782  { "REVERSE_THRUST", REVERSE_THRUST, 0 },
783  { "BANK_LEFT", BANK_LEFT, 0 },
784  { "BANK_RIGHT", BANK_RIGHT, 0 },
785  { "PITCH_FORWARD", PITCH_FORWARD, 0 },
786  { "PITCH_BACK", PITCH_BACK, 0 },
787  { "YAW_LEFT", YAW_LEFT, 0 },
788  { "YAW_RIGHT", YAW_RIGHT, 0 },
789  { "ZERO_THROTTLE", ZERO_THROTTLE, 1 },
790  { "MAX_THROTTLE", MAX_THROTTLE, 1 },
791  { "ONE_THIRD_THROTTLE", ONE_THIRD_THROTTLE, 1 },
792  { "TWO_THIRDS_THROTTLE", TWO_THIRDS_THROTTLE, 1 },
793  { "PLUS_5_PERCENT_THROTTLE", PLUS_5_PERCENT_THROTTLE, 1 },
794  { "MINUS_5_PERCENT_THROTTLE", MINUS_5_PERCENT_THROTTLE, 1 },
795  { "ATTACK_MESSAGE", ATTACK_MESSAGE, 1 },
796  { "DISARM_MESSAGE", DISARM_MESSAGE, 1 },
797  { "DISABLE_MESSAGE", DISABLE_MESSAGE, 1 },
798  { "ATTACK_SUBSYSTEM_MESSAGE", ATTACK_SUBSYSTEM_MESSAGE, 1 },
799  { "CAPTURE_MESSAGE", CAPTURE_MESSAGE, 1 },
800  { "ENGAGE_MESSAGE", ENGAGE_MESSAGE, 1 },
801  { "FORM_MESSAGE", FORM_MESSAGE, 1 },
802  { "IGNORE_MESSAGE", IGNORE_MESSAGE, 1 },
803  { "PROTECT_MESSAGE", PROTECT_MESSAGE, 1 },
804  { "COVER_MESSAGE", COVER_MESSAGE, 1 },
805  { "WARP_MESSAGE", WARP_MESSAGE, 1 },
806  { "REARM_MESSAGE", REARM_MESSAGE, 1 },
807  { "TARGET_CLOSEST_SHIP_ATTACKING_SELF", TARGET_CLOSEST_SHIP_ATTACKING_SELF, 1 },
808  { "VIEW_CHASE", VIEW_CHASE, 1 },
809  { "VIEW_EXTERNAL", VIEW_EXTERNAL, 1 },
810  { "VIEW_EXTERNAL_TOGGLE_CAMERA_LOCK", VIEW_EXTERNAL_TOGGLE_CAMERA_LOCK, 1 },
811  { "VIEW_SLEW", VIEW_SLEW, 1 },
812  { "VIEW_OTHER_SHIP", VIEW_OTHER_SHIP, 1 },
813  { "VIEW_DIST_INCREASE", VIEW_DIST_INCREASE, 1 },
814  { "VIEW_DIST_DECREASE", VIEW_DIST_DECREASE, 1 },
815  { "VIEW_CENTER", VIEW_CENTER, 1 },
816  { "PADLOCK_UP", PADLOCK_UP, 1 },
817  { "PADLOCK_DOWN", PADLOCK_DOWN, 1 },
818  { "PADLOCK_LEFT", PADLOCK_LEFT, 1 },
819  { "PADLOCK_RIGHT", PADLOCK_RIGHT, 1 },
820  { "RADAR_RANGE_CYCLE", RADAR_RANGE_CYCLE, 1 },
821  { "SQUADMSG_MENU", SQUADMSG_MENU, 2 },
822  { "SHOW_GOALS", SHOW_GOALS, 2 },
823  { "END_MISSION", END_MISSION, 2 },
824  { "TARGET_TARGETS_TARGET", TARGET_TARGETS_TARGET, 2 },
825  { "AFTERBURNER", AFTERBURNER, 2 },
826  { "INCREASE_WEAPON", INCREASE_WEAPON, 2 },
827  { "DECREASE_WEAPON", DECREASE_WEAPON, 2 },
828  { "INCREASE_SHIELD", INCREASE_SHIELD, 2 },
829  { "DECREASE_SHIELD", DECREASE_SHIELD, 2 },
830  { "INCREASE_ENGINE", INCREASE_ENGINE, 2 },
831  { "DECREASE_ENGINE", DECREASE_ENGINE, 2 },
832  { "ETS_EQUALIZE", ETS_EQUALIZE, 2 },
833  { "SHIELD_EQUALIZE", SHIELD_EQUALIZE, 2 },
834  { "SHIELD_XFER_TOP", SHIELD_XFER_TOP, 2 },
835  { "SHIELD_XFER_BOTTOM", SHIELD_XFER_BOTTOM, 2 },
836  { "SHIELD_XFER_LEFT", SHIELD_XFER_LEFT, 2 },
837  { "SHIELD_XFER_RIGHT", SHIELD_XFER_RIGHT, 2 },
838  { "XFER_SHIELD", XFER_SHIELD, 2 },
839  { "XFER_LASER", XFER_LASER, 2 },
840  { "GLIDE_WHEN_PRESSED", GLIDE_WHEN_PRESSED, 2 },
841  { "BANK_WHEN_PRESSED", BANK_WHEN_PRESSED, 2 },
842  { "SHOW_NAVMAP", SHOW_NAVMAP, 2 },
843  { "ADD_REMOVE_ESCORT", ADD_REMOVE_ESCORT, 2 },
844  { "ESCORT_CLEAR", ESCORT_CLEAR, 2 },
845  { "TARGET_NEXT_ESCORT_SHIP", TARGET_NEXT_ESCORT_SHIP, 2 },
846  { "TARGET_CLOSEST_REPAIR_SHIP", TARGET_CLOSEST_REPAIR_SHIP, 2 },
847  { "TARGET_NEXT_UNINSPECTED_CARGO", TARGET_NEXT_UNINSPECTED_CARGO, 2 },
848  { "TARGET_PREV_UNINSPECTED_CARGO", TARGET_PREV_UNINSPECTED_CARGO, 2 },
849  { "TARGET_NEWEST_SHIP", TARGET_NEWEST_SHIP, 2 },
850  { "TARGET_NEXT_LIVE_TURRET", TARGET_NEXT_LIVE_TURRET, 2 },
851  { "TARGET_PREV_LIVE_TURRET", TARGET_PREV_LIVE_TURRET, 2 },
852  { "TARGET_NEXT_BOMB", TARGET_NEXT_BOMB, 2 },
853  { "TARGET_PREV_BOMB", TARGET_PREV_BOMB, 3 },
854  { "MULTI_MESSAGE_ALL", MULTI_MESSAGE_ALL, 3 },
855  { "MULTI_MESSAGE_FRIENDLY", MULTI_MESSAGE_FRIENDLY, 3 },
856  { "MULTI_MESSAGE_HOSTILE", MULTI_MESSAGE_HOSTILE, 3 },
857  { "MULTI_MESSAGE_TARGET", MULTI_MESSAGE_TARGET, 3 },
858  { "MULTI_OBSERVER_ZOOM_TO", MULTI_OBSERVER_ZOOM_TO, 3 },
859  { "TIME_SPEED_UP", TIME_SPEED_UP, 3 },
860  { "TIME_SLOW_DOWN", TIME_SLOW_DOWN, 3 },
861  { "TOGGLE_HUD_CONTRAST", TOGGLE_HUD_CONTRAST, 3 },
862  { "MULTI_TOGGLE_NETINFO", MULTI_TOGGLE_NETINFO, 3 },
863  { "MULTI_SELF_DESTRUCT", MULTI_SELF_DESTRUCT, 3 },
864  { "TOGGLE_HUD", TOGGLE_HUD, 3 },
865  { "RIGHT_SLIDE_THRUST", RIGHT_SLIDE_THRUST, 3 },
866  { "LEFT_SLIDE_THRUST", LEFT_SLIDE_THRUST, 3 },
867  { "UP_SLIDE_THRUST", UP_SLIDE_THRUST, 3 },
868  { "DOWN_SLIDE_THRUST", DOWN_SLIDE_THRUST, 3 },
869  { "HUD_TARGETBOX_TOGGLE_WIREFRAME", HUD_TARGETBOX_TOGGLE_WIREFRAME, 3 },
870  { "VIEW_TOPDOWN", VIEW_TOPDOWN, 3 },
871  { "VIEW_TRACK_TARGET", VIEW_TRACK_TARGET, 3 },
872  { "AUTO_PILOT_TOGGLE", AUTO_PILOT_TOGGLE, 3 },
873  { "NAV_CYCLE", NAV_CYCLE, 3 },
874  { "TOGGLE_GLIDING", TOGGLE_GLIDING, 3 },
875 };
876 
878 
879 struct enum_h {
880  int index;
882 
883  enum_h(){index=-1; is_constant=false;}
884  enum_h(int n_index){index=n_index; is_constant=false;}
885 
886  bool IsValid(){return (index > -1 && index < ENUM_NEXT_INDEX);}
887 };
888 ade_obj<enum_h> l_Enum("enumeration", "Enumeration object");
889 
890 ADE_FUNC(__newindex, l_Enum, "enumeration", "Sets enumeration to specified value (if it is not a global", "enumeration", "enumeration")
891 {
892  enum_h *e1=NULL, *e2=NULL;
893  if(!ade_get_args(L, "oo", l_Enum.GetPtr(&e1), l_Enum.GetPtr(&e2)))
894  return ade_set_error(L, "o", l_Enum.Set(enum_h()));
895 
896  if(!e1->is_constant)
897  e1->index = e2->index;
898 
899  return ade_set_args(L, "o", l_Enum.Set(*e1));
900 }
901 
902 ADE_FUNC(__tostring, l_Enum, NULL, "Returns enumeration name", "string", "Enumeration name, or \"<INVALID>\" if invalid")
903 {
904  enum_h *e = NULL;
905  if(!ade_get_args(L, "o", l_Enum.GetPtr(&e)))
906  return ade_set_args(L, "s", "<INVALID>");
907 
908  if(e->index < 1 || e->index >= ENUM_NEXT_INDEX)
909  return ade_set_args(L, "s", "<INVALID>");
910 
911  uint i;
912  for(i = 0; i < Num_enumerations; i++)
913  {
914  if(Enumerations[i].def == e->index)
915  return ade_set_args(L, "s", Enumerations[i].name);
916  }
917 
918  return ade_set_args(L, "s", "<INVALID>");
919 }
920 
921 ADE_FUNC(__eq, l_Enum, "enumeration", "Compares the two enumerations for equality", "boolean", "true if equal, false otherwise")
922 {
923  enum_h *e1 = NULL;
924  enum_h *e2 = NULL;
925 
926  if(!ade_get_args(L, "oo", l_Enum.GetPtr(&e1), l_Enum.GetPtr(&e2)))
927  return ade_set_error(L, "o", l_Enum.Set(enum_h()));
928 
929  if (e1 == NULL || e2 == NULL)
930  return ADE_RETURN_FALSE;
931 
932  return ade_set_args(L, "b", e1->index == e2->index);
933 }
934 
935 //**********HANDLE: event
936 ade_obj<int> l_Event("event", "Mission event handle");
937 
938 ADE_VIRTVAR(Name, l_Event, "string", "Mission event name", "string", NULL)
939 {
940  int idx;
941  char *s = NULL;
942  if(!ade_get_args(L, "o|s", l_Event.Get(&idx), &s))
943  return ade_set_error(L, "s", "");
944 
945  if(idx < 0 || idx >= Num_mission_events)
946  return ade_set_error(L, "s", "");
947 
949 
950  if(ADE_SETTING_VAR) {
951  strncpy(mep->name, s, sizeof(mep->name) - sizeof(char));
952  }
953 
954  return ade_set_args(L, "s", mep->name);
955 }
956 
957 ADE_VIRTVAR(DirectiveText, l_Event, "string", "Directive text", "string", NULL)
958 {
959  int idx;
960  char *s = NULL;
961  if(!ade_get_args(L, "o|s", l_Event.Get(&idx), &s))
962  return ade_set_error(L, "s", "");
963 
964  if(idx < 0 || idx >= Num_mission_events)
965  return ade_set_error(L, "s", "");
966 
968 
969  if(ADE_SETTING_VAR && s != NULL) {
970  if(mep->objective_text != NULL)
971  vm_free(mep->objective_text);
972 
973  mep->objective_text = vm_strdup(s);
974  }
975 
976  if(mep->objective_text != NULL)
977  return ade_set_args(L, "s", mep->objective_text);
978  else
979  return ade_set_args(L, "s", "");
980 }
981 
982 ADE_VIRTVAR(DirectiveKeypressText, l_Event, "string", "Raw directive keypress text, as seen in FRED.", "string", NULL)
983 {
984  int idx;
985  char *s = NULL;
986  if(!ade_get_args(L, "o|s", l_Event.Get(&idx), &s))
987  return ade_set_error(L, "s", "");
988 
989  if(idx < 0 || idx >= Num_mission_events)
990  return ade_set_error(L, "s", "");
991 
993 
994  if(ADE_SETTING_VAR && s != NULL) {
995  if(mep->objective_text != NULL)
997 
998  mep->objective_key_text = vm_strdup(s);
999  }
1000 
1001  if(mep->objective_key_text != NULL)
1002  return ade_set_args(L, "s", mep->objective_key_text);
1003  else
1004  return ade_set_args(L, "s", "");
1005 }
1006 
1007 ADE_VIRTVAR(Interval, l_Event, "number", "Time for event to repeat (in seconds)", "number", "Repeat time, or 0 if invalid handle")
1008 {
1009  int idx;
1010  int newinterval = 0;
1011  if(!ade_get_args(L, "o|i", l_Event.Get(&idx), &newinterval))
1012  return ade_set_error(L, "i", 0);
1013 
1014  if(idx < 0 || idx >= Num_mission_events)
1015  return ade_set_error(L, "i", 0);
1016 
1018 
1020  mep->interval = newinterval;
1021  }
1022 
1023  return ade_set_args(L, "i", mep->interval);
1024 }
1025 
1026 ADE_VIRTVAR(ObjectCount, l_Event, "number", "Number of objects left for event", "number", "Repeat count, or 0 if invalid handle")
1027 {
1028  int idx;
1029  int newobject = 0;
1030  if(!ade_get_args(L, "o|i", l_Event.Get(&idx), &newobject))
1031  return ade_set_error(L, "i", 0);
1032 
1033  if(idx < 0 || idx >= Num_mission_events)
1034  return ade_set_error(L, "i", 0);
1035 
1036  mission_event *mep = &Mission_events[idx];
1037 
1038  if(ADE_SETTING_VAR) {
1039  mep->count = newobject;
1040  }
1041 
1042  return ade_set_args(L, "i", mep->count);
1043 }
1044 
1045 ADE_VIRTVAR(RepeatCount, l_Event, "number", "Event repeat count", "number", "Repeat count, or 0 if invalid handle")
1046 {
1047  int idx;
1048  int newrepeat = 0;
1049  if(!ade_get_args(L, "o|i", l_Event.Get(&idx), &newrepeat))
1050  return ade_set_error(L, "i", 0);
1051 
1052  if(idx < 0 || idx >= Num_mission_events)
1053  return ade_set_error(L, "i", 0);
1054 
1055  mission_event *mep = &Mission_events[idx];
1056 
1057  if(ADE_SETTING_VAR) {
1058  mep->repeat_count = newrepeat;
1059  }
1060 
1061  return ade_set_args(L, "i", mep->repeat_count);
1062 }
1063 
1064 ADE_VIRTVAR(Score, l_Event, "number", "Event score", "number", "Event score, or 0 if invalid handle")
1065 {
1066  int idx;
1067  int newscore = 0;
1068  if(!ade_get_args(L, "o|i", l_Event.Get(&idx), &newscore))
1069  return ade_set_error(L, "i", 0);
1070 
1071  if(idx < 0 || idx >= Num_mission_events)
1072  return ade_set_error(L, "i", 0);
1073 
1074  mission_event *mep = &Mission_events[idx];
1075 
1076  if(ADE_SETTING_VAR) {
1077  mep->score = newscore;
1078  }
1079 
1080  return ade_set_args(L, "i", mep->score);
1081 }
1082 
1083 ADE_FUNC(isValid, l_Event, NULL, "Detects whether handle is valid", "boolean", "true if valid, false if handle is invalid, nil if a syntax/type error occurs")
1084 {
1085  int idx;
1086  if(!ade_get_args(L, "o", l_Event.Get(&idx)))
1087  return ADE_RETURN_NIL;
1088 
1089  if(idx < 0 || idx >= Num_mission_events)
1090  return ADE_RETURN_FALSE;
1091 
1092  return ADE_RETURN_TRUE;
1093 }
1094 
1095 //**********HANDLE: File
1096 
1097 ade_obj<CFILE*> l_File("file", "File handle");
1098 
1099 ADE_FUNC(isValid, l_File, NULL, "Detects whether handle is valid", "boolean", "true if valid, false if handle is invalid, nil if a syntax/type error occurs")
1100 {
1101  CFILE *cfp = NULL;
1102  if(!ade_get_args(L, "o", l_File.Get(&cfp)))
1103  return ADE_RETURN_NIL;
1104 
1105  if(!cf_is_valid(cfp))
1106  return ADE_RETURN_FALSE;
1107 
1108  return ADE_RETURN_TRUE;
1109 }
1110 
1111 ADE_FUNC(close, l_File, NULL, "Instantly closes file and invalidates all file handles", NULL, NULL)
1112 {
1113  CFILE *cfp;
1114  if(!ade_get_args(L, "o", l_File.Get(&cfp)))
1115  return ADE_RETURN_FALSE;
1116 
1117  if(!cf_is_valid(cfp))
1118  return ADE_RETURN_FALSE;
1119 
1120  int rval = cfclose(cfp);
1121  if(rval != 0)
1122  {
1123  LuaError(L, "Attempt to close file resulted in error %d", rval);
1124  return ADE_RETURN_FALSE;
1125  }
1126  return ADE_RETURN_TRUE;
1127 }
1128 
1129 ADE_FUNC(flush, l_File, NULL, "Flushes file buffer to disk.", "boolean", "True for success, false on failure")
1130 {
1131  CFILE *cfp = NULL;
1132  if(!ade_get_args(L, "o", l_File.Get(&cfp)))
1133  return ADE_RETURN_FALSE;
1134 
1135  if(!cf_is_valid(cfp))
1136  return ADE_RETURN_FALSE;
1137 
1138  //WMC - this looks reversed, yes, it's right. Look at cflush.
1139  int cf_result = cflush(cfp);
1140  return ade_set_args(L, "b", cf_result ? false : true);
1141 }
1142 
1143 ADE_FUNC(getPath, l_File, NULL, "Determines path of the given file", "string", "Path string of the file handle, or an empty string if it doesn't have one, or the handle is invalid")
1144 {
1145  CFILE *cfp = NULL;
1146  if(!ade_get_args(L, "o", l_File.Get(&cfp)))
1147  return ade_set_error(L, "s", "");
1148 
1149  if(!cf_is_valid(cfp))
1150  return ade_set_error(L, "s", "");
1151 
1152  int id = cf_get_dir_type(cfp);
1153  if(Pathtypes[id].path != NULL)
1154  return ade_set_args(L, "s", Pathtypes[id].path);
1155  else
1156  return ade_set_args(L, "s", "");
1157 }
1158 
1159 extern int cfread_lua_number(double *buf, CFILE *cfile);
1160 ADE_FUNC(read, l_File, "number or string, ...",
1161  "Reads part of or all of a file, depending on arguments passed. Based on basic Lua file:read function."
1162  "Returns nil when the end of the file is reached."
1163  "<br><ul><li>\"*n\" - Reads a number.</li>"
1164  "<li>\"*a\" - Reads the rest of the file and returns it as a string.</li>"
1165  "<li>\"*l\" - Reads a line. Skips the end of line markers.</li>"
1166  "<li>(number) - Reads given number of characters, then returns them as a string.</li></ul>",
1167  "number or string, ...",
1168  "Requested data, or nil if the function fails")
1169 {
1170  CFILE *cfp = NULL;
1171  if(!ade_get_args(L, "o", l_File.Get(&cfp)))
1172  return ADE_RETURN_NIL;
1173 
1174  if(!cf_is_valid(cfp))
1175  return ADE_RETURN_NIL;
1176 
1177  int i;
1178  int num_returned = 0;
1179  int type = LUA_TNONE;
1180 
1181  //WMC - Since we push stuff onto the stack, we must get
1182  //the original arguments NOW.
1183  int lastarg = lua_gettop(L);
1184  for(i = 2; i <= lastarg; i++)
1185  {
1186  type = lua_type(L, i);
1187  char *fmt = NULL;
1188  //int num = 0;
1189  if(type == LUA_TSTRING)
1190  {
1191  fmt = (char*)lua_tostring(L, i);
1192  if(!stricmp(fmt, "*n"))
1193  {
1194  double d = 0.0f;
1195  if(cfread_lua_number(&d, cfp) == EOF)
1196  return ADE_RETURN_NIL;
1197 
1198  lua_pushnumber(L, d);
1199  num_returned++;
1200  }
1201  else if(!stricmp(fmt, "*a"))
1202  {
1203  int tell_res = cftell(cfp);
1204  if(tell_res < 0)
1205  {
1206  Error(LOCATION, "Critical error reading Lua file; could not cftell.");
1207  }
1208  int read_len = cfilelength(cfp) - tell_res;
1209 
1210  char *buf = (char *)vm_malloc(read_len + 1);
1211  int final_len = cfread(buf, 1, read_len, cfp);
1212  buf[final_len] = '\0';
1213 
1214  lua_pushstring(L, buf);
1215  vm_free(buf);
1216  num_returned++;
1217  }
1218  else if(!stricmp(fmt, "*l"))
1219  {
1220  char buf[10240];
1221  size_t idx;
1222  if(cfgets(buf, (int)(sizeof(buf)/sizeof(char)), cfp) == NULL)
1223  {
1224  lua_pushnil(L);
1225  }
1226  else
1227  {
1228  // Strip all newlines so this works like the Lua original
1229  // http://www.lua.org/source/5.1/liolib.c.html#g_read
1230  // Note: we also strip carriage return in WMC's implementation
1231  for (idx = 0; idx < strlen(buf); idx++)
1232  {
1233  if ( buf[idx] == '\n' || buf[idx] == '\r' )
1234  buf[idx] = '\0';
1235  }
1236 
1237  lua_pushstring(L, buf);
1238  }
1239  num_returned++;
1240  }
1241  }
1242  if(type == LUA_TNUMBER || (type == LUA_TSTRING && strpbrk(fmt, "1234567890")))
1243  {
1244  int num = 0;
1245  if(type == LUA_TSTRING)
1246  num = atoi(fmt);
1247  else
1248  num = fl2i(lua_tonumber(L, i));
1249 
1250  if(num < 1)
1251  {
1252  if(cfeof(cfp))
1253  lua_pushstring(L, "");
1254  else
1255  lua_pushnil(L);
1256  }
1257 
1258  char *buf = (char*)vm_malloc(num+1);
1259  int total_read = cfread(buf, 1, num, cfp);
1260  if(total_read)
1261  {
1262  buf[total_read] = '\0';
1263  lua_pushstring(L, buf);
1264  }
1265  else
1266  {
1267  lua_pushnil(L);
1268  }
1269  vm_free(buf);
1270  num_returned++;
1271  }
1272  if(type != LUA_TNUMBER && type != LUA_TSTRING)
1273  LuaError(L, "Invalid argument passed to file:read");
1274  }
1275 
1276  return num_returned;
1277 }
1278 
1279 ADE_FUNC(seek, l_File, "[string Whence=\"cur\", number Offset=0]",
1280  "Changes position of file, or gets location."
1281  "Whence can be:"
1282  "<li>\"set\" - File start.</li>"
1283  "<li>\"cur\" - Current position in file.</li>"
1284  "<li>\"end\" - File end.</li></ul>",
1285  "number",
1286  "new offset, or false or nil on failure")
1287 {
1288  char *w = NULL;
1289  int o = 0;
1290 
1291  CFILE *cfp = NULL;
1292  if(!ade_get_args(L, "o|si", l_File.Get(&cfp), &w, &o))
1293  return ADE_RETURN_NIL;
1294 
1295  if(!cf_is_valid(cfp))
1296  return ADE_RETURN_NIL;
1297 
1298  if(!(w == NULL || (!stricmp(w, "cur") && o != 0)))
1299  {
1300  int seek_type = CF_SEEK_CUR;
1301  if(!stricmp(w, "set"))
1302  seek_type = CF_SEEK_SET;
1303  else if(!stricmp(w, "cur"))
1304  seek_type = CF_SEEK_CUR;
1305  else if(!stricmp(w, "end"))
1306  seek_type = CF_SEEK_END;
1307  else
1308  LuaError(L, "Invalid where argument passed to seek() - '%s'", w);
1309 
1310  if(cfseek(cfp, o, seek_type))
1311  return ADE_RETURN_FALSE;
1312  }
1313 
1314  int res = cftell(cfp);
1315  if(res >= 0)
1316  return ade_set_args(L, "i", res);
1317  else
1318  return ADE_RETURN_FALSE;
1319 }
1320 
1321 ADE_FUNC(write, l_File, "string or number, ...",
1322  "Writes a series of Lua strings or numbers to the current file.", "number", "Number of items successfully written.")
1323 {
1324  CFILE *cfp = NULL;
1325  if(!ade_get_args(L, "o", l_File.Get(&cfp)))
1326  return ade_set_error(L, "i", 0);
1327 
1328  if(!cf_is_valid(cfp))
1329  return ade_set_error(L, "i", 0);
1330 
1331  int l_pos = 2;
1332  int type = LUA_TNONE;
1333 
1334  int num_successful = 0;
1335  while((type = lua_type(L, l_pos)) != LUA_TNONE)
1336  {
1337  if(type == LUA_TSTRING)
1338  {
1339  char *s = (char*)lua_tostring(L, l_pos);
1340  if(cfwrite(s, sizeof(char), strlen(s), cfp))
1341  num_successful++;
1342  }
1343  else if(type == LUA_TNUMBER)
1344  {
1345  double d = lua_tonumber(L, l_pos);
1346  char buf[32]= {0};
1347  sprintf(buf, LUA_NUMBER_FMT, d);
1348  if(cfwrite(buf, sizeof(char), strlen(buf), cfp))
1349  num_successful++;
1350  }
1351 
1352  l_pos++;
1353  }
1354 
1355  return ade_set_args(L, "i", num_successful);
1356 }
1357 
1358 //**********HANDLE: Font
1359 ade_obj<int> l_Font("font", "font handle");
1360 
1361 ADE_FUNC(__tostring, l_Font, NULL, "Filename of font", "string", "Font filename, or an empty string if the handle is invalid")
1362 {
1363  int font_num = -1;
1364  if(!ade_get_args(L, "o", l_Font.Get(&font_num)))
1365  return ade_set_error(L, "s", "");
1366 
1367  if(font_num < 0 || font_num >= Num_fonts)
1368  return ade_set_error(L, "s", "");
1369 
1370  return ade_set_args(L, "s", Fonts[font_num].filename);
1371 }
1372 
1373 ADE_VIRTVAR(Filename, l_Font, "string", "Filename of font (including extension)", "string", NULL)
1374 {
1375  int font_num = -1;
1376  char *newname = NULL;
1377  if(!ade_get_args(L, "o|s", l_Font.Get(&font_num), &newname))
1378  return ade_set_error(L, "s", "");
1379 
1380  if(font_num < 0 || font_num >= Num_fonts)
1381  return ade_set_error(L, "s", "");
1382 
1383  if(ADE_SETTING_VAR) {
1384  strncpy(Fonts[font_num].filename, newname, sizeof(Fonts[font_num].filename)-1);
1385  }
1386 
1387  return ade_set_args(L, "s", Fonts[font_num].filename);
1388 }
1389 
1390 ADE_VIRTVAR(Height, l_Font, "number", "Height of font (in pixels)", "number", "Font height, or 0 if the handle is invalid")
1391 {
1392  int font_num = -1;
1393  int newheight = -1;
1394  if(!ade_get_args(L, "o|i", l_Font.Get(&font_num), &newheight))
1395  return ade_set_error(L, "i", 0);
1396 
1397  if(font_num < 0 || font_num >= Num_fonts)
1398  return ade_set_error(L, "i", 0);
1399 
1400  if(ADE_SETTING_VAR && newheight > 0) {
1401  Fonts[font_num].h = newheight;
1402  }
1403 
1404  return ade_set_args(L, "i", Fonts[font_num].h);
1405 }
1406 
1407 ADE_FUNC(isValid, l_Font, NULL, "True if valid, false or nil if not", "boolean", "Detects whether handle is valid")
1408 {
1409  int font_num;
1410  if(!ade_get_args(L, "o", l_Font.Get(&font_num)))
1411  return ADE_RETURN_NIL;
1412 
1413  if(font_num < 0 || font_num >= Num_fonts)
1414  return ADE_RETURN_FALSE;
1415  else
1416  return ADE_RETURN_TRUE;
1417 }
1418 
1419 //**********HANDLE: gameevent
1421 {
1422 private:
1423  int edx;
1424 public:
1425  gameevent_h(){edx=-1;}
1426  gameevent_h(int n_event){edx=n_event;}
1427 
1428  bool IsValid(){return (edx > -1 && edx < Num_gs_event_text);}
1429 
1430  int Get(){return edx;}
1431 };
1432 
1433 ade_obj<gameevent_h> l_GameEvent("gameevent", "Game event");
1434 
1435 ADE_FUNC(__tostring, l_GameEvent, NULL, "Game event name", "string", "Game event name, or empty string if handle is invalid")
1436 {
1437  gameevent_h *gh = NULL;
1438  if(!ade_get_args(L, "o", l_GameEvent.GetPtr(&gh)))
1439  return ade_set_error(L, "s", "");
1440 
1441  if(!gh->IsValid())
1442  return ade_set_error(L, "s", "");
1443 
1444  return ade_set_args(L, "s", GS_event_text[gh->Get()]);
1445 }
1446 
1447 ADE_VIRTVAR(Name, l_GameEvent, "string", "Game event name", "string", "Game event name, or empty string if handle is invalid")
1448 {
1449  gameevent_h *gh = NULL;
1450  char *n_name = NULL;
1451  if(!ade_get_args(L, "o|s", l_GameEvent.GetPtr(&gh), &n_name))
1452  return ade_set_error(L, "s", "");
1453 
1454  if(!gh->IsValid())
1455  return ade_set_error(L, "s", "");
1456 
1457  int edx = gh->Get();
1458 
1459  if(ADE_SETTING_VAR)
1460  {
1461  Error(LOCATION, "Can't set game event names at this time");
1462  }
1463 
1464  return ade_set_args(L, "s", GS_event_text[edx]);
1465 }
1466 
1467 //**********HANDLE: gamestate
1469 {
1470 private:
1471  int sdx;
1472 public:
1473  gamestate_h(){sdx=-1;}
1474  gamestate_h(int n_state){sdx=n_state;}
1475 
1476  bool IsValid(){return (sdx > -1 && sdx < Num_gs_state_text);}
1477 
1478  int Get(){return sdx;}
1479 };
1480 
1481 ade_obj<gamestate_h> l_GameState("gamestate", "Game state");
1482 
1483 ADE_FUNC(__tostring, l_GameState, NULL, "Game state name", "string", "Game state name, or empty string if handle is invalid")
1484 {
1485  gamestate_h *gh = NULL;
1486  if(!ade_get_args(L, "o", l_GameState.GetPtr(&gh)))
1487  return ade_set_error(L, "s", "");
1488 
1489  if(!gh->IsValid())
1490  return ade_set_error(L, "s", "");
1491 
1492  return ade_set_args(L, "s", GS_state_text[gh->Get()]);
1493 }
1494 
1495 ADE_VIRTVAR(Name, l_GameState,"string", "Game state name", "string", "Game state name, or empty string if handle is invalid")
1496 {
1497  gamestate_h *gh = NULL;
1498  char *n_name = NULL;
1499  if(!ade_get_args(L, "o|s", l_GameState.GetPtr(&gh), &n_name))
1500  return ade_set_error(L, "s", "");
1501 
1502  if(!gh->IsValid())
1503  return ade_set_error(L, "s", "");
1504 
1505  int sdx = gh->Get();
1506 
1507  if(ADE_SETTING_VAR)
1508  {
1509  Error(LOCATION, "Can't set game state names at this time");
1510  }
1511 
1512  return ade_set_args(L, "s", GS_state_text[sdx]);
1513 }
1514 
1515 //**********HANDLE: HUD Gauge
1516 ade_obj<HudGauge> l_HudGauge("HudGauge", "HUD Gauge handle");
1517 
1518 ADE_VIRTVAR(Name, l_HudGauge, "string", "Custom HUD Gauge name", "string", "Custom HUD Gauge name, or nil if handle is invalid")
1519 {
1520  HudGauge* gauge;
1521 
1522  if (!ade_get_args(L, "o", l_HudGauge.GetPtr(&gauge)))
1523  return ADE_RETURN_NIL;
1524 
1525  if (gauge->getObjectType() != HUD_OBJECT_CUSTOM)
1526  return ADE_RETURN_NIL;
1527 
1528  return ade_set_args(L, "s", gauge->getCustomGaugeName());
1529 }
1530 
1531 ADE_VIRTVAR(Text, l_HudGauge, "string", "Custom HUD Gauge text", "string", "Custom HUD Gauge text, or nil if handle is invalid")
1532 {
1533  HudGauge* gauge;
1534  char* text = NULL;
1535 
1536  if (!ade_get_args(L, "o|s", l_HudGauge.GetPtr(&gauge), text))
1537  return ADE_RETURN_NIL;
1538 
1539  if (gauge->getObjectType() != HUD_OBJECT_CUSTOM)
1540  return ADE_RETURN_NIL;
1541 
1542  if (ADE_SETTING_VAR && text != NULL)
1543  {
1544  gauge->updateCustomGaugeText(text);
1545  }
1546 
1547  return ade_set_args(L, "s", gauge->getCustomGaugeText());
1548 }
1549 
1550 //**********HANDLE: Eyepoint
1551 struct eye_h
1552 {
1553  int model;
1554  int eye_idx;
1555 
1556  eye_h(){model=-1;eye_idx=-1;}
1557  eye_h(int n_m, int n_e){model=n_m; eye_idx=n_e;}
1558  bool IsValid(){
1559  polymodel *pm = NULL;
1560  return (model > -1
1561  && (pm = model_get(model)) != NULL
1562  && eye_idx > -1
1563  && eye_idx < pm->n_view_positions);
1564  }
1565 };
1566 ade_obj<eye_h> l_Eyepoint("eyepoint", "Eyepoint handle");
1567 
1568 ADE_VIRTVAR(Normal, l_Eyepoint, "vector", "Eyepoint normal", "vector", "Eyepoint normal, or null vector if handle is invalid")
1569 {
1570  eye_h *eh;
1571  vec3d *v;
1572  if(!ade_get_args(L, "o|o", l_Eyepoint.GetPtr(&eh), l_Vector.GetPtr(&v)))
1573  return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
1574 
1575  if(!eh->IsValid())
1576  return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
1577 
1578  polymodel *pm = model_get(eh->model);
1579 
1580  if(ADE_SETTING_VAR && v != NULL)
1581  {
1582  pm->view_positions[eh->eye_idx].norm = *v;
1583  }
1584 
1585  return ade_set_args(L, "o", l_Vector.Set(pm->view_positions[eh->eye_idx].norm));
1586 }
1587 
1588 ADE_VIRTVAR(Position, l_Eyepoint, "vector", "Eyepoint location (Local vector)", "vector", "Eyepoint location, or null vector if handle is invalid")
1590  eye_h *eh;
1591  vec3d *v;
1592  if(!ade_get_args(L, "o|o", l_Eyepoint.GetPtr(&eh), l_Vector.GetPtr(&v)))
1593  return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
1594 
1595  if(!eh->IsValid())
1596  return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
1597 
1599 
1600  if(ADE_SETTING_VAR && v != NULL)
1601  {
1602  pm->view_positions[eh->eye_idx].pnt = *v;
1603  }
1604 
1605  return ade_set_args(L, "o", l_Vector.Set(pm->view_positions[eh->eye_idx].pnt));
1606 }
1607 
1608 ADE_FUNC(IsValid, l_Eyepoint, NULL, "Detect whether this handle is valid", "boolean", "true if valid false otherwise")
1609 {
1610  eye_h *eh = NULL;
1611  if (!ade_get_args(L, "o", l_Eyepoint.GetPtr(&eh)))
1612  {
1613  return ADE_RETURN_FALSE;
1614  }
1615 
1616  return ade_set_args(L, "b", eh->IsValid());
1617 }
1618 
1619 //**********HANDLE: model
1620 class model_h
1621 {
1622 protected:
1623  int mid;
1625 
1626 public:
1628  if(!this->IsValid())
1629  return NULL;
1630 
1631  return model;
1632  }
1633 
1634  int GetID(){
1635  if(!this->IsValid())
1636  return -1;
1637 
1638  return mid;
1639  }
1640 
1641  bool IsValid(){
1642  return (model != NULL && mid > -1 && model_get(mid) == model);
1643  }
1644 
1645  model_h(int n_modelnum) {
1646  mid = n_modelnum;
1647  if(mid > 0)
1648  model = model_get(mid);
1649  else
1650  model = NULL;
1651  }
1652  model_h(polymodel *n_model) {
1653  model = n_model;
1654  if(n_model != NULL)
1655  mid = n_model->id;
1656  else
1657  mid = -1;
1658  }
1660  mid=-1;
1661  model = NULL;
1662  }
1663 };
1664 
1665 class modeltextures_h : public model_h
1666 {
1667 public:
1670 };
1671 ade_obj<model_h> l_Model("model", "3D Model (POF) handle");
1672 
1673 ade_obj<modeltextures_h> l_ModelTextures("modeltextures_h", "Array of materials");
1674 
1675 class eyepoints_h : public model_h
1676 {
1677 public:
1680 };
1681 
1682 ade_obj<eyepoints_h> l_Eyepoints("eyepoints", "Array of model eye points");
1683 
1684 // Thrusters:
1685 class thrusters_h : public model_h
1686 {
1687  public:
1690 };
1691 
1692 ade_obj<thrusters_h> l_Thrusters("thrusters", "The thrusters of a model");
1693 
1694 // Thrusterbank:
1696 {
1698 
1700  {
1701  bank = NULL;
1702  }
1703 
1705  {
1706  bank = ba;
1707  }
1708 
1710  {
1711  if (!isValid())
1712  return NULL;
1713 
1714  return bank;
1715  }
1716 
1717  bool isValid()
1718  {
1719  return bank != NULL;
1720  }
1721 };
1722 
1723 ade_obj<thrusterbank_h> l_Thrusterbank("thrusterbank", "A model thrusterbank");
1724 
1725 // Glowpoint:
1727 {
1729 
1731  {
1732  }
1733 
1735  {
1736  point = np;
1737  }
1738 
1740  {
1741  if (!isValid())
1742  return NULL;
1743 
1744  return point;
1745  }
1746 
1747  bool isValid()
1748  {
1749  return point != NULL;
1750  }
1751 
1752 };
1753 
1754 ade_obj<glowpoint_h> l_Glowpoint("glowpoint", "A model glowpoint");
1755 
1756 // Glowbanks:
1757 class dockingbays_h : public model_h
1758 {
1759  public:
1762 };
1763 ade_obj<dockingbays_h> l_Dockingbays("dockingbays", "The docking bays of a model");
1764 
1765 ADE_VIRTVAR(Textures, l_Model, "modeltextures_h", "Model textures", "modeltextures_h", "Model textures, or an invalid modeltextures handle if the model handle is invalid")
1766 {
1767  model_h *mdl = NULL;
1768  modeltextures_h *oth = NULL;
1769  if(!ade_get_args(L, "o|o", l_Model.GetPtr(&mdl), l_ModelTextures.GetPtr(&oth)))
1770  return ade_set_error(L, "o", l_ModelTextures.Set(modeltextures_h()));
1771 
1772  polymodel *pm = mdl->Get();
1773  if(pm == NULL)
1774  return ade_set_error(L, "o", l_ModelTextures.Set(modeltextures_h()));
1775 
1776  if(ADE_SETTING_VAR && oth && oth->IsValid()) {
1777  //WMC TODO: Copy code
1778  LuaError(L, "Attempt to use Incomplete Feature: Modeltextures copy");
1779  }
1780 
1781  return ade_set_args(L, "o", l_ModelTextures.Set(modeltextures_h(pm)));
1782 }
1783 
1784 ADE_VIRTVAR(Thrusters, l_Model, "thrusters", "Model thrusters", "thrusters", "Thrusters of the model or invalid handle")
1785 {
1786  model_h *mdl = NULL;
1787  thrusters_h *oth = NULL;
1788  if(!ade_get_args(L, "o|o", l_Model.GetPtr(&mdl), l_Thrusters.GetPtr(&oth)))
1789  return ade_set_error(L, "o", l_Thrusters.Set(thrusters_h()));
1790 
1791  polymodel *pm = mdl->Get();
1792  if(pm == NULL)
1793  return ade_set_error(L, "o", l_Thrusters.Set(thrusters_h()));
1794 
1795  if(ADE_SETTING_VAR && oth && oth->IsValid()) {
1796  LuaError(L, "Attempt to use Incomplete Feature: Thrusters copy");
1797  }
1798 
1799  return ade_set_args(L, "o", l_Thrusters.Set(thrusters_h(pm)));
1800 }
1801 
1802 ADE_VIRTVAR(Eyepoints, l_Model, "eyepoints", "Model eyepoints", "eyepoints", "Array of eyepoints or invalid handle on error")
1803 {
1804  model_h *mdl = NULL;
1805  eyepoints_h *eph = NULL;
1806  if(!ade_get_args(L, "o|o", l_Model.GetPtr(&mdl), l_Eyepoints.GetPtr(&eph)))
1807  return ade_set_error(L, "o", l_Eyepoints.Set(eyepoints_h()));
1808 
1809  polymodel *pm = mdl->Get();
1810  if(pm == NULL)
1811  return ade_set_error(L, "o", l_Eyepoints.Set(eyepoints_h()));
1812 
1813  if(ADE_SETTING_VAR && eph && eph->IsValid()) {
1814  LuaError(L, "Attempt to use Incomplete Feature: Eyepoints copy");
1815  }
1816 
1817  return ade_set_args(L, "o", l_Eyepoints.Set(eyepoints_h(pm)));
1818 }
1819 
1820 ADE_VIRTVAR(Dockingbays, l_Model, "dockingbays", "Docking bays handle of model", "dockingbays", "Array of docking bays on this model, or invalid handle on error")
1821 {
1822  model_h *mdl = NULL;
1823  dockingbays_h *dbh = NULL;
1824  if(!ade_get_args(L, "o|o", l_Model.GetPtr(&mdl), l_Dockingbays.GetPtr(&dbh)))
1825  return ade_set_error(L, "o", l_Dockingbays.Set(dockingbays_h()));
1826 
1827  polymodel *pm = mdl->Get();
1828  if(pm == NULL)
1829  return ade_set_error(L, "o", l_Dockingbays.Set(dockingbays_h()));
1830 
1831  if(ADE_SETTING_VAR && dbh && dbh->IsValid()) {
1832  LuaError(L, "Attempt to use Incomplete Feature: Docking bays copy");
1833  }
1834 
1835  return ade_set_args(L, "o", l_Dockingbays.Set(dockingbays_h(pm)));
1836 }
1837 
1838 extern void model_calc_bound_box( vec3d *box, vec3d *big_mn, vec3d *big_mx);
1839 
1840 ADE_VIRTVAR(BoundingBoxMax, l_Model, "vector", "Model bounding box maximum", "vector", "Model bounding box, or an empty vector if the handle is invalid")
1841 {
1842  model_h *mdl = NULL;
1843  vec3d *v = NULL;
1844  if(!ade_get_args(L, "o|o", l_Model.GetPtr(&mdl), l_Vector.GetPtr(&v)))
1845  return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
1846 
1847  polymodel *pm = mdl->Get();
1848 
1849  if(pm == NULL)
1850  return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
1851 
1852  if(ADE_SETTING_VAR && v != NULL) {
1853  pm->maxs = *v;
1854 
1855  //Recalculate this, so it stays valid
1856  model_calc_bound_box(pm->bounding_box, &pm->mins, &pm->maxs);
1857  }
1858 
1859  return ade_set_args(L, "o", l_Vector.Set(pm->maxs));
1860 }
1861 
1862 ADE_VIRTVAR(BoundingBoxMin, l_Model, "vector", "Model bounding box minimum", "vector", "Model bounding box, or an empty vector if the handle is invalid")
1863 {
1864  model_h *mdl = NULL;
1865  vec3d *v = NULL;
1866  if(!ade_get_args(L, "o|o", l_Model.GetPtr(&mdl), l_Vector.GetPtr(&v)))
1867  return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
1868 
1869  polymodel *pm = mdl->Get();
1870 
1871  if(pm == NULL)
1872  return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
1873 
1874  if(ADE_SETTING_VAR && v != NULL) {
1875  pm->mins = *v;
1876 
1877  //Recalculate this, so it stays valid
1878  model_calc_bound_box(pm->bounding_box, &pm->mins, &pm->maxs);
1879  }
1880 
1881  return ade_set_args(L, "o", l_Vector.Set(pm->mins));
1882 }
1883 
1884 ADE_VIRTVAR(Filename, l_Model, "string", "Model filename", "string", "Model filename, or an empty string if the handle is invalid")
1885 {
1886  model_h *mdl = NULL;
1887  char *s = NULL;
1888  if(!ade_get_args(L, "o|s", l_Model.GetPtr(&mdl), &s))
1889  return ade_set_error(L, "s", "");
1890 
1891  polymodel *pm = mdl->Get();
1892 
1893  if(pm == NULL)
1894  return ade_set_error(L, "s", "");
1895 
1896  if(ADE_SETTING_VAR) {
1897  strncpy(pm->filename, s, sizeof(pm->filename) - sizeof(char));
1898  }
1899 
1900  return ade_set_args(L, "s", pm->filename);
1901 }
1902 
1903 ADE_VIRTVAR(Mass, l_Model, "number", "Model mass", "number", "Model mass, or 0 if the model handle is invalid")
1904 {
1905  model_h *mdl = NULL;
1906  float nm = 0.0f;
1907  if(!ade_get_args(L, "o|f", l_Model.GetPtr(&mdl), &nm))
1908  return ade_set_error(L, "f", 0.0f);
1909 
1910  polymodel *pm = mdl->Get();
1911 
1912  if(pm == NULL)
1913  return ade_set_error(L, "f", 0.0f);
1914 
1915  if(ADE_SETTING_VAR) {
1916  pm->mass = nm;
1917  }
1918 
1919  return ade_set_args(L, "f", pm->mass);
1920 }
1921 
1922 ADE_VIRTVAR(MomentOfInertia, l_Model, "orientation", "Model moment of inertia", "orientation", "Moment of Inertia matrix or identity matrix if invalid" )
1923 {
1924  model_h *mdl = NULL;
1925  matrix_h *mh = NULL;
1926  if(!ade_get_args(L, "o|o", l_Model.GetPtr(&mdl), l_Matrix.GetPtr(&mh)))
1927  return ade_set_error(L, "o", l_Matrix.Set(matrix_h()));
1928 
1929  polymodel *pm = mdl->Get();
1930 
1931  if(pm == NULL)
1932  return ade_set_error(L, "o", l_Matrix.Set(matrix_h()));
1933 
1934  if(ADE_SETTING_VAR && mh != NULL) {
1935  matrix *mtx = mh->GetMatrix();
1936  memcpy(&pm->moment_of_inertia, mtx, sizeof(*mtx));
1937  }
1938 
1939  return ade_set_args(L, "o", l_Matrix.Set(matrix_h(&pm->moment_of_inertia)));
1940 }
1941 
1942 ADE_VIRTVAR(Radius, l_Model, "number", "Model radius (Used for collision & culling detection)", "number", "Model Radius or 0 if invalid")
1943 {
1944  model_h *mdl = NULL;
1945  float nr = 0.0f;
1946  if(!ade_get_args(L, "o|f", l_Model.GetPtr(&mdl), &nr))
1947  return ade_set_error(L, "f", 0.0f);
1948 
1949  polymodel *pm = mdl->Get();
1950 
1951  if(pm == NULL)
1952  return ade_set_error(L, "f", 0.0f);
1953 
1954  if(ADE_SETTING_VAR) {
1955  pm->rad = nr;
1956  }
1957 
1958  return ade_set_args(L, "f", pm->rad);
1959 }
1960 
1961 ADE_FUNC(isValid, l_Model, NULL, "True if valid, false or nil if not", "boolean", "Detects whether handle is valid")
1962 {
1963  model_h *mdl;
1964  if(!ade_get_args(L, "o", l_Model.GetPtr(&mdl)))
1965  return ADE_RETURN_NIL;
1966 
1967  return mdl->IsValid();
1968 }
1969 
1970 //**********HANDLE: eyepoints
1971 ADE_FUNC(__len, l_Eyepoints, NULL, "Gets the number of eyepoints on this model", "number", "Number of eyepoints on this model or 0 on error")
1972 {
1973  eyepoints_h *eph = NULL;
1974  if (!ade_get_args(L, "o", l_Eyepoints.GetPtr(&eph)))
1975  {
1976  return ade_set_error(L, "i", 0);
1977  }
1978 
1979  if (!eph->IsValid())
1980  {
1981  return ade_set_error(L, "i", 0);
1982  }
1983 
1984  polymodel *pm = eph->Get();
1985 
1986  if (pm == NULL)
1987  {
1988  return ade_set_error(L, "i", 0);
1989  }
1990 
1991  return ade_set_args(L, "i", pm->n_view_positions);
1992 }
1993 
1994 ADE_INDEXER(l_Eyepoints, "eyepoint", "Gets en eyepoint handle", "eyepoint", "eye handle or invalid handle on error")
1995 {
1996  eyepoints_h *eph = NULL;
1997  int index = -1;
1998  eye_h *eh = NULL;
1999 
2000  if (!ade_get_args(L, "oi|o", l_Eyepoints.GetPtr(&eph), &index, l_Eyepoint.GetPtr(&eh)))
2001  {
2002  return ade_set_error(L, "o", l_Eyepoint.Set(eye_h()));
2003  }
2004 
2005  if (!eph->IsValid())
2006  {
2007  return ade_set_error(L, "o", l_Eyepoint.Set(eye_h()));
2008  }
2009 
2010  polymodel *pm = eph->Get();
2011 
2012  if (pm == NULL)
2013  {
2014  return ade_set_error(L, "o", l_Eyepoint.Set(eye_h()));
2015  }
2016 
2017  index--; // Lua -> FS2
2018 
2020  {
2021  return ade_set_error(L, "o", l_Eyepoint.Set(eye_h()));
2022  }
2023 
2024  if (ADE_SETTING_VAR && eh && eh->IsValid())
2025  {
2026  LuaError(L, "Attempted to use incomplete feature: Eyepoint copy");
2027  }
2028 
2029  return ade_set_args(L, "o", l_Eyepoint.Set(eye_h(eph->GetID(), index)));
2030 }
2031 
2032 ADE_FUNC(isValid, l_Eyepoints, NULL, "Detects whether handle is valid or not", "boolean", "true if valid false otherwise")
2033 {
2034  eyepoints_h *eph;
2035  if(!ade_get_args(L, "o", l_Eyepoints.GetPtr(&eph)))
2036  return ADE_RETURN_FALSE;
2037 
2038  return ade_set_args(L, "b", eph->IsValid());
2039 }
2040 
2041 //**********HANDLE: thrusters
2042 ADE_FUNC(__len, l_Thrusters, NULL, "Number of thruster banks on the model", "number", "Number of thrusterbanks")
2043 {
2044  thrusters_h *trh;
2045  if(!ade_get_args(L, "o", l_Thrusters.GetPtr(&trh)))
2046  return ade_set_error(L, "i", -1);
2047 
2048  if(!trh->IsValid())
2049  return ade_set_error(L, "i", -1);
2050 
2051  polymodel *pm = trh->Get();
2052 
2053  if(pm == NULL)
2054  return ade_set_error(L, "i", -1);
2055 
2056  return ade_set_args(L, "i", pm->n_thrusters);
2057 }
2058 
2059 ADE_INDEXER(l_Thrusters, "number Index", "Array of all thrusterbanks on this thruster", "thrusterbank", "Handle to the thrusterbank or invalid handle if index is invalid")
2060 {
2061  thrusters_h *trh = NULL;
2062  char *s = NULL;
2063  thrusterbank_h newThr;
2064 
2065  if (!ade_get_args(L, "os|o", l_Thrusters.GetPtr(&trh), &s, l_Thrusterbank.Get(&newThr)))
2066  return ade_set_error(L, "o", l_Thrusterbank.Set(thrusterbank_h()));
2067 
2068  polymodel *pm = trh->Get();
2069 
2070  if (!trh->IsValid() || s == NULL || pm == NULL)
2071  return ade_set_error(L, "o", l_Thrusterbank.Set(thrusterbank_h()));
2072 
2073  //Determine index
2074  int idx = atoi(s) - 1; //Lua->FS2
2075 
2076  if (idx < 0 || idx >= pm->n_thrusters)
2077  return ade_set_error(L, "o", l_Thrusterbank.Set(thrusterbank_h()));
2078 
2079  thruster_bank* bank = &pm->thrusters[idx];
2080 
2081  if (ADE_SETTING_VAR && trh != NULL)
2082  {
2083  if (newThr.isValid())
2084  {
2085  pm->thrusters[idx] = *(newThr.Get());
2086  }
2087  }
2088 
2089  return ade_set_args(L, "o", l_Thrusterbank.Set(bank));
2090 }
2091 
2092 ADE_FUNC(isValid, l_Thrusters, NULL, "Detects whether handle is valid", "boolean", "true if valid, false if handle is invalid, nil if a syntax/type error occurs")
2093 {
2094  thrusters_h *trh;
2095  if(!ade_get_args(L, "o", l_Thrusters.GetPtr(&trh)))
2096  return ADE_RETURN_NIL;
2097 
2098  return ade_set_args(L, "b", trh->IsValid());
2099 }
2100 
2101 //**********HANDLE: thrusterbank
2102 ADE_FUNC(__len, l_Thrusterbank, NULL, "Number of thrusters on this thrusterbank", "number", "Number of thrusters on this bank or 0 if handle is invalid")
2103 {
2104  thrusterbank_h *tbh = NULL;
2105  if(!ade_get_args(L, "o", l_Thrusterbank.GetPtr(&tbh)))
2106  return ade_set_error(L, "i", -1);
2107 
2108  if(!tbh->isValid())
2109  return ade_set_error(L, "i", -1);
2110 
2111  thruster_bank* bank = tbh->Get();
2112 
2113  return ade_set_args(L, "i", bank->num_points);
2114 }
2115 
2116 ADE_INDEXER(l_Thrusterbank, "number Index", "Array of glowpoint", "glowpoint", "Glowpoint, or invalid glowpoint handle on failure")
2117 {
2118  thrusterbank_h *tbh = NULL;
2119  char *s = NULL;
2120  glowpoint_h *glh = NULL;
2121 
2122  if (!ade_get_args(L, "os|o", l_Thrusterbank.GetPtr(&tbh), &s, l_Glowpoint.GetPtr(&glh)))
2123  return ade_set_error(L, "o", l_Glowpoint.Set(glowpoint_h()));
2124 
2125  if (!tbh->isValid() || s==NULL)
2126  return ade_set_error(L, "o", l_Glowpoint.Set(glowpoint_h()));
2127 
2128  thruster_bank* bank = tbh->Get();
2129 
2130  //Determine index
2131  int idx = atoi(s) - 1; //Lua->FS2
2132 
2133  if (idx < 0 || idx >= bank->num_points)
2134  return ade_set_error(L, "o", l_Glowpoint.Set(glowpoint_h()));
2135 
2136  glow_point* glp = &bank->points[idx];
2137 
2138  if (ADE_SETTING_VAR && glh != NULL)
2139  {
2140  if (glh->isValid())
2141  {
2142  bank->points[idx] = *(glh->Get());
2143  }
2144  }
2145 
2146  return ade_set_args(L, "o", l_Glowpoint.Set(glp));
2147 }
2148 
2149 ADE_FUNC(isValid, l_Thrusterbank, NULL, "Detectes if this handle is valid", "boolean", "true if this handle is valid, false otherwise")
2150 {
2151  thrusterbank_h* trh;
2152  if(!ade_get_args(L, "o", l_Thrusterbank.GetPtr(&trh)))
2153  return ADE_RETURN_FALSE;
2154 
2155  if (!trh->isValid())
2156  return ADE_RETURN_FALSE;
2157 
2158  return ade_set_args(L, "b", trh->isValid());
2159 }
2160 
2161 //**********HANDLE: glowpoint
2162 ADE_VIRTVAR(Position, l_Glowpoint, NULL, "The (local) vector to the position of the glowpoint", "vector", "The local vector to the glowpoint or nil invalid")
2164  glowpoint_h *glh = NULL;
2165  vec3d newVec;
2166 
2167  if(!ade_get_args(L, "o|o", l_Glowpoint.GetPtr(&glh), l_Vector.Get(&newVec)))
2168  return ADE_RETURN_NIL;
2169 
2170  if (!glh->isValid())
2171  return ADE_RETURN_NIL;
2172 
2173  vec3d vec = glh->point->pnt;
2174 
2175  if (ADE_SETTING_VAR)
2176  {
2177  glh->point->pnt = newVec;
2178  }
2179 
2180  return ade_set_args(L, "o", l_Vector.Set(vec));
2181 }
2182 
2183 ADE_VIRTVAR(Radius, l_Glowpoint, NULL, "The radius of the glowpoint", "number", "The radius of the glowpoint or -1 of invalid")
2184 {
2185  glowpoint_h* glh = NULL;
2186  float newVal;
2187 
2188  if(!ade_get_args(L, "o|f", l_Glowpoint.GetPtr(&glh), &newVal))
2189  return ade_set_error(L, "f", -1.0f);
2190 
2191  if (!glh->isValid())
2192  return ade_set_error(L, "f", -1.0f);
2193 
2194  float radius = glh->point->radius;
2195 
2196  if (ADE_SETTING_VAR)
2197  {
2198  glh->point->radius = newVal;
2199  }
2200 
2201  return ade_set_args(L, "f", radius);
2202 }
2203 
2204 ADE_FUNC(isValid, l_Glowpoint, NULL, "Returns wether this handle is valid or not", "boolean", "True if handle is valid, false otherwise")
2205 {
2206  glowpoint_h glh = NULL;
2207 
2208  if(!ade_get_args(L, "o", l_Glowpoint.Get(&glh)))
2209  return ADE_RETURN_FALSE;
2210 
2211  return ade_set_args(L, "b", glh.isValid());
2212 }
2213 
2214 class dockingbay_h : public model_h
2215 {
2216 private:
2217  int dock_id;
2218 
2219 public:
2220  dockingbay_h(polymodel *pm, int dock_idx) : model_h(pm), dock_id(dock_idx) {}
2221  dockingbay_h() : model_h(), dock_id(-1){}
2222 
2223  bool IsValid()
2224  {
2225  if (!model_h::IsValid())
2226  {
2227  return false;
2228  }
2229  else
2230  {
2231  return dock_id >= 0 && dock_id < this->Get()->n_docks;
2232  }
2233  }
2234 
2236  {
2237  if (!this->IsValid())
2238  {
2239  return NULL;
2240  }
2241 
2242  return &this->Get()->docking_bays[dock_id];
2243  }
2244 };
2245 ade_obj<dockingbay_h> l_Dockingbay("dockingbay", "Handle to a model docking bay");
2246 
2247 //**********HANDLE: dockingbays
2248 ADE_INDEXER(l_Dockingbays, "dockingbay", "Gets a dockingbay handle from this model. If a string is given then a dockingbay with that name is searched.", "dockingbay", "Handle or invalid handle on error")
2249 {
2250  dockingbays_h *dbhp = NULL;
2251  int index = -1;
2252  dockingbay_h *newVal = NULL;
2253 
2254  if (lua_isnumber(L, 2))
2255  {
2256  if (!ade_get_args(L, "oi|o", l_Dockingbays.GetPtr(&dbhp), &index, l_Dockingbay.GetPtr(&newVal)))
2257  return ade_set_error(L, "o", l_Dockingbay.Set(dockingbay_h()));
2258 
2259  if (!dbhp->IsValid())
2260  return ade_set_error(L, "o", l_Dockingbay.Set(dockingbay_h()));
2261 
2262  index--; // Lua --> C/C++
2263  }
2264  else
2265  {
2266  char* name = NULL;
2267 
2268  if (!ade_get_args(L, "os|o", l_Dockingbays.GetPtr(&dbhp), &name, l_Dockingbay.GetPtr(&newVal)))
2269  {
2270  return ade_set_error(L, "o", l_Dockingbay.Set(dockingbay_h()));
2271  }
2272 
2273  if (!dbhp->IsValid() && name != NULL)
2274  return ade_set_error(L, "o", l_Dockingbay.Set(dockingbay_h()));
2275 
2276  index = model_find_dock_name_index(dbhp->GetID(), name);
2277  }
2278 
2279  polymodel *pm = dbhp->Get();
2280 
2281  if (index < 0 || index >= pm->n_docks)
2282  {
2283  return ade_set_error(L, "o", l_Dockingbay.Set(dockingbay_h()));
2284  }
2285 
2286  return ade_set_args(L, "o", l_Dockingbay.Set(dockingbay_h(pm, index)));
2287 }
2288 
2289 ADE_FUNC(__len, l_Dockingbays, NULL, "Retrieves the number of dockingbays on this model", "number", "number of docking bays or 0 on error")
2290 {
2291  dockingbays_h *dbhp = NULL;
2292 
2293  if (!ade_get_args(L, "o", l_Dockingbays.GetPtr(&dbhp)))
2294  return ade_set_error(L, "i", 0);
2295 
2296  if (!dbhp->IsValid())
2297  return ade_set_error(L, "i", 0);
2298 
2299  return ade_set_args(L, "i", dbhp->Get()->n_docks);
2300 }
2301 
2302 //**********HANDLE: dockingbay
2303 ADE_FUNC(__len, l_Dockingbay, NULL, "Gets the number of docking points in this bay", "number", "The number of docking points or 0 on error")
2304 {
2305  dockingbay_h* dbh = NULL;
2306 
2307  if (!ade_get_args(L, "o", l_Dockingbay.GetPtr(&dbh)))
2308  {
2309  return ade_set_error(L, "i", 0);
2310  }
2311 
2312  if (dbh == NULL || !dbh->IsValid())
2313  {
2314  return ade_set_error(L, "i", 0);
2315  }
2316 
2317  return ade_set_args(L, "i", dbh->getDockingBay()->num_slots);
2318 }
2319 
2320 ADE_FUNC(getName, l_Dockingbay, NULL, "Gets the name of this docking bay", "string", "The name or an empty string on error")
2321 {
2322  dockingbay_h* dbh = NULL;
2323  if (!ade_get_args(L, "o", l_Dockingbay.GetPtr(&dbh)))
2324  {
2325  return ade_set_error(L, "s", "");
2326  }
2327 
2328  if (dbh == NULL || !dbh->IsValid())
2329  {
2330  return ade_set_error(L, "s", "");
2331  }
2332 
2333  dock_bay* dbp = dbh->getDockingBay();
2334 
2335  return ade_set_args(L, "s", dbp->name);
2336 }
2337 
2338 ADE_FUNC(getPoint, l_Dockingbay, "number index", "Gets the location of a docking point in this bay", "vector", "The local location or null vector on error")
2339 {
2340  dockingbay_h* dbh = NULL;
2341  int index = -1;
2342 
2343  if (!ade_get_args(L, "oi", l_Dockingbay.GetPtr(&dbh), &index))
2344  {
2345  return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
2346  }
2347 
2348  index--; // Lua --> C/C++
2349 
2350  if (dbh == NULL || !dbh->IsValid())
2351  {
2352  return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
2353  }
2354 
2355  dock_bay* dbp = dbh->getDockingBay();
2356 
2358  {
2359  LuaError(L, "Invalid dock bay index %d!", (index + 1));
2360  return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
2361  }
2362 
2363  return ade_set_args(L, "o", l_Vector.Set(dbp->pnt[index]));
2364 }
2365 
2366 ADE_FUNC(getNormal, l_Dockingbay, "number index", "Gets the normal of a docking point in this bay", "vector", "The normal vector or null vector on error")
2367 {
2368  dockingbay_h* dbh = NULL;
2369  int index = -1;
2370 
2371  if (!ade_get_args(L, "oi", l_Dockingbay.GetPtr(&dbh), &index))
2372  {
2373  return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
2374  }
2375 
2376  index--; // Lua --> C/C++
2377 
2378  if (dbh == NULL || !dbh->IsValid())
2379  {
2380  return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
2381  }
2382 
2383  dock_bay* dbp = dbh->getDockingBay();
2384 
2386  {
2387  LuaError(L, "Invalid dock bay index %d!", (index + 1));
2388  return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
2389  }
2390 
2391  return ade_set_args(L, "o", l_Vector.Set(dbp->norm[index]));
2392 }
2393 
2394 ADE_FUNC(computeDocker, l_Dockingbay, "dockingbay", "Computes the final position and orientation of a docker bay that docks with this bay.", "vector, orientation", "The local location and orientation of the docker vessel in the reference to the vessel of the docking bay handle, or a nil value on error")
2395 {
2396  dockingbay_h *dockee_bay_h = NULL, *docker_bay_h = NULL;
2397  vec3d final_pos;
2398  matrix final_orient;
2399 
2400  if (!ade_get_args(L, "oo", l_Dockingbay.GetPtr(&dockee_bay_h), l_Dockingbay.GetPtr(&docker_bay_h)))
2401  {
2402  return ADE_RETURN_NIL;
2403  }
2404 
2405  if (!dockee_bay_h->IsValid() || !docker_bay_h->IsValid())
2406  {
2407  return ADE_RETURN_NIL;
2408  }
2409 
2410  dock_bay* dockee_bay = dockee_bay_h->getDockingBay();
2411  dock_bay* docker_bay = docker_bay_h->getDockingBay();
2412 
2413  // Mostly the same as aicode.cpp: dock_orient_and_approach
2414  vec3d dockee_dock_pos, docker_dock_pos_local, docker_dock_pos;
2415  vec3d dock_up_dir;
2416 
2417  // Get the center between the two docking points
2418  vm_vec_avg(&dockee_dock_pos, &dockee_bay->pnt[0], &dockee_bay->pnt[1]);
2419  vm_vec_avg(&docker_dock_pos_local, &docker_bay->pnt[0], &docker_bay->pnt[1]);
2420 
2421  // Get the up-vector of the docking bay
2422  vm_vec_sub(&dock_up_dir, &dockee_bay->pnt[1], &dockee_bay->pnt[0]);
2423 
2424  // Compute the orientation
2425  vm_vector_2_matrix(&final_orient, &dockee_bay->norm[0], &dock_up_dir, NULL);
2426 
2427  // Rotate the docker position into the right orientation
2428  vm_vec_unrotate(&docker_dock_pos, &docker_dock_pos_local, &final_orient);
2429 
2430  // The docker vector points into the wrong direction, we need to scale it appropriately
2431  vm_vec_scale(&docker_dock_pos, -1.0f);
2432 
2433  // Now get the position of the other vessel
2434  vm_vec_add(&final_pos, &dockee_dock_pos, &docker_dock_pos);
2435 
2436  return ade_set_args(L, "oo", l_Vector.Set(final_pos),l_Matrix.Set(matrix_h(&final_orient)));
2437 }
2438 
2439 ADE_FUNC(isValid, l_Dockingbay, NULL, "Detects whether is valid or not", "number", "<i>true</i> if valid, <i>false</i> otherwise")
2440 {
2441  dockingbay_h* dbh = NULL;
2442 
2443  if (!ade_get_args(L, "o", l_Dockingbay.GetPtr(&dbh)))
2444  {
2445  return ade_set_error(L, "i", 0);
2446  }
2447 
2448  if (dbh == NULL)
2449  {
2450  return ADE_RETURN_FALSE;
2451  }
2452 
2453  return ade_set_args(L, "b", dbh->IsValid());
2454 }
2455 
2456 //**********HANDLE: physics
2458 {
2461 
2463  objh = object_h();
2464  pi = NULL;
2465  }
2466 
2468  objh = object_h(objp);
2469  pi = &objp->phys_info;
2470  }
2471 
2473  pi = in_pi;
2474  }
2475 
2476  bool IsValid(){if(objh.objp != NULL) return objh.IsValid(); else return (pi != NULL);}
2477 };
2478 
2479 ade_obj<physics_info_h> l_Physics("physics", "Physics handle");
2480 
2481 ADE_VIRTVAR(AfterburnerAccelerationTime, l_Physics, "number", "Afterburner acceleration time", "number", "Afterburner acceleration time, or 0 if handle is invalid")
2482 {
2483  physics_info_h *pih;
2484  float f = 0.0f;
2485  if(!ade_get_args(L, "o|f", l_Physics.GetPtr(&pih), &f))
2486  return ade_set_error(L, "f", 0.0f);
2487 
2488  if(!pih->IsValid())
2489  return ade_set_error(L, "f", 0.0f);
2490 
2491  if(ADE_SETTING_VAR) {
2493  }
2494 
2496 }
2497 
2498 ADE_VIRTVAR(AfterburnerVelocityMax, l_Physics, "vector", "Afterburner max velocity (Local vector)", "vector", "Afterburner max velocity, or null vector if handle is invalid")
2499 {
2500  physics_info_h *pih;
2501  vec3d *v3=NULL;
2502  if(!ade_get_args(L, "o|o", l_Physics.GetPtr(&pih), l_Vector.GetPtr(&v3)))
2503  return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
2504 
2505  if(!pih->IsValid())
2506  return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
2507 
2508  if(ADE_SETTING_VAR && v3 != NULL) {
2509  pih->pi->afterburner_max_vel = *v3;
2510  }
2511 
2512  return ade_set_args(L, "o", l_Vector.Set(pih->pi->afterburner_max_vel));
2513 }
2514 
2515 ADE_VIRTVAR(BankingConstant, l_Physics, "number", "Banking constant", "number", "Banking constant, or 0 if handle is invalid")
2516 {
2517  physics_info_h *pih;
2518  float f = 0.0f;
2519  if(!ade_get_args(L, "o|f", l_Physics.GetPtr(&pih), &f))
2520  return ade_set_error(L, "f", 0.0f);
2521 
2522  if(!pih->IsValid())
2523  return ade_set_error(L, "f", 0.0f);
2524 
2525  if(ADE_SETTING_VAR) {
2526  pih->pi->delta_bank_const = f;
2527  }
2528 
2529  return ade_set_args(L, "f", pih->pi->delta_bank_const);
2530 }
2531 
2532 ADE_VIRTVAR(ForwardAccelerationTime, l_Physics, "number", "Forward acceleration time", "number", "Forward acceleration time, or 0 if handle is invalid")
2533 {
2534  physics_info_h *pih;
2535  float f = 0.0f;
2536  if(!ade_get_args(L, "o|f", l_Physics.GetPtr(&pih), &f))
2537  return ade_set_error(L, "f", 0.0f);
2538 
2539  if(!pih->IsValid())
2540  return ade_set_error(L, "f", 0.0f);
2541 
2542  if(ADE_SETTING_VAR) {
2543  pih->pi->forward_accel_time_const = f;
2544  }
2545 
2546  return ade_set_args(L, "f", pih->pi->forward_accel_time_const);
2547 }
2548 
2549 ADE_VIRTVAR(ForwardDecelerationTime, l_Physics, "number", "Forward deceleration time", "number", "Forward decleration time, or 0 if handle is invalid")
2550 {
2551  physics_info_h *pih;
2552  float f = 0.0f;
2553  if(!ade_get_args(L, "o|f", l_Physics.GetPtr(&pih), &f))
2554  return ade_set_error(L, "f", 0.0f);
2555 
2556  if(!pih->IsValid())
2557  return ade_set_error(L, "f", 0.0f);
2558 
2559  if(ADE_SETTING_VAR) {
2560  pih->pi->forward_decel_time_const = f;
2561  }
2562 
2563  return ade_set_args(L, "f", pih->pi->forward_decel_time_const);
2564 }
2565 
2566 ADE_VIRTVAR(ForwardThrust, l_Physics, "number", "Forward thrust amount (0-1), used primarily for thruster graphics", "number", "Forward thrust, or 0 if handle is invalid")
2567 {
2568  physics_info_h *pih;
2569  float f = 0.0f;
2570  if(!ade_get_args(L, "o|f", l_Physics.GetPtr(&pih), &f))
2571  return ade_set_error(L, "f", 0.0f);
2572 
2573  if(!pih->IsValid())
2574  return ade_set_error(L, "f", 0.0f);
2575 
2576  if(ADE_SETTING_VAR) {
2577  pih->pi->forward_thrust = f;
2578  }
2579 
2580  return ade_set_args(L, "f", pih->pi->forward_thrust);
2581 }
2582 
2583 ADE_VIRTVAR(Mass, l_Physics, "number", "Object mass", "number", "Object mass, or 0 if handle is invalid")
2584 {
2585  physics_info_h *pih;
2586  float f = 0.0f;
2587  if(!ade_get_args(L, "o|f", l_Physics.GetPtr(&pih), &f))
2588  return ade_set_error(L, "f", 0.0f);
2589 
2590  if(!pih->IsValid())
2591  return ade_set_error(L, "f", 0.0f);
2592 
2593  if(ADE_SETTING_VAR) {
2594  pih->pi->mass = f;
2595  }
2596 
2597  return ade_set_args(L, "f", pih->pi->mass);
2598 }
2599 
2600 ADE_VIRTVAR(RotationalVelocity, l_Physics, "vector", "Rotational velocity (Local vector)", "vector", "Rotational velocity, or null vector if handle is invalid")
2601 {
2602  physics_info_h *pih;
2603  vec3d *v3=NULL;
2604  if(!ade_get_args(L, "o|o", l_Physics.GetPtr(&pih), l_Vector.GetPtr(&v3)))
2605  return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
2606 
2607  if(!pih->IsValid())
2608  return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
2609 
2610  if(ADE_SETTING_VAR && v3 != NULL) {
2611  pih->pi->rotvel = *v3;
2612  }
2613 
2614  return ade_set_args(L, "o", l_Vector.Set(pih->pi->rotvel));
2615 }
2616 
2617 ADE_VIRTVAR(RotationalVelocityDamping, l_Physics, "number", "Rotational damping, ie derivative of rotational speed", "number", "Rotational damping, or 0 if handle is invalid")
2618 {
2619  physics_info_h *pih;
2620  float f = 0.0f;
2621  if(!ade_get_args(L, "o|f", l_Physics.GetPtr(&pih), &f))
2622  return ade_set_error(L, "f", 0.0f);
2623 
2624  if(!pih->IsValid())
2625  return ade_set_error(L, "f", 0.0f);
2626 
2627  if(ADE_SETTING_VAR) {
2628  pih->pi->rotdamp = f;
2629  }
2630 
2631  return ade_set_args(L, "f", pih->pi->rotdamp);
2632 }
2633 
2634 ADE_VIRTVAR(RotationalVelocityDesired, l_Physics, "vector", "Desired rotational velocity", "vector", "Desired rotational velocity, or null vector if handle is invalid")
2635 {
2636  physics_info_h *pih;
2637  vec3d *v3=NULL;
2638  if(!ade_get_args(L, "o|o", l_Physics.GetPtr(&pih), l_Vector.GetPtr(&v3)))
2639  return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
2640 
2641  if(!pih->IsValid())
2642  return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
2643 
2644  if(ADE_SETTING_VAR && v3 != NULL) {
2645  pih->pi->desired_rotvel = *v3;
2646  }
2647 
2648  return ade_set_args(L, "o", l_Vector.Set(pih->pi->desired_rotvel));
2649 }
2650 
2651 ADE_VIRTVAR(RotationalVelocityMax, l_Physics, "vector", "Maximum rotational velocity (Local vector)", "vector", "Maximum rotational velocity, or null vector if handle is invalid")
2652 {
2653  physics_info_h *pih;
2654  vec3d *v3=NULL;
2655  if(!ade_get_args(L, "o|o", l_Physics.GetPtr(&pih), l_Vector.GetPtr(&v3)))
2656  return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
2657 
2658  if(!pih->IsValid())
2659  return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
2660 
2661  if(ADE_SETTING_VAR && v3 != NULL) {
2662  pih->pi->max_rotvel = *v3;
2663  }
2664 
2665  return ade_set_args(L, "o", l_Vector.Set(pih->pi->max_rotvel));
2666 }
2667 
2668 ADE_VIRTVAR(ShockwaveShakeAmplitude, l_Physics, "number", "How much shaking from shockwaves is applied to object", "number", "Shockwave shake amplitude, or 0 if handle is invalid")
2669 {
2670  physics_info_h *pih;
2671  float f = 0.0f;
2672  if(!ade_get_args(L, "o|f", l_Physics.GetPtr(&pih), &f))
2673  return ade_set_error(L, "f", 0.0f);
2674 
2675  if(!pih->IsValid())
2676  return ade_set_error(L, "f", 0.0f);
2677 
2678  if(ADE_SETTING_VAR) {
2679  pih->pi->shockwave_shake_amp = f;
2680  }
2681 
2682  return ade_set_args(L, "f", pih->pi->shockwave_shake_amp);
2683 }
2684 
2685 ADE_VIRTVAR(SideThrust, l_Physics, "number", "Side thrust amount (0-1), used primarily for thruster graphics", "number", "Side thrust amount, or 0 if handle is invalid")
2686 {
2687  physics_info_h *pih;
2688  float f = 0.0f;
2689  if(!ade_get_args(L, "o|f", l_Physics.GetPtr(&pih), &f))
2690  return ade_set_error(L, "f", 0.0f);
2691 
2692  if(!pih->IsValid())
2693  return ade_set_error(L, "f", 0.0f);
2694 
2695  if(ADE_SETTING_VAR) {
2696  pih->pi->side_thrust = f;
2697  }
2698 
2699  return ade_set_args(L, "f", pih->pi->side_thrust);
2700 }
2701 
2702 ADE_VIRTVAR(SlideAccelerationTime, l_Physics, "number", "Time to accelerate to maximum slide velocity", "number", "Sliding acceleration time, or 0 if handle is invalid")
2703 {
2704  physics_info_h *pih;
2705  float f = 0.0f;
2706  if(!ade_get_args(L, "o|f", l_Physics.GetPtr(&pih), &f))
2707  return ade_set_error(L, "f", 0.0f);
2708 
2709  if(!pih->IsValid())
2710  return ade_set_error(L, "f", 0.0f);
2711 
2712  if(ADE_SETTING_VAR) {
2713  pih->pi->slide_accel_time_const = f;
2714  }
2715 
2716  return ade_set_args(L, "f", pih->pi->slide_accel_time_const);
2717 }
2718 
2719 ADE_VIRTVAR(SlideDecelerationTime, l_Physics, "number", "Time to decelerate from maximum slide speed", "number", "Sliding deceleration time, or 0 if handle is invalid")
2720 {
2721  physics_info_h *pih;
2722  float f = 0.0f;
2723  if(!ade_get_args(L, "o|f", l_Physics.GetPtr(&pih), &f))
2724  return ade_set_error(L, "f", 0.0f);
2725 
2726  if(!pih->IsValid())
2727  return ade_set_error(L, "f", 0.0f);
2728 
2729  if(ADE_SETTING_VAR) {
2730  pih->pi->slide_decel_time_const = f;
2731  }
2732 
2733  return ade_set_args(L, "f", pih->pi->slide_decel_time_const);
2734 }
2735 
2736 ADE_VIRTVAR(Velocity, l_Physics, "vector", "Object world velocity (World vector)", "vector", "Object velocity, or null vector if handle is invalid")
2737 {
2738  physics_info_h *pih;
2739  vec3d *v3=NULL;
2740  if(!ade_get_args(L, "o|o", l_Physics.GetPtr(&pih), l_Vector.GetPtr(&v3)))
2741  return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
2742 
2743  if(!pih->IsValid())
2744  return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
2745 
2746  if(ADE_SETTING_VAR && v3 != NULL) {
2747  pih->pi->vel = *v3;
2748  }
2749 
2750  return ade_set_args(L, "o", l_Vector.Set(pih->pi->vel));
2751 }
2752 
2753 ADE_VIRTVAR(VelocityDesired, l_Physics, "vector", "Desired velocity (World vector)", "vector", "Desired velocity, or null vector if handle is invalid")
2754 {
2755  physics_info_h *pih;
2756  vec3d *v3=NULL;
2757  if(!ade_get_args(L, "o|o", l_Physics.GetPtr(&pih), l_Vector.GetPtr(&v3)))
2758  return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
2759 
2760  if(!pih->IsValid())
2761  return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
2762 
2763  if(ADE_SETTING_VAR && v3 != NULL) {
2764  pih->pi->desired_vel = *v3;
2765  }
2766 
2767  return ade_set_args(L, "o", l_Vector.Set(pih->pi->desired_vel));
2768 }
2769 
2770 ADE_VIRTVAR(VelocityMax, l_Physics, "vector", "Object max local velocity (Local vector)", "vector", "Maximum velocity, or null vector if handle is invalid")
2771 {
2772  physics_info_h *pih;
2773  vec3d *v3=NULL;
2774  if(!ade_get_args(L, "o|o", l_Physics.GetPtr(&pih), l_Vector.GetPtr(&v3)))
2775  return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
2776 
2777  if(!pih->IsValid())
2778  return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
2779 
2780  if(ADE_SETTING_VAR && v3 != NULL) {
2781  pih->pi->max_vel = *v3;
2782  }
2783 
2784  return ade_set_args(L, "o", l_Vector.Set(pih->pi->max_vel));
2785 }
2786 
2787 ADE_VIRTVAR(VerticalThrust, l_Physics, "number", "Vertical thrust amount (0-1), used primarily for thruster graphics", "number", "Vertical thrust amount, or 0 if handle is invalid")
2788 {
2789  physics_info_h *pih;
2790  float f = 0.0f;
2791  if(!ade_get_args(L, "o|f", l_Physics.GetPtr(&pih), &f))
2792  return ade_set_error(L, "f", 0.0f);
2793 
2794  if(!pih->IsValid())
2795  return ade_set_error(L, "f", 0.0f);
2796 
2797  if(ADE_SETTING_VAR) {
2798  pih->pi->vert_thrust = f;
2799  }
2800 
2801  return ade_set_args(L, "f", pih->pi->vert_thrust);
2802 }
2803 
2804 ADE_VIRTVAR(AfterburnerActive, l_Physics, "boolean", "Specifies if the afterburner is active or not", "boolean", "true if afterburner is active false otherwise")
2805 {
2806  physics_info_h *pih;
2807  bool set = false;
2808 
2809  if(!ade_get_args(L, "o|b", l_Physics.GetPtr(&pih), &set))
2810  return ade_set_error(L, "b", false);
2811 
2812  if(!pih->IsValid())
2813  return ade_set_error(L, "b", false);
2814 
2815  if (ADE_SETTING_VAR)
2816  {
2817  if(set)
2818  pih->pi->flags |= PF_AFTERBURNER_ON;
2819  else
2820  pih->pi->flags &= ~PF_AFTERBURNER_ON;
2821  }
2822 
2823  if (pih->pi->flags & PF_AFTERBURNER_ON)
2824  return ade_set_args(L, "b", true);
2825  else
2826  return ade_set_args(L, "b", false);
2827 }
2828 
2829 ADE_FUNC(isValid, l_Physics, NULL, "True if valid, false or nil if not", "boolean", "Detects whether handle is valid")
2830 {
2831  physics_info_h *pih;
2832  if(!ade_get_args(L, "o", l_Physics.GetPtr(&pih)))
2833  return ADE_RETURN_NIL;
2834 
2835  return ade_set_args(L, "b", pih->IsValid());
2836 }
2837 
2838 ADE_FUNC(getSpeed, l_Physics, NULL, "Gets total speed as of last frame", "number", "Total speed, or 0 if handle is invalid")
2839 {
2840  physics_info_h *pih;
2841  if(!ade_get_args(L, "o", l_Physics.GetPtr(&pih)))
2842  return ade_set_error(L, "f", 0.0f);
2843 
2844  if(!pih->IsValid())
2845  return ade_set_error(L, "f", 0.0f);
2846 
2847  return ade_set_args(L, "f", pih->pi->speed);
2848 }
2849 
2850 ADE_FUNC(getForwardSpeed, l_Physics, NULL, "Gets total speed in the ship's 'forward' direction as of last frame", "number", "Total forward speed, or 0 if handle is invalid")
2851 {
2852  physics_info_h *pih;
2853  if(!ade_get_args(L, "o", l_Physics.GetPtr(&pih)))
2854  return ade_set_error(L, "f", 0.0f);
2855 
2856  if(!pih->IsValid())
2857  return ade_set_error(L, "f", 0.0f);
2858 
2859  return ade_set_args(L, "f", pih->pi->fspeed);
2860 }
2861 
2862 // Nuke's afterburner function
2863 ADE_FUNC(isAfterburnerActive, l_Physics, NULL, "True if Afterburners are on, false or nil if not", "boolean", "Detects whether afterburner is active")
2864 {
2865  physics_info_h *pih;
2866  if(!ade_get_args(L, "o", l_Physics.GetPtr(&pih)))
2867  return ADE_RETURN_NIL;
2868 
2869  if(!pih->IsValid())
2870  return ade_set_error(L, "b", false);
2871 
2872  if (pih->pi->flags & PF_AFTERBURNER_ON)
2873  return ade_set_args(L, "b", true);
2874  else
2875  return ade_set_args(L, "b", false);
2876 }
2877 
2878 //nukes glide function
2879 ADE_FUNC(isGliding, l_Physics, NULL, "True if glide mode is on, false or nil if not", "boolean", "Detects if ship is gliding")
2880 {
2881  physics_info_h *pih;
2882  if(!ade_get_args(L, "o", l_Physics.GetPtr(&pih)))
2883  return ADE_RETURN_NIL;
2884 
2885  if(!pih->IsValid())
2886  return ade_set_error(L, "b", false);
2887 
2888  if (pih->pi->flags & (PF_GLIDING|PF_FORCE_GLIDE))
2889  return ade_set_args(L, "b", true);
2890  else
2891  return ade_set_args(L, "b", false);
2892 }
2893 
2894 ADE_FUNC(applyWhack, l_Physics, "vector Impulse, [ vector Position]", "Applies a whack to an object at a position (a local vector) based on impulse supplied (a world vector). If no position is supplied, an empty vector is used.", "boolean", "true if it succeeded, false otherwise")
2895  {
2896  object_h objh;
2897  physics_info_h *pih;
2898  vec3d *impulse;
2900 
2901  if (!ade_get_args(L, "oo|o", l_Physics.GetPtr(&pih), l_Vector.GetPtr(&impulse), l_Vector.GetPtr(&offset)))
2902  return ADE_RETURN_NIL;
2903 
2904  objh = pih->objh;
2905 
2906  physics_apply_whack(impulse, offset, pih->pi, &objh.objp->orient, pih->pi->mass);
2907 
2908  return ADE_RETURN_TRUE;
2909 
2910 }
2911 
2912 
2913 //**********HANDLE: sexpvariable
2915 {
2916  int idx;
2918 
2919  sexpvar_h(){idx=-1;variable_name[0]='\0';}
2920  sexpvar_h(int n_idx){idx = n_idx; strcpy_s(variable_name, Sexp_variables[n_idx].variable_name);}
2921  bool IsValid(){
2922  return (idx > -1
2923  && idx < MAX_SEXP_VARIABLES
2925  && !strcmp(Sexp_variables[idx].variable_name, variable_name));}
2926 };
2927 
2928 ade_obj<sexpvar_h> l_SEXPVariable("sexpvariable", "SEXP Variable handle");
2929 
2930 ADE_VIRTVAR(Persistence, l_SEXPVariable, "enumeration", "SEXP Variable persistance, uses SEXPVAR_*_PERSISTENT enumerations", "enumeration", "SEXPVAR_*_PERSISTENT enumeration, or invalid numeration if handle is invalid")
2931 {
2932  sexpvar_h *svh = NULL;
2933  enum_h *type = NULL;
2934  if(!ade_get_args(L, "o|o", l_SEXPVariable.GetPtr(&svh), l_Enum.GetPtr(&type)))
2935  return ade_set_error(L, "o", l_Enum.Set(enum_h()));
2936 
2937  if(!svh->IsValid())
2938  return ade_set_error(L, "o", l_Enum.Set(enum_h()));
2939 
2940  sexp_variable *sv = &Sexp_variables[svh->idx];
2941 
2942  if(ADE_SETTING_VAR && type != NULL)
2943  {
2944  if(type->index == LE_SEXPVAR_PLAYER_PERSISTENT)
2945  {
2948  }
2949  else if(type->index == LE_SEXPVAR_CAMPAIGN_PERSISTENT)
2950  {
2953  }
2954  else if(type->index == LE_SEXPVAR_NOT_PERSISTENT)
2955  {
2958  }
2959  }
2960 
2961  enum_h ren;
2966  else
2968 
2969  return ade_set_args(L, "o", l_Enum.Set(ren));
2970 }
2971 
2972 ADE_VIRTVAR(Type, l_SEXPVariable, "enumeration", "SEXP Variable type, uses SEXPVAR_TYPE_* enumerations", "enumeration", "SEXPVAR_TYPE_* enumeration, or invalid numeration if handle is invalid")
2973 {
2974  sexpvar_h *svh = NULL;
2975  enum_h *type = NULL;
2976  if(!ade_get_args(L, "o|o", l_SEXPVariable.GetPtr(&svh), l_Enum.GetPtr(&type)))
2977  return ade_set_error(L, "o", l_Enum.Set(enum_h()));
2978 
2979  if(!svh->IsValid())
2980  return ade_set_error(L, "o", l_Enum.Set(enum_h()));
2981 
2982  sexp_variable *sv = &Sexp_variables[svh->idx];
2983 
2984  if(ADE_SETTING_VAR && type != NULL)
2985  {
2986  if(type->index == LE_SEXPVAR_TYPE_NUMBER)
2987  {
2988  sv->type &= ~(SEXP_VARIABLE_NUMBER);
2989  sv->type |= SEXP_VARIABLE_STRING;
2990  }
2991  else if(type->index == LE_SEXPVAR_TYPE_STRING)
2992  {
2993  sv->type |= SEXP_VARIABLE_NUMBER;
2994  sv->type &= ~(SEXP_VARIABLE_STRING);
2995  }
2996  }
2997 
2998  enum_h ren;
2999  if(sv->type & SEXP_VARIABLE_NUMBER)
3001  else if(sv->type & SEXP_VARIABLE_STRING)
3003 
3004  return ade_set_args(L, "o", l_Enum.Set(ren));
3005 }
3006 
3007 ADE_VIRTVAR(Value, l_SEXPVariable, "number/string", "SEXP variable value", "string", "SEXP variable contents, or nil if the variable is of an invalid type or the handle is invalid")
3008 {
3009  sexpvar_h *svh = NULL;
3010  char *newvalue = NULL;
3011  char number_as_str[TOKEN_LENGTH];
3012 
3013  if(lua_type(L, 2) == LUA_TNUMBER)
3014  {
3015  int newnumber = 0;
3016  if(!ade_get_args(L, "o|i", l_SEXPVariable.GetPtr(&svh), &newnumber))
3017  return ADE_RETURN_NIL;
3018 
3019  sprintf(number_as_str, "%d", newnumber);
3020  newvalue = number_as_str;
3021  }
3022  else
3023  {
3024  if(!ade_get_args(L, "o|s", l_SEXPVariable.GetPtr(&svh), &newvalue))
3025  return ADE_RETURN_NIL;
3026  }
3027 
3028  if(!svh->IsValid())
3029  return ADE_RETURN_NIL;
3030 
3031  sexp_variable *sv = &Sexp_variables[svh->idx];
3032 
3033  if(ADE_SETTING_VAR && newvalue)
3034  {
3035  sexp_modify_variable(newvalue, svh->idx, false);
3036  }
3037 
3038  if(sv->type & SEXP_VARIABLE_NUMBER)
3039  return ade_set_args(L, "i", atoi(sv->text));
3040  else if(sv->type & SEXP_VARIABLE_STRING)
3041  return ade_set_args(L, "s", sv->text);
3042  else
3043  return ADE_RETURN_NIL;
3044 }
3045 
3046 ADE_FUNC(__tostring, l_SEXPVariable, NULL, "Returns SEXP name", "string", "SEXP name, or empty string if handle is invalid")
3047 {
3048  sexpvar_h *svh = NULL;
3049  if(!ade_get_args(L, "o", l_SEXPVariable.GetPtr(&svh)))
3050  return ade_set_error(L, "s", "");
3051 
3052  if(!svh->IsValid())
3053  return ade_set_error(L, "s", "");
3054 
3055  return ade_set_args(L, "s", Sexp_variables[svh->idx].variable_name);
3056 }
3057 
3058 ADE_FUNC(isValid, l_SEXPVariable, NULL, "Detects whether handle is valid", "boolean", "true if valid, false if handle is invalid, nil if a syntax/type error occurs")
3059 {
3060  sexpvar_h *svh = NULL;
3061  if(!ade_get_args(L, "o", l_SEXPVariable.GetPtr(&svh)))
3062  return ADE_RETURN_NIL;
3063 
3064  if(!svh->IsValid())
3065  return ADE_RETURN_FALSE;
3066 
3067  return ADE_RETURN_TRUE;
3068 }
3069 
3070 ADE_FUNC(delete, l_SEXPVariable, NULL, "Deletes a SEXP Variable", "boolean", "True if successful, false if the handle is invalid")
3071 {
3072  sexpvar_h *svh = NULL;
3073  if(!ade_get_args(L, "o", l_SEXPVariable.GetPtr(&svh)))
3074  return ade_set_error(L, "b", false);
3075 
3076  if(!svh->IsValid())
3077  return ade_set_error(L, "b", false);
3078 
3079  sexp_variable_delete(svh->idx);
3080 
3081  return ADE_RETURN_TRUE;
3082 }
3083 
3084 //**********HANDLE: Shields
3085 ade_obj<object_h> l_Shields("shields", "Shields handle");
3086 
3087 ADE_FUNC(__len, l_Shields, NULL, "Number of shield segments", "number", "Number of shield segments or 0 if handle is invalid")
3088 {
3089  object_h *objh;
3090 
3091  if(!ade_get_args(L, "o", l_Shields.GetPtr(&objh)))
3092  return ade_set_error(L, "i", -1);
3093 
3094  if(!objh->IsValid())
3095  return ade_set_error(L, "i", -1);
3096 
3097  return ade_set_args(L, "i", objh->objp->n_quadrants);
3098 }
3099 
3100 ADE_INDEXER(l_Shields, "enumeration/number", "Gets or sets shield segment strength. Use \"SHIELD_*\" enumerations (for standard 4-quadrant shields) or index of a specific segment, or NONE for the entire shield", "number", "Segment/shield strength, or 0 if handle is invalid")
3101 {
3102  object_h *objh;
3103  float nval = -1.0f;
3104 
3105  object *objp = NULL;
3106  int qdx = -1;
3107 
3108  if(lua_isstring(L, 2))
3109  {
3110  char *qd = NULL;
3111  if(!ade_get_args(L, "os|f", l_Shields.GetPtr(&objh), &qd, &nval))
3112  return ade_set_error(L, "f", 0.0f);
3113 
3114  if(!objh->IsValid())
3115  return ade_set_error(L, "f", 0.0f);
3116 
3117  objp = objh->objp;
3118 
3119  //Which quadrant?
3120  int qdi;
3121  if(qd == NULL)
3122  qdx = -1;
3123  else if((qdi = atoi(qd)) > 0 && qdi <= objp->n_quadrants)
3124  qdx = qdi-1; //LUA->FS2
3125  else
3126  return ade_set_error(L, "f", 0.0f);
3127  } else {
3128  enum_h *qd = NULL;
3129  if(!ade_get_args(L, "oo|f", l_Shields.GetPtr(&objh), l_Enum.GetPtr(&qd), &nval))
3130  return 0;
3131 
3132  if(!objh->IsValid())
3133  return ade_set_error(L, "f", 0.0f);
3134 
3135  objp = objh->objp;
3136 
3137  switch(qd->index)
3138  {
3139  case LE_NONE:
3140  qdx = -1;
3141  break;
3142  case LE_SHIELD_FRONT:
3143  qdx = FRONT_QUAD;
3144  break;
3145  case LE_SHIELD_LEFT:
3146  qdx = LEFT_QUAD;
3147  break;
3148  case LE_SHIELD_RIGHT:
3149  qdx = RIGHT_QUAD;
3150  break;
3151  case LE_SHIELD_BACK:
3152  qdx = REAR_QUAD;
3153  break;
3154  default:
3155  return ade_set_error(L, "f", 0.0f);
3156  }
3157  }
3158 
3159  //Set/get all quadrants
3160  if(qdx == -1) {
3161  if(ADE_SETTING_VAR && nval >= 0.0f)
3162  shield_set_strength(objp, nval);
3163 
3164  return ade_set_args(L, "f", shield_get_strength(objp));
3165  }
3166 
3167  //Set one quadrant?
3168  if(ADE_SETTING_VAR && nval >= 0.0f)
3169  shield_set_quad(objp, qdx, nval);
3170 
3171  //Get one quadrant
3172  return ade_set_args(L, "f", shield_get_quad(objp, qdx));
3173 }
3174 
3175 //WMC - Not sure if I want this to be a variable. It'd make more sense
3176 //as a function, since it modifies all quadrant variables
3177 //WMC - Ehh, screw it.
3178 ADE_VIRTVAR(CombinedLeft, l_Shields, "number", "Total shield hitpoints left (for all segments combined)", "number", "Combined shield strength, or 0 if handle is invalid")
3179 {
3180  object_h *objh;
3181  float nval = -1.0f;
3182  if(!ade_get_args(L, "o|f", l_Shields.GetPtr(&objh), &nval))
3183  return ade_set_error(L, "f", 0.0f);
3184 
3185  if(!objh->IsValid())
3186  return ade_set_error(L, "f", 0.0f);
3187 
3188  if(ADE_SETTING_VAR && nval >= 0.0f) {
3189  shield_set_strength(objh->objp, nval);
3190  }
3191 
3192  return ade_set_args(L, "f", shield_get_strength(objh->objp));
3193 }
3194 
3195 ADE_VIRTVAR(CombinedMax, l_Shields, "number", "Maximum shield hitpoints (for all segments combined)", "number", "Combined maximum shield strength, or 0 if handle is invalid")
3196 {
3197  object_h *objh;
3198  float nval = -1.0f;
3199  if(!ade_get_args(L, "o|f", l_Shields.GetPtr(&objh), &nval))
3200  return 0;
3201 
3202  if(!objh->IsValid())
3203  return ade_set_error(L, "f", 0.0f);
3204 
3205  if(ADE_SETTING_VAR && nval >= 0.0f) {
3206  shield_set_max_strength(objh->objp, nval);
3207  }
3208 
3209  return ade_set_args(L, "f", shield_get_max_strength(objh->objp));
3210 }
3211 
3212 ADE_FUNC(isValid, l_Shields, NULL, "Detects whether handle is valid", "boolean", "true if valid, false if handle is invalid, nil if a syntax/type error occurs")
3213 {
3214  object_h *oh;
3215  if(!ade_get_args(L, "o", l_Shields.GetPtr(&oh)))
3216  return ADE_RETURN_NIL;
3217 
3218  return ade_set_args(L, "b", oh->IsValid());
3219 }
3220 
3221 //**********HANDLE: Shiptype
3222 ade_obj<int> l_Shiptype("shiptype", "Ship type handle");
3223 extern int Species_initted;
3224 
3225 ADE_VIRTVAR(Name, l_Shiptype, "string", "Ship type name", "string", "Ship type name, or empty string if handle is invalid")
3226 {
3227  if(!Species_initted)
3228  return ade_set_error(L, "s", "");
3229 
3230  char *s = NULL;
3231  int idx;
3232  if(!ade_get_args(L, "o|s", l_Shiptype.Get(&idx), &s))
3233  return ade_set_error(L, "s", "");
3234 
3235  if(idx < 0 || idx >= (int)Ship_types.size())
3236  return ade_set_error(L, "s", "");
3237 
3238  if(ADE_SETTING_VAR && s != NULL) {
3239  strncpy(Ship_types[idx].name, s, sizeof(Ship_types[idx].name)-1);
3240  }
3241 
3242  return ade_set_args(L, "s", Ship_types[idx].name);
3243 }
3244 
3245 ADE_FUNC(isValid, l_Shiptype, NULL, "Detects whether handle is valid", "boolean", "true if valid, false if handle is invalid, nil if a syntax/type error occurs")
3246 {
3247  int idx;
3248  if(!ade_get_args(L, "o", l_Shiptype.Get(&idx)))
3249  return ADE_RETURN_NIL;
3250 
3251  if(idx < 0 || idx >= (int)Ship_types.size())
3252  return ADE_RETURN_FALSE;
3253 
3254  return ADE_RETURN_TRUE;
3255 }
3256 
3257 //**********HANDLE: Species
3258 ade_obj<int> l_Species("species", "Species handle");
3259 extern int Species_initted;
3260 
3261 ADE_VIRTVAR(Name, l_Species, "string", "Species name", "string", "Species name, or empty string if handle is invalid")
3262 {
3263  if(!Species_initted)
3264  return ade_set_error(L, "s", "");
3265 
3266  char *s = NULL;
3267  int idx;
3268  if(!ade_get_args(L, "o|s", l_Species.Get(&idx), &s))
3269  return ade_set_error(L, "s", "");
3270 
3271  if(idx < 0 || idx >= (int)Species_info.size())
3272  return ade_set_error(L, "s", "");
3273 
3274  if(ADE_SETTING_VAR && s != NULL) {
3275  strncpy(Species_info[idx].species_name, s, sizeof(Species_info[idx].species_name)-1);
3276  }
3277 
3278  return ade_set_args(L, "s", Species_info[idx].species_name);
3279 }
3280 
3281 ADE_FUNC(isValid, l_Species, NULL, "Detects whether handle is valid", "boolean", "true if valid, false if handle is invalid, nil if a syntax/type error occurs")
3282 {
3283  int idx;
3284  if(!ade_get_args(L, "o", l_Species.Get(&idx)))
3285  return ADE_RETURN_NIL;
3286 
3287  if(idx < 0 || idx >= (int)Species_info.size())
3288  return ADE_RETURN_FALSE;
3289 
3290  return ADE_RETURN_TRUE;
3291 }
3292 
3293 //**********HANDLE: Team
3294 ade_obj<int> l_Team("team", "Team handle");
3295 
3296 ADE_FUNC(__eq, l_Team, "team, team", "Checks whether two teams are the same team", "boolean", "true if equal")
3297 {
3298  int t1, t2;
3299  if(!ade_get_args(L, "oo", l_Team.Get(&t1), l_Team.Get(&t2)))
3300  return ADE_RETURN_FALSE;
3301 
3302  return ade_set_args(L, "b", (t1 == t2));
3303 }
3304 
3305 ADE_VIRTVAR(Name, l_Team, "string", "Team name", "string", "Team name, or empty string if handle is invalid")
3306 {
3307  int tdx=-1;
3308  char *s=NULL;
3309  if(!ade_get_args(L, "o|s", l_Team.Get(&tdx), &s))
3310  return ade_set_error(L, "s", "");
3311 
3312  if(tdx < 0 || tdx > Num_iffs)
3313  return ade_set_error(L, "s", "");
3314 
3315  if(ADE_SETTING_VAR && s != NULL) {
3316  strncpy(Iff_info[tdx].iff_name, s, NAME_LENGTH-1);
3317  }
3318 
3319  return ade_set_args(L, "s", Iff_info[tdx].iff_name);
3320 }
3321 
3322 ADE_FUNC(getColor, l_Team, NULL, "Gets the IFF color of the specified Team", "number, number, number", "rgb color for the specified team or nil if invalid") {
3323  int idx;
3324  int r,g,b;
3325  if(!ade_get_args(L, "o", l_Team.Get(&idx)))
3326  return ADE_RETURN_NIL;
3327 
3328  if(idx < 0 || idx >= Num_iffs)
3329  return ADE_RETURN_NIL;
3330 
3331  color* col = iff_get_color_by_team(idx, 0, 0);
3332 
3333  r = col->red;
3334  g = col->green;
3335  b = col->blue;
3336 
3337  return ade_set_args(L, "iii", r, g, b);
3338 }
3339 
3340 ADE_FUNC(isValid, l_Team, NULL, "Detects whether handle is valid", "boolean", "true if valid, false if handle is invalid, nil if a syntax/type error occurs")
3341 {
3342  int idx;
3343  if(!ade_get_args(L, "o", l_Team.Get(&idx)))
3344  return ADE_RETURN_NIL;
3345 
3346  if(idx < 0 || idx >= Num_iffs)
3347  return ADE_RETURN_FALSE;
3348 
3349  return ADE_RETURN_TRUE;
3350 }
3351 
3352 //**********HANDLE: Texture
3353 ade_obj<int> l_Texture("texture", "Texture handle");
3354 //WMC - int should NEVER EVER be an invalid handle. Return Nil instead. Nil FTW.
3355 
3356 static float lua_Opacity = 1.0f;
3357 static int lua_Opacity_type = GR_ALPHABLEND_NONE;
3358 
3359 ADE_FUNC(__gc, l_Texture, NULL, "Auto-deletes texture", NULL, NULL)
3360 {
3361  int idx;
3362 
3363  if(!ade_get_args(L, "o", l_Texture.Get(&idx)))
3364  return ADE_RETURN_NIL;
3365 
3366  // Note: due to some unknown reason, in some circumstances this function
3367  // might get called even for handles to bitmaps which are actually still in
3368  // use, and in order to prevent that we want to double-check the load count
3369  // here before unloading the bitmap. -zookeeper
3370  if(idx > -1 && bm_is_valid(idx) && bm_bitmaps[bm_get_cache_slot(idx, 0)].load_count < 1)
3371  bm_release(idx);
3372 
3373  return ADE_RETURN_NIL;
3374 }
3375 
3376 ADE_FUNC(__eq, l_Texture, "texture, texture", "Checks if two texture handles refer to the same texture", "boolean", "True if textures are equal")
3377 {
3378  int idx,idx2;
3379 
3380  if(!ade_get_args(L, "oo", l_Texture.Get(&idx), l_Texture.Get(&idx2)))
3381  return ADE_RETURN_NIL;
3382 
3383  if(idx == idx2)
3384  return ADE_RETURN_TRUE;
3385 
3386  return ADE_RETURN_FALSE;
3387 }
3388 
3390  "Returns texture handle to specified frame number in current texture's animation."
3391  "This means that [1] will always return the first frame in an animation, no matter what frame an animation is."
3392  "You cannot change a texture animation frame.",
3393  "texture",
3394  "Texture handle, or invalid texture handle if index is invalid")
3395 {
3396  int idx;
3397  int frame=-1;
3398  int newframe=-1; //WMC - Ignore for now
3399  if(!ade_get_args(L, "oi|i", l_Texture.Get(&idx), &frame, &newframe))
3400  return ade_set_error(L, "o", l_Texture.Set(-1));
3401 
3402  if(frame < 1)
3403  return ade_set_error(L, "o", l_Texture.Set(-1));
3404 
3405  //Get me some info
3406  int num=-1;
3407  int first=-1;
3408  first = bm_get_info(idx, NULL, NULL, NULL, &num);
3409 
3410  //Check it's a valid one
3411  if(first < 0 || frame > num)
3412  return ade_set_error(L, "o", l_Texture.Set(-1));
3413 
3414  frame--; //Lua->FS2
3415 
3416  //Get actual texture handle
3417  frame = first + frame;
3418 
3419  return ade_set_args(L, "o", l_Texture.Set(frame));
3420 }
3421 
3422 ADE_FUNC(isValid, l_Texture, NULL, "Detects whether handle is valid", "boolean", "true if valid, false if handle is invalid, nil if a syntax/type error occurs")
3423 {
3424  int idx;
3425  if(!ade_get_args(L, "o", l_Texture.Get(&idx)))
3426  return ADE_RETURN_NIL;
3427 
3428  return ade_set_args(L, "b", bm_is_valid(idx));
3429 }
3430 
3431 ADE_FUNC(unload, l_Texture, NULL, "Unloads a texture from memory", NULL, NULL)
3432 {
3433  int *idx;
3434 
3435  if(!ade_get_args(L, "o", l_Texture.GetPtr(&idx)))
3436  return ADE_RETURN_NIL;
3437 
3438  if(!bm_is_valid(*idx))
3439  return ADE_RETURN_NIL;
3440 
3441  bm_release(*idx);
3442 
3443  //WMC - invalidate this handle
3444  *idx = -1;
3445 
3446  return ADE_RETURN_NIL;
3447 }
3448 
3449 ADE_FUNC(getFilename, l_Texture, NULL, "Returns filename for texture", "string", "Filename, or empty string if handle is invalid")
3450 {
3451  int idx;
3452  if(!ade_get_args(L, "o", l_Texture.Get(&idx)))
3453  return ade_set_error(L, "s", "");
3454 
3455  if(!bm_is_valid(idx))
3456  return ade_set_error(L, "s", "");
3457 
3458  return ade_set_args(L, "s", bm_get_filename(idx));
3459 }
3460 
3461 ADE_FUNC(getWidth, l_Texture, NULL, "Gets texture width", "number", "Texture width, or 0 if handle is invalid")
3462 {
3463  int idx;
3464  if(!ade_get_args(L, "o", l_Texture.Get(&idx)))
3465  return ade_set_error(L, "i", 0);
3466 
3467  if(!bm_is_valid(idx))
3468  return ade_set_error(L, "i", 0);
3469 
3470  int w = -1;
3471 
3472  if(bm_get_info(idx, &w) < 0)
3473  return ade_set_error(L, "i", 0);
3474 
3475  return ade_set_args(L, "i", w);
3476 }
3477 
3478 ADE_FUNC(getHeight, l_Texture, NULL, "Gets texture height", "number", "Texture height, or 0 if handle is invalid")
3479 {
3480  int idx;
3481  if(!ade_get_args(L, "o", l_Texture.Get(&idx)))
3482  return ade_set_error(L, "i", 0);
3483 
3484  if(!bm_is_valid(idx))
3485  return ade_set_error(L, "i", 0);
3486 
3487  int h=-1;
3488 
3489  if(bm_get_info(idx, NULL, &h) < 0)
3490  return ade_set_error(L, "i", 0);
3491 
3492  return ade_set_args(L, "i", h);
3493 }
3494 
3495 ADE_FUNC(getFPS, l_Texture, NULL,"Gets frames-per-second of texture", "number", "Texture FPS, or 0 if handle is invalid")
3496 {
3497  int idx;
3498  if(!ade_get_args(L, "o", l_Texture.Get(&idx)))
3499  return ade_set_error(L, "i", 0);
3500 
3501  if(!bm_is_valid(idx))
3502  return ade_set_error(L, "i", 0);
3503 
3504  int fps=-1;
3505 
3506  if(bm_get_info(idx, NULL, NULL, NULL, NULL, &fps) < 0)
3507  return ade_set_error(L, "i", 0);
3508 
3509  return ade_set_args(L, "i", fps);
3510 }
3511 
3512 ADE_FUNC(getFramesLeft, l_Texture, NULL, "Gets number of frames left, from handle's position in animation", "number", "Frames left, or 0 if handle is invalid")
3513 {
3514  int idx;
3515  if(!ade_get_args(L, "o", l_Texture.Get(&idx)))
3516  return ADE_RETURN_NIL;
3517 
3518  if(!bm_is_valid(idx))
3519  return ADE_RETURN_NIL;
3520 
3521  int num=-1;
3522 
3523  if(bm_get_info(idx, NULL, NULL, NULL, &num) < 0)
3524  return ade_set_error(L, "i", 0);
3525 
3526  return ade_set_args(L, "i", num);
3527 }
3528 
3529 //**********OBJECT: vector
3530 //WMC - see matrix for ade_obj def
3531 
3532 ADE_INDEXER(l_Vector, "x,y,z or 1-3", "Vector component", "number", "Value at index, or 0 if vector handle is invalid")
3533 {
3534  vec3d *v3;
3535  char *s = NULL;
3536  float newval = 0.0f;
3537  int numargs = ade_get_args(L, "os|f", l_Vector.GetPtr(&v3), &s, &newval);
3538 
3539  if(!numargs || s[1] != '\0')
3540  return ade_set_error(L, "f", 0.0f);
3541 
3542  int idx=-1;
3543  if(s[0]=='x' || s[0] == '1')
3544  idx = 0;
3545  else if(s[0]=='y' || s[0] == '2')
3546  idx = 1;
3547  else if(s[0]=='z' || s[0] == '3')
3548  idx = 2;
3549 
3550  if(idx < 0 || idx > 3)
3551  return ade_set_error(L, "f", 0.0f);
3552 
3553  if(ADE_SETTING_VAR) {
3554  v3->a1d[idx] = newval;
3555  }
3556 
3557  return ade_set_args(L, "f", v3->a1d[idx]);
3558 }
3559 
3560 ADE_FUNC(__add, l_Vector, "number/vector", "Adds vector by another vector, or adds all axes by value", "vector", "Final vector, or null vector if error occurs")
3561 {
3562  vec3d v3 = vmd_zero_vector;
3563  if(lua_isnumber(L, 1) || lua_isnumber(L, 2))
3564  {
3565  float f;
3566  if((lua_isnumber(L, 1) && ade_get_args(L, "fo", &f, l_Vector.Get(&v3)))
3567  || (lua_isnumber(L, 2) && ade_get_args(L, "of", l_Vector.Get(&v3), &f)))
3568  {
3569  v3.xyz.x += f;
3570  v3.xyz.y += f;
3571  v3.xyz.z += f;
3572  }
3573  }
3574  else
3575  {
3576  vec3d v3b;
3577  //WMC - doesn't really matter which is which
3578  if(ade_get_args(L, "oo", l_Vector.Get(&v3), l_Vector.Get(&v3b)))
3579  {
3580  vm_vec_add2(&v3, &v3b);
3581  }
3582  }
3583  return ade_set_args(L, "o", l_Vector.Set(v3));
3584 }
3585 
3586 ADE_FUNC(__sub, l_Vector, "number/vector", "Subtracts vector from another vector, or subtracts all axes by value", "vector", "Final vector, or null vector if error occurs")
3587 {
3588  vec3d v3 = vmd_zero_vector;
3589  if(lua_isnumber(L, 1) || lua_isnumber(L, 2))
3590  {
3591  float f;
3592  if((lua_isnumber(L, 1) && ade_get_args(L, "fo", &f, l_Vector.Get(&v3)))
3593  || (lua_isnumber(L, 2) && ade_get_args(L, "of", l_Vector.Get(&v3), &f)))
3594  {
3595  v3.xyz.x += f;
3596  v3.xyz.y += f;
3597  v3.xyz.z += f;
3598  }
3599  }
3600  else
3601  {
3602  vec3d v3b;
3603  //WMC - doesn't really matter which is which
3604  if(ade_get_args(L, "oo", l_Vector.Get(&v3), l_Vector.Get(&v3b)))
3605  {
3606  vm_vec_sub2(&v3, &v3b);
3607  }
3608  }
3609 
3610  return ade_set_args(L, "o", l_Vector.Set(v3));
3611 }
3612 
3613 ADE_FUNC(__mul, l_Vector, "number/vector", "Scales vector object (Multiplies all axes by number), or multiplies each axes by the other vector's axes.", "vector", "Final vector, or null vector if error occurs")
3614 {
3615  vec3d v3 = vmd_zero_vector;
3616  if(lua_isnumber(L, 1) || lua_isnumber(L, 2))
3617  {
3618  float f;
3619  if((lua_isnumber(L, 1) && ade_get_args(L, "fo", &f, l_Vector.Get(&v3)))
3620  || (lua_isnumber(L, 2) && ade_get_args(L, "of", l_Vector.Get(&v3), &f)))
3621  {
3622  vm_vec_scale(&v3, f);
3623  }
3624  }
3625  else
3626  {
3627  vec3d *v1 = NULL;
3628  vec3d *v2 = NULL;
3629  if(!ade_get_args(L, "oo", l_Vector.GetPtr(&v1), l_Vector.GetPtr(&v2)))
3630  return ade_set_args(L, "o", l_Vector.Set(vmd_zero_vector));
3631 
3632  v3.xyz.x = v1->xyz.x * v2->xyz.x;
3633  v3.xyz.y = v1->xyz.y * v2->xyz.y;
3634  v3.xyz.z = v1->xyz.z * v2->xyz.z;
3635  }
3636 
3637  return ade_set_args(L, "o", l_Vector.Set(v3));
3638 }
3639 
3640 ADE_FUNC(__div, l_Vector, "number/vector", "Scales vector object (Divide all axes by number), or divides each axes by the dividing vector's axes.", "vector", "Final vector, or null vector if error occurs")
3641 {
3642  vec3d v3 = vmd_zero_vector;
3643  if(lua_isnumber(L, 1) || lua_isnumber(L, 2))
3644  {
3645  float f;
3646  if((lua_isnumber(L, 1) && ade_get_args(L, "fo", &f, l_Vector.Get(&v3)))
3647  || (lua_isnumber(L, 2) && ade_get_args(L, "of", l_Vector.Get(&v3), &f)))
3648  {
3649  vm_vec_scale(&v3, 1.0f/f);
3650  }
3651  }
3652  else
3653  {
3654  vec3d *v1 = NULL;
3655  vec3d *v2 = NULL;
3656  if(!ade_get_args(L, "oo", l_Vector.GetPtr(&v1), l_Vector.GetPtr(&v2)))
3657  return ade_set_args(L, "o", l_Vector.Set(vmd_zero_vector));
3658 
3659  v3.xyz.x = v1->xyz.x / v2->xyz.x;
3660  v3.xyz.y = v1->xyz.y / v2->xyz.y;
3661  v3.xyz.z = v1->xyz.z / v2->xyz.z;
3662  }
3663 
3664  return ade_set_args(L, "o", l_Vector.Set(v3));
3665 }
3666 
3667 
3668 ADE_FUNC(__tostring, l_Vector, NULL, "Converts a vector to string with format \"(x,y,z)\"", "string", "Vector as string, or empty string if handle is invalid")
3669 {
3670  vec3d *v3;
3671  if(!ade_get_args(L, "o", l_Vector.GetPtr(&v3)))
3672  return ade_set_error(L, "s", "");
3673 
3674  char buf[128];
3675  sprintf(buf, "(%f,%f,%f)", v3->xyz.x, v3->xyz.y, v3->xyz.z);
3676 
3677  return ade_set_args(L, "s", buf);
3678 }
3679 
3680 ADE_FUNC(getOrientation, l_Vector, NULL,
3681  "Returns orientation object representing the direction of the vector. Does not require vector to be normalized.",
3682  "orientation",
3683  "Orientation object, or null orientation object if handle is invalid")
3684 {
3685  vec3d v3;
3686  if(!ade_get_args(L, "o", l_Vector.Get(&v3)))
3687  return ade_set_error(L, "o", l_Matrix.Set(matrix_h()));
3688 
3690 
3691  vm_vec_normalize_safe(&v3);
3692  vm_vector_2_matrix_norm(&mt, &v3);
3693  matrix_h mh(&mt);
3694 
3695  return ade_set_args(L, "o", l_Matrix.Set(mh));
3696 }
3697 
3698 ADE_FUNC(getMagnitude, l_Vector, NULL, "Returns the magnitude of a vector (Total regardless of direction)", "number", "Magnitude of vector, or 0 if handle is invalid")
3699 {
3700  vec3d *v3;
3701  if(!ade_get_args(L, "o", l_Vector.GetPtr(&v3)))
3702  return ade_set_error(L, "f", 0.0f);
3703 
3704  return ade_set_args(L, "f", vm_vec_mag(v3));
3705 }
3706 
3707 ADE_FUNC(getDistance, l_Vector, "Vector", "Distance", "number", "Returns distance from another vector")
3708 {
3709  vec3d *v3a, *v3b;
3710  if(!ade_get_args(L, "oo", l_Vector.GetPtr(&v3a), l_Vector.GetPtr(&v3b)))
3711  return ade_set_error(L, "f", 0.0f);
3712 
3713  return ade_set_args(L, "f",vm_vec_dist(v3a, v3b));
3714 }
3715 
3716 ADE_FUNC(getDotProduct, l_Vector, "vector OtherVector", "Returns dot product of vector object with vector argument", "number", "Dot product, or 0 if a handle is invalid")
3717 {
3718  vec3d *v3a, *v3b;
3719  if(!ade_get_args(L, "oo", l_Vector.GetPtr(&v3a), l_Vector.GetPtr(&v3b)))
3720  return ade_set_error(L, "f", 0.0f);
3721 
3722  return ade_set_args(L, "f", vm_vec_dot(v3a, v3b));
3723 }
3724 
3725 ADE_FUNC(getCrossProduct, l_Vector, "vector OtherVector", "Returns cross product of vector object with vector argument", "vector", "Cross product, or null vector if a handle is invalid")
3726 {
3727  vec3d *v3a, *v3b;
3728  if(!ade_get_args(L, "oo", l_Vector.GetPtr(&v3a), l_Vector.GetPtr(&v3b)))
3729  return ade_set_error(L, "o", l_Vector.Set(vmd_zero_vector));
3730 
3731  vec3d v3r;
3732  vm_vec_cross(&v3r, v3a, v3b);
3733 
3734  return ade_set_args(L, "o",l_Vector.Set(v3r));
3735 }
3736 
3737 ADE_FUNC(getScreenCoords, l_Vector, NULL, "Gets screen cordinates of a world vector", "number,number", "X (number), Y (number), or false if off-screen")
3738 {
3739  vec3d v3;
3740  if(!ade_get_args(L, "o", l_Vector.Get(&v3)))
3741  return ADE_RETURN_NIL;
3742 
3743  vertex vtx;
3744  bool do_g3 = G3_count < 1;
3745  if(do_g3)
3746  g3_start_frame(1);
3747 
3748  g3_rotate_vertex(&vtx,&v3);
3749  g3_project_vertex(&vtx);
3750 
3751  if(do_g3)
3752  g3_end_frame();
3753 
3754  if(vtx.flags & PF_OVERFLOW)
3755  return ADE_RETURN_FALSE;
3756 
3757  return ade_set_args(L, "ff", vtx.screen.xyw.x, vtx.screen.xyw.y);
3758 }
3759 
3760 ADE_FUNC(getNormalized, l_Vector, NULL, "Returns a normalized version of the vector", "vector", "Normalized Vector, or NIL if invalid")
3761 {
3762  vec3d v3;
3763  if(!ade_get_args(L, "o", l_Vector.Get(&v3)))
3764  return ADE_RETURN_NIL;
3765 
3766  vm_vec_normalize(&v3);
3767 
3768  return ade_set_args(L, "o", l_Vector.Set(v3));
3769 }
3770 
3771 //**********HANDLE: material
3772 static const int THT_INDEPENDENT = 0;
3773 static const int THT_OBJECT = 1;
3774 static const int THT_MODEL = 2;
3776 {
3777 protected:
3778  int type;
3781 
3782  texture_map *tmap; //Pointer to subsystem, or NULL for the hull
3783 
3784 public:
3786  type = THT_INDEPENDENT;
3787  tmap = NULL;
3788  }
3789 
3790  texture_map_h(object *objp, texture_map *n_tmap = NULL) {
3791  type = THT_OBJECT;
3792  obj = object_h(objp);
3793  tmap = n_tmap;
3794  }
3795 
3796  texture_map_h(int modelnum, texture_map *n_tmap = NULL) {
3797  type = THT_MODEL;
3798  mdl = model_h(modelnum);
3799  tmap = n_tmap;
3800  }
3801 
3802  texture_map_h(polymodel *n_model, texture_map *n_tmap = NULL) {
3803  type = THT_MODEL;
3804  mdl = model_h(n_model);
3805  tmap = n_tmap;
3806  }
3807 
3809  {
3810  if(!this->IsValid())
3811  return NULL;
3812 
3813  return tmap;
3814  }
3815 
3816  int GetSize()
3817  {
3818  if(!this->IsValid())
3819  return 0;
3820 
3821  switch(type)
3822  {
3823  case THT_MODEL:
3824  return mdl.Get()->n_textures;
3825  case THT_OBJECT:
3826  return 0; //Can't do this right now.
3827  default:
3828  return 0;
3829  }
3830  }
3831 
3832  bool IsValid() {
3833  if(tmap == NULL)
3834  return false;
3835 
3836  switch(type)
3837  {
3838  case THT_INDEPENDENT:
3839  return true;
3840  case THT_OBJECT:
3841  return obj.IsValid();
3842  case THT_MODEL:
3843  return mdl.IsValid();
3844  default:
3845  Error(LOCATION, "Bad type in texture_map_h; debug this.");
3846  return false;
3847  }
3848  }
3849 };
3850 ade_obj<texture_map_h> l_TextureMap("material", "Texture map, including diffuse, glow, and specular textures");
3851 
3852 ADE_VIRTVAR(BaseMap, l_TextureMap, "texture", "Base texture", "texture", "Base texture, or invalid texture handle if material handle is invalid")
3853 {
3854  texture_map_h *tmh = NULL;
3855  int new_tex = -1;
3856  if(!ade_get_args(L, "o|o", l_TextureMap.GetPtr(&tmh), l_Texture.Get(&new_tex)))
3857  return ade_set_error(L, "o", l_Texture.Set(-1));
3858 
3859  texture_map *tmap = tmh->Get();
3860  if(tmap == NULL)
3861  return ade_set_error(L, "o", l_Texture.Set(-1));
3862 
3863  if(ADE_SETTING_VAR && new_tex > -1) {
3864  tmap->textures[TM_BASE_TYPE].SetTexture(new_tex);
3865  }
3866 
3867  return ade_set_args(L, "o", l_Texture.Set(tmap->textures[TM_BASE_TYPE].GetTexture()));
3868 }
3869 
3870 ADE_VIRTVAR(GlowMap, l_TextureMap, "texture", "Glow texture", "texture", "Glow texture, or invalid texture handle if material handle is invalid")
3871 {
3872  texture_map_h *tmh = NULL;
3873  int new_tex = -1;
3874  if(!ade_get_args(L, "o|o", l_TextureMap.GetPtr(&tmh), l_Texture.Get(&new_tex)))
3875  return ade_set_error(L, "o", l_Texture.Set(-1));
3876 
3877  texture_map *tmap = tmh->Get();
3878  if(tmap == NULL)
3879  return ade_set_error(L, "o", l_Texture.Set(-1));
3880 
3881  if(ADE_SETTING_VAR && new_tex > -1) {
3882  tmap->textures[TM_GLOW_TYPE].SetTexture(new_tex);
3883  }
3884 
3885  return ade_set_args(L, "o", l_Texture.Set(tmap->textures[TM_GLOW_TYPE].GetTexture()));
3886 }
3887 
3888 ADE_VIRTVAR(SpecularMap, l_TextureMap, "texture", "Specular texture", "texture", "Texture handle, or invalid texture handle if material handle is invalid")
3889 {
3890  texture_map_h *tmh = NULL;
3891  int new_tex = -1;
3892  if(!ade_get_args(L, "o|o", l_TextureMap.GetPtr(&tmh), l_Texture.Get(&new_tex)))
3893  return ade_set_error(L, "o", l_Texture.Set(-1));
3894 
3895  texture_map *tmap = tmh->Get();
3896  if(tmap == NULL)
3897  return ade_set_error(L, "o", l_Texture.Set(-1));
3898 
3899  if(ADE_SETTING_VAR && new_tex > -1) {
3900  tmap->textures[TM_SPECULAR_TYPE].SetTexture(new_tex);
3901  }
3902 
3903  return ade_set_args(L, "o", l_Texture.Set(tmap->textures[TM_SPECULAR_TYPE].GetTexture()));
3904 }
3905 
3906 //**********HANDLE: Weaponclass
3907 ade_obj<int> l_Weaponclass("weaponclass", "Weapon class handle");
3908 
3909 ADE_FUNC(__tostring, l_Weaponclass, NULL, "Weapon class name", "string", "Weapon class name, or an empty string if handle is invalid")
3910 {
3911  int idx;
3912  char *s = NULL;
3913  if(!ade_get_args(L, "o|s", l_Weaponclass.Get(&idx), &s))
3914  return ade_set_error(L, "s", "");
3915 
3916  if(idx < 0 || idx >= Num_weapon_types)
3917  return ade_set_error(L, "s", "");
3918 
3919  return ade_set_args(L, "s", Weapon_info[idx].name);
3920 }
3921 
3922 ADE_FUNC(__eq, l_Weaponclass, "weaponclass, weaponclass", "Checks if the two classes are equal", "boolean", "true if equal false otherwise")
3923 {
3924  int idx1,idx2;
3925  if(!ade_get_args(L, "oo", l_Weaponclass.Get(&idx1), l_Weaponclass.Get(&idx2)))
3926  return ade_set_error(L, "b", false);
3927 
3928  if(idx1 < 0 || idx1 >= Num_weapon_types)
3929  return ade_set_error(L, "b", false);
3930 
3931  if(idx2 < 0 || idx2 >= Num_weapon_types)
3932  return ade_set_error(L, "b", false);
3933 
3934  return ade_set_args(L, "b", idx1 == idx2);
3935 }
3936 
3937 ADE_VIRTVAR(Name, l_Weaponclass, "string", "Weapon class name", "string", "Weapon class name, or empty string if handle is invalid")
3938 
3939 {
3940  int idx;
3941  char *s = NULL;
3942  if(!ade_get_args(L, "o|s", l_Weaponclass.Get(&idx), &s))
3943  return ade_set_error(L, "s", "");
3944 
3945  if(idx < 0 || idx >= Num_weapon_types)
3946  return ade_set_error(L, "s", "");
3947 
3948  if(ADE_SETTING_VAR && s != NULL) {
3949  strncpy(Weapon_info[idx].name, s, sizeof(Weapon_info[idx].name)-1);
3950  }
3951 
3952  return ade_set_args(L, "s", Weapon_info[idx].name);
3953 }
3954 
3955 ADE_VIRTVAR(Title, l_Weaponclass, "string", "Weapon class title", "string", "Weapon class title, or empty string if handle is invalid")
3956 {
3957  int idx;
3958  char *s = NULL;
3959  if(!ade_get_args(L, "o|s", l_Weaponclass.Get(&idx), &s))
3960  return ade_set_error(L, "s", "");
3961 
3962  if(idx < 0 || idx >= Num_weapon_types)
3963  return ade_set_error(L, "s", "");
3964 
3965  if(ADE_SETTING_VAR && s != NULL) {
3966  strncpy(Weapon_info[idx].title, s, sizeof(Weapon_info[idx].title)-1);
3967  }
3968 
3969  return ade_set_args(L, "s", Weapon_info[idx].title);
3970 }
3971 
3972 ADE_VIRTVAR(Description, l_Weaponclass, "string", "Weapon class description string", "string", "Description string, or empty string if handle is invalid")
3973 {
3974  int idx;
3975  char *s = NULL;
3976  if(!ade_get_args(L, "o|s", l_Weaponclass.Get(&idx), &s))
3977  return ade_set_error(L, "s", "");
3978 
3979  if(idx < 0 || idx >= Num_weapon_types)
3980  return ade_set_error(L, "s", "");
3981 
3982  weapon_info *wip = &Weapon_info[idx];
3983 
3984  if(ADE_SETTING_VAR) {
3985  vm_free(wip->desc);
3986  if(s != NULL) {
3987  wip->desc = (char*)vm_malloc(strlen(s)+1);
3988  strcpy(wip->desc, s);
3989  } else {
3990  wip->desc = NULL;
3991  }
3992  }
3993 
3994  if(wip->desc != NULL)
3995  return ade_set_args(L, "s", wip->desc);
3996  else
3997  return ade_set_args(L, "s", "");
3998 }
3999 
4000 ADE_VIRTVAR(TechTitle, l_Weaponclass, "string", "Weapon class tech title", "string", "Tech title, or empty string if handle is invalid")
4001 {
4002  int idx;
4003  char *s = NULL;
4004  if(!ade_get_args(L, "o|s", l_Weaponclass.Get(&idx), &s))
4005  return ade_set_error(L, "s", "");
4006 
4007  if(idx < 0 || idx >= Num_weapon_types)
4008  return ade_set_error(L, "s", "");
4009 
4010  if(ADE_SETTING_VAR && s != NULL) {
4011  strncpy(Weapon_info[idx].tech_title, s, sizeof(Weapon_info[idx].tech_title)-1);
4012  }
4013 
4014  return ade_set_args(L, "s", Weapon_info[idx].tech_title);
4015 }
4016 
4017 ADE_VIRTVAR(TechAnimationFilename, l_Weaponclass, "string", "Weapon class animation filename", "string", "Filename, or empty string if handle is invalid")
4018 {
4019  int idx;
4020  char *s = NULL;
4021  if(!ade_get_args(L, "o|s", l_Weaponclass.Get(&idx), &s))
4022  return ade_set_error(L, "s", "");
4023 
4024  if(idx < 0 || idx >= Num_weapon_types)
4025  return ade_set_error(L, "s", "");
4026 
4027  if(ADE_SETTING_VAR && s != NULL) {
4028  strncpy(Weapon_info[idx].tech_anim_filename, s, sizeof(Weapon_info[idx].tech_anim_filename)-1);
4029  }
4030 
4031  return ade_set_args(L, "s", Weapon_info[idx].tech_anim_filename);
4032 }
4033 
4034 ADE_VIRTVAR(TechDescription, l_Weaponclass, "string", "Weapon class tech description string", "string", "Description string, or empty string if handle is invalid")
4035 {
4036  int idx;
4037  char *s = NULL;
4038  if(!ade_get_args(L, "o|s", l_Weaponclass.Get(&idx), &s))
4039  return ade_set_error(L, "s", "");
4040 
4041  if(idx < 0 || idx >= Num_weapon_types)
4042  return ade_set_error(L, "s", "");
4043 
4044  weapon_info *wip = &Weapon_info[idx];
4045 
4046  if(ADE_SETTING_VAR) {
4047  vm_free(wip->tech_desc);
4048  if(s != NULL) {
4049  wip->tech_desc = (char*)vm_malloc(strlen(s)+1);
4050  strcpy(wip->tech_desc, s);
4051  } else {
4052  wip->tech_desc = NULL;
4053  }
4054  }
4055 
4056  if(wip->tech_desc != NULL)
4057  return ade_set_args(L, "s", wip->tech_desc);
4058  else
4059  return ade_set_args(L, "s", "");
4060 }
4061 
4062 ADE_VIRTVAR(Model, l_Weaponclass, "model", "Model", "model", "Weapon class model, or invalid model handle if weaponclass handle is invalid")
4063 {
4064  int weapon_info_idx=-1;
4065  model_h *mdl = NULL;
4066  if(!ade_get_args(L, "o|o", l_Weaponclass.Get(&weapon_info_idx), l_Model.GetPtr(&mdl)))
4067  return ade_set_error(L, "o", l_Model.Set(-1));
4068 
4069  if(weapon_info_idx < 0 || weapon_info_idx >= Num_weapon_types)
4070  return ade_set_error(L, "o", l_Model.Set(-1));
4071 
4072  weapon_info *wip = &Weapon_info[weapon_info_idx];
4073 
4074  int mid = (mdl ? mdl->GetID() : -1);
4075 
4076  if(ADE_SETTING_VAR && mid > -1) {
4077  wip->model_num = mid;
4078  }
4079 
4080  return ade_set_args(L, "o", l_Model.Set(model_h(wip->model_num)));
4081 }
4082 
4083 ADE_VIRTVAR(ArmorFactor, l_Weaponclass, "number", "Amount of weapon damage applied to ship hull (0-1.0)", "number", "Armor factor, or empty string if handle is invalid")
4084 {
4085  int idx;
4086  float f = 0.0f;
4087  if(!ade_get_args(L, "o|f", l_Weaponclass.Get(&idx), &f))
4088  return ade_set_error(L, "f", 0.0f);
4089 
4090  if(idx < 0 || idx >= Num_weapon_types)
4091  return ade_set_error(L, "f", 0.0f);
4092 
4093  if(ADE_SETTING_VAR) {
4095  }
4096 
4097  return ade_set_args(L, "f", Weapon_info[idx].armor_factor);
4098 }
4099 
4100 ADE_VIRTVAR(Damage, l_Weaponclass, "number", "Amount of damage that weapon deals", "number", "Damage amount, or 0 if handle is invalid")
4101 {
4102  int idx;
4103  float f = 0.0f;
4104  if(!ade_get_args(L, "o|f", l_Weaponclass.Get(&idx), &f))
4105  return ade_set_error(L, "f", 0.0f);
4106 
4107  if(idx < 0 || idx >= Num_weapon_types)
4108  return ade_set_error(L, "f", 0.0f);
4109 
4110  if(ADE_SETTING_VAR) {
4111  Weapon_info[idx].damage = f;
4112  }
4113 
4114  return ade_set_args(L, "f", Weapon_info[idx].damage);
4115 }
4116 
4117 ADE_VIRTVAR(FireWait, l_Weaponclass, "number", "Weapon fire wait (cooldown time) in seconds", "number", "Fire wait time, or 0 if handle is invalid")
4118 {
4119  int idx;
4120  float f = 0.0f;
4121  if(!ade_get_args(L, "o|f", l_Weaponclass.Get(&idx), &f))
4122  return ade_set_error(L, "f", 0.0f);
4123 
4124  if(idx < 0 || idx >= Num_weapon_types)
4125  return ade_set_error(L, "f", 0.0f);
4126 
4127  if(ADE_SETTING_VAR) {
4129  }
4130 
4131  return ade_set_args(L, "f", Weapon_info[idx].fire_wait);
4132 }
4133 
4134 ADE_VIRTVAR(FreeFlightTime, l_Weaponclass, "number", "The time the weapon will fly before turing onto its target", "number", "Free flight time or emty string if invalid")
4135 {
4136  int idx;
4137  float f = 0.0f;
4138  if(!ade_get_args(L, "o|f", l_Weaponclass.Get(&idx), &f))
4139  return ade_set_error(L, "f", 0.0f);
4140 
4141  if(idx < 0 || idx >= Num_weapon_types)
4142  return ade_set_error(L, "f", 0.0f);
4143 
4144  if(ADE_SETTING_VAR) {
4146  }
4147 
4148  return ade_set_args(L, "f", Weapon_info[idx].free_flight_time);
4149 }
4150 
4151 ADE_VIRTVAR(LifeMax, l_Weaponclass, "number", "Life of weapon in seconds", "number", "Life of weapon, or 0 if handle is invalid")
4152 {
4153  int idx;
4154  float f = 0.0f;
4155  if(!ade_get_args(L, "o|f", l_Weaponclass.Get(&idx), &f))
4156  return ade_set_error(L, "f", 0.0f);
4157 
4158  if(idx < 0 || idx >= Num_weapon_types)
4159  return ade_set_error(L, "f", 0.0f);
4160 
4161  if(ADE_SETTING_VAR) {
4163  }
4164 
4165  return ade_set_args(L, "f", Weapon_info[idx].lifetime);
4166 }
4167 
4168 ADE_VIRTVAR(Range, l_Weaponclass, "number", "Range of weapon in meters", "number", "Weapon Range, or 0 if handle is invalid")
4169 {
4170  int idx;
4171  float f = 0.0f;
4172  if(!ade_get_args(L, "o|f", l_Weaponclass.Get(&idx), &f))
4173  return ade_set_error(L, "f", 0.0f);
4174 
4175  if(idx < 0 || idx >= Num_weapon_types)
4176  return ade_set_error(L, "f", 0.0f);
4177 
4178  if(ADE_SETTING_VAR) {
4180  }
4181 
4182  return ade_set_args(L, "f", Weapon_info[idx].weapon_range);
4183 }
4184 
4185 ADE_VIRTVAR(Mass, l_Weaponclass, "number", "Weapon mass", "number", "Weapon mass, or 0 if handle is invalid")
4186 {
4187  int idx;
4188  float f = 0.0f;
4189  if(!ade_get_args(L, "o|f", l_Weaponclass.Get(&idx), &f))
4190  return ade_set_error(L, "f", 0.0f);
4191 
4192  if(idx < 0 || idx >= Num_weapon_types)
4193  return ade_set_error(L, "f", 0.0f);
4194 
4195  if(ADE_SETTING_VAR) {
4196  Weapon_info[idx].mass = f;
4197  }
4198 
4199  return ade_set_args(L, "f", Weapon_info[idx].mass);
4200 }
4201 
4202 ADE_VIRTVAR(ShieldFactor, l_Weaponclass, "number", "Amount of weapon damage applied to ship shields (0-1.0)", "number", "Shield damage factor, or 0 if handle is invalid")
4203 {
4204  int idx;
4205  float f = 0.0f;
4206  if(!ade_get_args(L, "o|f", l_Weaponclass.Get(&idx), &f))
4207  return ade_set_error(L, "f", 0.0f);
4208 
4209  if(idx < 0 || idx >= Num_weapon_types)
4210  return ade_set_error(L, "f", 0.0f);
4211 
4212  if(ADE_SETTING_VAR) {
4214  }
4215 
4216  return ade_set_args(L, "f", Weapon_info[idx].shield_factor);
4217 }
4218 
4219 ADE_VIRTVAR(SubsystemFactor, l_Weaponclass, "number", "Amount of weapon damage applied to ship subsystems (0-1.0)", "number", "Subsystem damage factor, or 0 if handle is invalid")
4220 {
4221  int idx;
4222  float f = 0.0f;
4223  if(!ade_get_args(L, "o|f", l_Weaponclass.Get(&idx), &f))
4224  return ade_set_error(L, "f", 0.0f);
4225 
4226  if(idx < 0 || idx >= Num_weapon_types)
4227  return ade_set_error(L, "f", 0.0f);
4228 
4229  if(ADE_SETTING_VAR) {
4231  }
4232 
4233  return ade_set_args(L, "f", Weapon_info[idx].subsystem_factor);
4234 }
4235 
4236 ADE_VIRTVAR(TargetLOD, l_Weaponclass, "number", "LOD used for weapon model in the targeting computer", "number", "LOD number, or 0 if handle is invalid")
4237 {
4238  int idx;
4239  int lod = 0;
4240  if(!ade_get_args(L, "o|i", l_Weaponclass.Get(&idx), &lod))
4241  return ade_set_error(L, "i", 0);
4242 
4243  if(idx < 0 || idx >= Num_weapon_types)
4244  return ade_set_error(L, "i", 0);
4245 
4246  if(ADE_SETTING_VAR) {
4248  }
4249 
4250  return ade_set_args(L, "i", Weapon_info[idx].hud_target_lod);
4251 }
4252 
4253 ADE_VIRTVAR(Speed, l_Weaponclass, "number", "Weapon max speed, aka $Velocity in weapons.tbl", "number", "Weapon speed, or 0 if handle is invalid")
4254 {
4255  int idx;
4256  float spd = 0.0f;
4257  if(!ade_get_args(L, "o|f", l_Weaponclass.Get(&idx), &spd))
4258  return ade_set_error(L, "f", 0.0f);
4259 
4260  if(idx < 0 || idx >= Num_weapon_types)
4261  return ade_set_error(L, "f", 0.0f);
4262 
4263  if(ADE_SETTING_VAR) {
4264  Weapon_info[idx].max_speed = spd;
4265  }
4266 
4267  return ade_set_args(L, "f", Weapon_info[idx].max_speed);
4268 }
4269 
4270 ADE_VIRTVAR(Bomb, l_Weaponclass, "boolean", "Is weapon class flagged as bomb", "boolean", "New flag")
4271 {
4272  int idx;
4273  bool newVal = false;
4274  if(!ade_get_args(L, "o|b", l_Weaponclass.Get(&idx), &newVal))
4275  return ADE_RETURN_FALSE;
4276 
4277  if(idx < 0 || idx >= Num_weapon_types)
4278  return ADE_RETURN_FALSE;
4279 
4280  weapon_info *info = &Weapon_info[idx];
4281 
4282  if(ADE_SETTING_VAR)
4283  {
4284  if(newVal)
4285  {
4286  info->wi_flags |= WIF_BOMB;
4287  }
4288  else
4289  {
4290  info->wi_flags &= ~WIF_BOMB;
4291  }
4292  }
4293 
4294 
4295  if (info->wi_flags & WIF_BOMB)
4296  return ADE_RETURN_TRUE;
4297  else
4298  return ADE_RETURN_FALSE;
4299 }
4300 
4301 ADE_VIRTVAR(CargoSize, l_Weaponclass, "number", "The cargo size of this weapon class", "number", "The new cargo size or -1 on error")
4302 {
4303  int idx;
4304  float newVal = -1.0f;
4305  if(!ade_get_args(L, "o|f", l_Weaponclass.Get(&idx), &newVal))
4306  return ade_set_args(L, "f", -1.0f);
4307 
4308  if(idx < 0 || idx >= Num_weapon_types)
4309  return ade_set_args(L, "f", -1.0f);
4310 
4311  weapon_info *info = &Weapon_info[idx];
4312 
4313  if(ADE_SETTING_VAR)
4314  {
4315  if(newVal > 0)
4316  {
4317  info->cargo_size = newVal;
4318  }
4319  else
4320  {
4321  LuaError(L, "Cargo size must be bigger than zero, got %f!", newVal);
4322  }
4323  }
4324 
4325  return ade_set_args(L, "f", info->cargo_size);
4326 }
4327 
4328 ADE_FUNC(isValid, l_Weaponclass, NULL, "Detects whether handle is valid", "boolean", "true if valid, false if handle is invalid, nil if a syntax/type error occurs")
4329 {
4330  int idx;
4331  if(!ade_get_args(L, "o", l_Weaponclass.Get(&idx)))
4332  return ADE_RETURN_NIL;
4333 
4334  if(idx < 0 || idx >= Num_weapon_types)
4335  return ADE_RETURN_FALSE;
4336 
4337  return ADE_RETURN_TRUE;
4338 }
4339 
4340 ADE_FUNC(getWeaponClassIndex, l_Weaponclass, NULL, "Gets the index value of the weapon class", "number", "index value of the weapon class")
4341 {
4342  int idx;
4343  if(!ade_get_args(L, "o", l_Weaponclass.Get(&idx)))
4344  return ade_set_args(L, "i", -1);
4345 
4346  if(idx < 0 || idx >= Num_weapon_types)
4347  return ade_set_args(L, "i", -1);
4348 
4349  return ade_set_args(L, "i", idx + 1);
4350 }
4351 
4352 ADE_FUNC(isLaser, l_Weaponclass, NULL, "Return true if the weapon is a primary weapon (this includes Beams). This function is deprecated, use isPrimary instead.", "boolean", "true if the weapon is a primary, false otherwise")
4353 {
4354  int idx;
4355  if(!ade_get_args(L, "o", l_Weaponclass.Get(&idx)))
4356  return ADE_RETURN_NIL;
4357 
4358  if(idx < 0 || idx >= Num_weapon_types)
4359  return ADE_RETURN_FALSE;
4360 
4361  if (Weapon_info[idx].subtype == WP_LASER)
4362  return ADE_RETURN_TRUE;
4363  else
4365 }
4366 
4367 ADE_FUNC(isMissile, l_Weaponclass, NULL, "Return true if the weapon is a secondary weapon. This function is deprecated, use isSecondary instead.", "boolean", "true if the weapon is a secondary, false otherwise")
4368 {
4369  int idx;
4370  if(!ade_get_args(L, "o", l_Weaponclass.Get(&idx)))
4371  return ADE_RETURN_NIL;
4372 
4373  if(idx < 0 || idx >= Num_weapon_types)
4374  return ADE_RETURN_FALSE;
4375 
4376  if (Weapon_info[idx].subtype == WP_MISSILE)
4377  return ADE_RETURN_TRUE;
4378  else
4379  return ADE_RETURN_FALSE;
4380 }
4381 
4382 ADE_FUNC(isPrimary, l_Weaponclass, NULL, "Return true if the weapon is a primary weapon (this includes Beams)", "boolean", "true if the weapon is a primary, false otherwise")
4383 {
4384  int idx;
4385  if(!ade_get_args(L, "o", l_Weaponclass.Get(&idx)))
4386  return ADE_RETURN_NIL;
4387 
4388  if(idx < 0 || idx >= Num_weapon_types)
4389  return ADE_RETURN_FALSE;
4390 
4391  if (Weapon_info[idx].subtype == WP_LASER)
4392  return ADE_RETURN_TRUE;
4393  else
4394  return ADE_RETURN_FALSE;
4395 }
4396 
4397 ADE_FUNC(isSecondary, l_Weaponclass, NULL, "Return true if the weapon is a secondary weapon", "boolean", "true if the weapon is a secondary, false otherwise")
4398 {
4399  int idx;
4400  if(!ade_get_args(L, "o", l_Weaponclass.Get(&idx)))
4401  return ADE_RETURN_NIL;
4402 
4403  if(idx < 0 || idx >= Num_weapon_types)
4404  return ADE_RETURN_FALSE;
4405 
4406  if (Weapon_info[idx].subtype == WP_MISSILE)
4407  return ADE_RETURN_TRUE;
4408  else
4409  return ADE_RETURN_FALSE;
4410 }
4411 
4412 ADE_FUNC(isBeam, l_Weaponclass, NULL, "Return true if the weapon is a beam", "boolean", "true if the weapon is a beam, false otherwise")
4413 {
4414  int idx;
4415  if(!ade_get_args(L, "o", l_Weaponclass.Get(&idx)))
4416  return ADE_RETURN_NIL;
4417 
4418  if(idx < 0 || idx >= Num_weapon_types)
4419  return ADE_RETURN_FALSE;
4420 
4421  if (Weapon_info[idx].wi_flags & WIF_BEAM || Weapon_info[idx].subtype == WP_BEAM)
4422  return ADE_RETURN_TRUE;
4423  else
4424  return ADE_RETURN_FALSE;
4425 }
4426 
4428 {
4429 protected:
4431 public:
4432  mc_info_h(mc_info* val) : info(val) {}
4433 
4434  mc_info_h() : info(NULL) {}
4435 
4437  {
4438  return info;
4439  }
4440 
4441  void deleteInfo()
4442  {
4443  if (!this->IsValid())
4444  return;
4445 
4446  delete info;
4447 
4448  info = NULL;
4449  }
4450 
4451  bool IsValid()
4452  {
4453  return info != NULL;
4454  }
4455 };
4456 
4457 //**********HANDLE: Collision info
4458 ade_obj<mc_info_h> l_ColInfo("collision info", "Information about a collision");
4459 
4460 ADE_FUNC(__gc, l_ColInfo, NULL, "Removes the allocated reference of this handle", NULL, NULL)
4461 {
4462  mc_info_h* info;
4463 
4464  if(!ade_get_args(L, "o", l_ColInfo.GetPtr(&info)))
4465  return ADE_RETURN_NIL;
4466 
4467  if (info->IsValid())
4468  info->deleteInfo();
4469 
4470  return ADE_RETURN_NIL;
4471 }
4472 
4473 ADE_VIRTVAR(Model, l_ColInfo, "model", "The model this collision info is about", "model", "The model")
4474 {
4475  mc_info_h* info;
4476  model_h * mh = nullptr;
4477 
4478  if(!ade_get_args(L, "o|o", l_ColInfo.GetPtr(&info), l_Model.GetPtr(&mh)))
4479  return ade_set_error(L, "o", l_Model.Set(model_h()));
4480 
4481  if (!info->IsValid())
4482  return ade_set_error(L, "o", l_Model.Set(model_h()));
4483 
4484  mc_info *collide = info->Get();
4485 
4486  int modelNum = collide->model_num;
4487 
4488  if (ADE_SETTING_VAR && mh)
4489  {
4490  if (mh->IsValid())
4491  {
4492  collide->model_num = mh->GetID();
4493  }
4494  }
4495 
4496  return ade_set_args(L, "o", l_Model.Set(model_h(modelNum)));
4497 }
4498 
4499 ADE_FUNC(getCollisionDistance, l_ColInfo, NULL, "The distance to the closest collision point", "number", "distance or -1 on error")
4500 {
4501  mc_info_h* info;
4502 
4503  if(!ade_get_args(L, "o", l_ColInfo.GetPtr(&info)))
4504  return ade_set_error(L, "f", -1.0f);
4505 
4506  if (!info->IsValid())
4507  return ade_set_error(L, "f", -1.0f);
4508 
4509  mc_info *collide = info->Get();
4510 
4511  if (collide->num_hits <= 0)
4512  {
4513  return ade_set_args(L, "f", -1.0f);;
4514  }
4515  else
4516  {
4517  return ade_set_args(L, "f", collide->hit_dist);
4518  }
4519 }
4520 
4521 ADE_FUNC(getCollisionPoint, l_ColInfo, "[boolean local]", "The collision point of this information (local to the object if boolean is set to <i>true</i>)", "vector", "The collision point or nil of none")
4522 {
4523  mc_info_h* info;
4524  bool local = false;
4525 
4526  if(!ade_get_args(L, "o|b", l_ColInfo.GetPtr(&info), &local))
4527  return ADE_RETURN_NIL;
4528 
4529  if (!info->IsValid())
4530  return ADE_RETURN_NIL;
4531 
4532  mc_info *collide = info->Get();
4533 
4534  if (collide->num_hits <= 0)
4535  {
4536  return ADE_RETURN_NIL;
4537  }
4538  else
4539  {
4540  if (local)
4541  return ade_set_args(L, "o", l_Vector.Set(collide->hit_point));
4542  else
4543  return ade_set_args(L, "o", l_Vector.Set(collide->hit_point_world));
4544  }
4545 }
4546 
4547 ADE_FUNC(getCollisionNormal, l_ColInfo, "[boolean local]", "The collision normal of this information (local to object if boolean is set to <i>true</i>)", "vector", "The collision normal or nil of none")
4548 {
4549  mc_info_h* info;
4550  bool local = false;
4551 
4552  if(!ade_get_args(L, "o|b", l_ColInfo.GetPtr(&info), &local))
4553  return ADE_RETURN_NIL;
4554 
4555  if (!info->IsValid())
4556  return ADE_RETURN_NIL;
4557 
4558  mc_info *collide = info->Get();
4559 
4560  if (collide->num_hits <= 0)
4561  {
4562  return ADE_RETURN_NIL;
4563  }
4564  else
4565  {
4566  if (!local)
4567  {
4568  vec3d normal;
4569 
4570  vm_vec_unrotate(&normal, &collide->hit_normal, collide->orient);
4571 
4572  return ade_set_args(L, "o", l_Vector.Set(normal));
4573  }
4574  else
4575  {
4576  return ade_set_args(L, "o", l_Vector.Set(collide->hit_normal));
4577  }
4578  }
4579 }
4580 
4581 ADE_FUNC(isValid, l_ColInfo, NULL, "Detects if this handle is valid", "boolean", "true if valid false otherwise")
4582 {
4583  mc_info_h* info;
4584 
4585  if(!ade_get_args(L, "o", l_ColInfo.GetPtr(&info)))
4586  return ADE_RETURN_NIL;
4587 
4588  if (info->IsValid())
4589  return ADE_RETURN_TRUE;
4590  else
4591  return ADE_RETURN_FALSE;
4592 }
4593 
4594 //**********HANDLE: modeltextures
4595 ADE_FUNC(__len, l_ModelTextures, NULL, "Number of textures on model", "number", "Number of model textures")
4596 {
4597  modeltextures_h *mth;
4598  if(!ade_get_args(L, "o", l_ModelTextures.GetPtr(&mth)))
4599  return ade_set_error(L, "i", 0);
4600 
4601  if(!mth->IsValid())
4602  return ade_set_error(L, "i", 0);
4603 
4604  polymodel *pm = mth->Get();
4605 
4606  if(pm == NULL)
4607  return ade_set_error(L, "i", 0);
4608 
4609  return ade_set_args(L, "i", TM_NUM_TYPES*pm->n_textures);
4610 }
4611 
4612 ADE_INDEXER(l_ModelTextures, "texture", "number Index/string TextureName", "texture", "Model textures, or invalid modeltextures handle if model handle is invalid")
4613 {
4614  modeltextures_h *mth = NULL;
4615  int new_tex = -1;
4616  char *s = NULL;
4617 
4618  if (!ade_get_args(L, "os|o", l_ModelTextures.GetPtr(&mth), &s, l_Texture.Get(&new_tex)))
4619  return ade_set_error(L, "o", l_Texture.Set(-1));
4620 
4621  polymodel *pm = mth->Get();
4622 
4623  if (!mth->IsValid() || s == NULL || pm == NULL)
4624  return ade_set_error(L, "o", l_Texture.Set(-1));
4625 
4626  texture_info *tinfo = NULL;
4627  texture_map *tmap = NULL;
4628 
4629  if(strspn(s, "0123456789") == strlen(s))
4630  {
4631  int num_textures = TM_NUM_TYPES*pm->n_textures;
4632  int idx = atoi(s) - 1; //Lua->FS2
4633 
4634  if (idx < 0 || idx >= num_textures)
4635  return ade_set_error(L, "o", l_Texture.Set(-1));
4636 
4637  tmap = &pm->maps[idx / TM_NUM_TYPES];
4638  tinfo = &tmap->textures[idx % TM_NUM_TYPES];
4639  }
4640 
4641  if(tinfo == NULL)
4642  {
4643  for (int i = 0; i < pm->n_textures; i++)
4644  {
4645  tmap = &pm->maps[i];
4646 
4647  int tnum = tmap->FindTexture(s);
4648  if(tnum > -1)
4649  tinfo = &tmap->textures[tnum];
4650  }
4651  }
4652 
4653  if(tinfo == NULL)
4654  return ade_set_error(L, "o", l_Texture.Set(-1));
4655 
4656  if (ADE_SETTING_VAR) {
4657  tinfo->SetTexture(new_tex);
4658  }
4659 
4660  return ade_set_args(L, "o", l_Texture.Set(tinfo->GetTexture()));
4661 }
4662 
4663 ADE_FUNC(isValid, l_ModelTextures, NULL, "Detects whether handle is valid", "boolean", "true if valid, false if handle is invalid, nil if a syntax/type error occurs")
4664 {
4665  modeltextures_h *mth;
4666  if(!ade_get_args(L, "o", l_ModelTextures.GetPtr(&mth)))
4667  return ADE_RETURN_NIL;
4668 
4669  return ade_set_args(L, "b", mth->IsValid());
4670 }
4671 
4672 //**********HANDLE: Object
4673 ade_obj<object_h> l_Object("object", "Object handle");
4674 //Helper function
4675 //Returns 1 if object sig stored in idx exists, and stores Objects[] index in idx
4676 //Returns 0 if object sig does not exist, and does not change idx
4677 
4678 ADE_FUNC(__eq, l_Object, "object, object", "Checks whether two object handles are for the same object", "boolean", "True if equal, false if not or a handle is invalid")
4679 {
4680  object_h *o1, *o2;
4681  if(!ade_get_args(L, "oo", l_Object.GetPtr(&o1), l_Object.GetPtr(&o2)))
4682  return ADE_RETURN_FALSE;
4683 
4684  if(!o1->IsValid() || !o2->IsValid())
4685  return ADE_RETURN_FALSE;
4686 
4687  return ade_set_args(L, "b", o1->sig == o2->sig);
4688 }
4689 
4690 ADE_FUNC(__tostring, l_Object, NULL, "Returns name of object (if any)", "string", "Object name, or empty string if handle is invalid")
4691 {
4692  object_h *objh;
4693  if(!ade_get_args(L, "o", l_Object.GetPtr(&objh)))
4694  return ade_set_error(L, "s", "");
4695 
4696  if(!objh->IsValid())
4697  return ade_set_error(L, "s", "");
4698 
4699  char buf[512];
4700 
4701  switch(objh->objp->type)
4702  {
4703  case OBJ_SHIP:
4704  sprintf(buf, "%s", Ships[objh->objp->instance].ship_name);
4705  break;
4706  case OBJ_WEAPON:
4707  sprintf(buf, "%s projectile", Weapon_info[Weapons[objh->objp->instance].weapon_info_index].name);
4708  break;
4709  default:
4710  sprintf(buf, "Object %td [%d]", OBJ_INDEX(objh->objp), objh->sig);
4711  }
4712 
4713  return ade_set_args(L, "s", buf);
4714 }
4715 
4716 ADE_VIRTVAR(Parent, l_Object, "object", "Parent of the object. Value may also be a deriviative of the 'object' class, such as 'ship'.", "object", "Parent handle, or invalid handle if object is invalid")
4717 {
4718  object_h *objh;
4719  object_h *newparenth = NULL;
4720  if(!ade_get_args(L, "o|o", l_Object.GetPtr(&objh), l_Object.GetPtr(&newparenth)))
4721  return ade_set_error(L, "o", l_Object.Set(object_h()));
4722 
4723  if(!objh->IsValid())
4724  return ade_set_error(L, "o", l_Object.Set(object_h()));
4725 
4726  if(ADE_SETTING_VAR)
4727  {
4728  if(newparenth != NULL && newparenth->IsValid())
4729  {
4730  objh->objp->parent = OBJ_INDEX(newparenth->objp);
4731  objh->objp->parent_sig = newparenth->sig;
4732  objh->objp->parent_type = newparenth->objp->type;
4733  }
4734  else
4735  {
4736  objh->objp->parent = -1;
4737  objh->objp->parent_sig = 0;
4738  objh->objp->parent_type = OBJ_NONE;
4739  }
4740  }
4741 
4742  if(objh->objp->parent > -1)
4743  return ade_set_object_with_breed(L, objh->objp->parent);
4744  else
4745  return ade_set_args(L, "o", l_Object.Set(object_h()));
4746 }
4747 
4748 ADE_VIRTVAR(Position, l_Object, "vector", "Object world position (World vector)", "vector", "World position, or null vector if handle is invalid")