1 // 2 // 3 4 5 #include "ship.h" 6 #include "texture.h" 7 #include "object.h" 8 #include "subsystem.h" 9 #include "shipclass.h" 10 #include "cockpit_display.h" 11 #include "weaponclass.h" 12 #include "ship_bank.h" 13 #include "team.h" 14 #include "order.h" 15 #include "enums.h" 16 #include "wing.h" 17 #include "vecmath.h" 18 19 #include "ship/shiphit.h" 20 #include "hud/hudshield.h" 21 #include "playerman/player.h" 22 #include "mission/missionlog.h" 23 #include "ai/aigoals.h" 24 #include "ship/shipfx.h" 25 #include "hud/hudets.h" 26 #include "object/object.h" 27 #include "model/model.h" 28 #include "ship/ship.h" 29 #include "parse/parselo.h" 30 31 extern void ship_reset_disabled_physics(object *objp, int ship_class); 32 33 namespace scripting { 34 namespace api { 35 36 //**********HANDLE: shiptextures 37 ADE_OBJ(l_ShipTextures, object_h, "shiptextures", "Ship textures handle"); 38 39 ADE_FUNC(__len, l_ShipTextures, NULL, "Number of textures on ship", "number", "Number of textures on ship, or 0 if handle is invalid") 40 { 41 object_h *objh; 42 if(!ade_get_args(L, "o", l_ShipTextures.GetPtr(&objh))) 43 return ade_set_error(L, "i", 0); 44 45 if(!objh->IsValid()) 46 return ade_set_error(L, "i", 0); 47 48 polymodel *pm = model_get(Ship_info[Ships[objh->objp->instance].ship_info_index].model_num); 49 50 if(pm == NULL) 51 return ade_set_error(L, "i", 0); 52 53 return ade_set_args(L, "i", pm->n_textures*TM_NUM_TYPES); 54 } 55 56 ADE_INDEXER(l_ShipTextures, "number/string IndexOrTextureFilename", "Array of ship textures", "texture", "Texture, or invalid texture handle on failure") 57 { 58 object_h *oh; 59 const char* s; 60 texture_h* tdx = nullptr; 61 if (!ade_get_args(L, "os|o", l_ShipTextures.GetPtr(&oh), &s, l_Texture.GetPtr(&tdx))) 62 return ade_set_error(L, "o", l_Texture.Set(texture_h())); 63 64 if (!oh->IsValid() || s==NULL) 65 return ade_set_error(L, "o", l_Texture.Set(texture_h())); 66 67 ship *shipp = &Ships[oh->objp->instance]; 68 polymodel *pm = model_get(Ship_info[shipp->ship_info_index].model_num); 69 int final_index = -1; 70 int i; 71 72 char fname[MAX_FILENAME_LEN]; 73 if (shipp->ship_replacement_textures != NULL) 74 { 75 for(i = 0; i < MAX_REPLACEMENT_TEXTURES; i++) 76 { 77 bm_get_filename(shipp->ship_replacement_textures[i], fname); 78 79 if(!strextcmp(fname, s)) { 80 final_index = i; 81 break; 82 } 83 } 84 } 85 86 if(final_index < 0) 87 { 88 for (i = 0; i < pm->n_textures; i++) 89 { 90 int tm_num = pm->maps[i].FindTexture(s); 91 if(tm_num > -1) 92 { 93 final_index = i*TM_NUM_TYPES+tm_num; 94 break; 95 } 96 } 97 } 98 99 if (final_index < 0) 100 { 101 final_index = atoi(s) - 1; //Lua->FS2 102 103 if (final_index < 0 || final_index >= MAX_REPLACEMENT_TEXTURES) 104 return ade_set_error(L, "o", l_Texture.Set(texture_h())); 105 } 106 107 if (ADE_SETTING_VAR) { 108 if (shipp->ship_replacement_textures == NULL) { 109 shipp->ship_replacement_textures = (int *) vm_malloc(MAX_REPLACEMENT_TEXTURES * sizeof(int)); 110 111 for (i = 0; i < MAX_REPLACEMENT_TEXTURES; i++) 112 shipp->ship_replacement_textures[i] = -1; 113 } 114 115 if (tdx != nullptr) { 116 if (tdx->isValid()) 117 shipp->ship_replacement_textures[final_index] = tdx->handle; 118 else 119 shipp->ship_replacement_textures[final_index] = -1; 120 } 121 } 122 123 if (shipp->ship_replacement_textures != NULL && shipp->ship_replacement_textures[final_index] >= 0) 124 return ade_set_args(L, "o", l_Texture.Set(texture_h(shipp->ship_replacement_textures[final_index]))); 125 else 126 return ade_set_args(L, "o", l_Texture.Set(texture_h(pm->maps[final_index / TM_NUM_TYPES].textures[final_index % TM_NUM_TYPES].GetTexture()))); 127 } 128 129 ADE_FUNC(isValid, l_ShipTextures, NULL, "Detects whether handle is valid", "boolean", "true if valid, false if handle is invalid, nil if a syntax/type error occurs") 130 { 131 object_h *oh; 132 if(!ade_get_args(L, "o", l_ShipTextures.GetPtr(&oh))) 133 return ADE_RETURN_NIL; 134 135 return ade_set_args(L, "b", oh->IsValid()); 136 } 137 138 //**********HANDLE: Ship 139 ADE_OBJ_DERIV(l_Ship, object_h, "ship", "Ship handle", l_Object); 140 141 ADE_INDEXER(l_Ship, "string/number NameOrIndex", "Array of ship subsystems", "subsystem", "Subsystem handle, or invalid subsystem handle if index or ship handle is invalid") 142 { 143 object_h *objh; 144 const char* s = nullptr; 145 ship_subsys_h *sub = nullptr; 146 if(!ade_get_args(L, "o|so", l_Ship.GetPtr(&objh), &s, l_Subsystem.GetPtr(&sub))) 147 return ade_set_error(L, "o", l_Subsystem.Set(ship_subsys_h())); 148 149 if(!objh->IsValid()) 150 return ade_set_error(L, "o", l_Subsystem.Set(ship_subsys_h())); 151 152 ship *shipp = &Ships[objh->objp->instance]; 153 ship_subsys *ss = ship_get_subsys(shipp, s); 154 155 if(ss == NULL) 156 { 157 int idx = atoi(s); 158 if(idx > 0 && idx <= ship_get_num_subsys(shipp)) 159 { 160 idx--; //Lua->FS2 161 ss = ship_get_indexed_subsys(shipp, idx); 162 } 163 } 164 165 if(ss == NULL) 166 return ade_set_error(L, "o", l_Subsystem.Set(ship_subsys_h())); 167 168 return ade_set_args(L, "o", l_Subsystem.Set(ship_subsys_h(objh->objp, ss))); 169 } 170 171 ADE_FUNC(__len, l_Ship, NULL, "Number of subsystems on ship", "number", "Subsystem number, or 0 if handle is invalid") 172 { 173 object_h *objh; 174 if(!ade_get_args(L, "o", l_Ship.GetPtr(&objh))) 175 return ade_set_error(L, "i", 0); 176 177 if(!objh->IsValid()) 178 return ade_set_error(L, "i", 0); 179 180 return ade_set_args(L, "i", ship_get_num_subsys(&Ships[objh->objp->instance])); 181 } 182 183 ADE_VIRTVAR(ShieldArmorClass, l_Ship, "string", "Current Armor class of the ships' shield", "string", "Armor class name, or empty string if none is set") 184 { 185 object_h *objh; 186 const char* s = nullptr; 187 const char *name = nullptr; 188 189 if(!ade_get_args(L, "o|s", l_Ship.GetPtr(&objh), &s)) 190 return ade_set_error(L, "s", ""); 191 192 if(!objh->IsValid()) 193 return ade_set_error(L, "s", ""); 194 195 ship *shipp = &Ships[objh->objp->instance]; 196 int atindex; 197 if (ADE_SETTING_VAR && s != nullptr) { 198 atindex = armor_type_get_idx(s); 199 shipp->shield_armor_type_idx = atindex; 200 } else { 201 atindex = shipp->shield_armor_type_idx; 202 } 203 204 if (atindex != -1) 205 name = Armor_types[atindex].GetNamePtr(); 206 else 207 name = ""; 208 209 return ade_set_args(L, "s", name); 210 } 211 212 ADE_VIRTVAR(ArmorClass, l_Ship, "string", "Current Armor class", "string", "Armor class name, or empty string if none is set") 213 { 214 object_h *objh; 215 const char* s = nullptr; 216 const char *name = nullptr; 217 218 if(!ade_get_args(L, "o|s", l_Ship.GetPtr(&objh), &s)) 219 return ade_set_error(L, "s", ""); 220 221 if(!objh->IsValid()) 222 return ade_set_error(L, "s", ""); 223 224 ship *shipp = &Ships[objh->objp->instance]; 225 int atindex; 226 if (ADE_SETTING_VAR && s != nullptr) { 227 atindex = armor_type_get_idx(s); 228 shipp->armor_type_idx = atindex; 229 } else { 230 atindex = shipp->armor_type_idx; 231 } 232 233 if (atindex != -1) 234 name = Armor_types[atindex].GetNamePtr(); 235 else 236 name = ""; 237 238 return ade_set_args(L, "s", name); 239 } 240 241 ADE_VIRTVAR(Name, l_Ship, "string", "Ship name. This is the actual name of the ship. Use <i>getDisplayString</i> to get the string which should be displayed to the player.", "string", "Ship name, or empty string if handle is invalid") 242 { 243 object_h *objh; 244 const char* s = nullptr; 245 if(!ade_get_args(L, "o|s", l_Ship.GetPtr(&objh), &s)) 246 return ade_set_error(L, "s", ""); 247 248 if(!objh->IsValid()) 249 return ade_set_error(L, "s", ""); 250 251 ship *shipp = &Ships[objh->objp->instance]; 252 253 if(ADE_SETTING_VAR && s != nullptr) { 254 auto len = sizeof(shipp->ship_name); 255 strncpy(shipp->ship_name, s, len); 256 shipp->ship_name[len - 1] = 0; 257 } 258 259 return ade_set_args(L, "s", shipp->ship_name); 260 } 261 262 ADE_VIRTVAR(DisplayName, l_Ship, "string", "Ship display name", "string", "The display name of the ship or empty if there is no display string") 263 { 264 object_h *objh; 265 const char* s = nullptr; 266 if(!ade_get_args(L, "o|s", l_Ship.GetPtr(&objh), &s)) 267 return ade_set_error(L, "s", ""); 268 269 if(!objh->IsValid()) 270 return ade_set_error(L, "s", ""); 271 272 ship *shipp = &Ships[objh->objp->instance]; 273 274 if(ADE_SETTING_VAR && s != nullptr) { 275 shipp->display_name = s; 276 277 // for compatibility reasons, if we are setting this to the empty string, clear the flag 278 shipp->flags.set(Ship::Ship_Flags::Has_display_name, s[0] != 0); 279 } 280 281 return ade_set_args(L, "s", shipp->display_name.c_str()); 282 } 283 284 ADE_VIRTVAR(AfterburnerFuelLeft, l_Ship, "number", "Afterburner fuel left", "number", "Afterburner fuel left, or 0 if handle is invalid") 285 { 286 object_h *objh; 287 float fuel = -1.0f; 288 if(!ade_get_args(L, "o|f", l_Ship.GetPtr(&objh), &fuel)) 289 return ade_set_error(L, "f", 0.0f); 290 291 if(!objh->IsValid()) 292 return ade_set_error(L, "f", 0.0f); 293 294 ship *shipp = &Ships[objh->objp->instance]; 295 296 if(ADE_SETTING_VAR && fuel >= 0.0f) 297 shipp->afterburner_fuel = fuel; 298 299 return ade_set_args(L, "f", shipp->afterburner_fuel); 300 } 301 302 ADE_VIRTVAR(AfterburnerFuelMax, l_Ship, "number", "Afterburner fuel capacity", "number", "Afterburner fuel capacity, or 0 if handle is invalid") 303 { 304 object_h *objh; 305 float fuel = -1.0f; 306 if(!ade_get_args(L, "o|f", l_Ship.GetPtr(&objh), &fuel)) 307 return ade_set_error(L, "f", 0.0f); 308 309 if(!objh->IsValid()) 310 return ade_set_error(L, "f", 0.0f); 311 312 ship_info *sip = &Ship_info[Ships[objh->objp->instance].ship_info_index]; 313 314 if(ADE_SETTING_VAR && fuel >= 0.0f) 315 sip->afterburner_fuel_capacity = fuel; 316 317 return ade_set_args(L, "f", sip->afterburner_fuel_capacity); 318 } 319 320 ADE_VIRTVAR(Class, l_Ship, "shipclass", "Ship class", "shipclass", "Ship class, or invalid shipclass handle if ship handle is invalid") 321 { 322 object_h *objh; 323 int idx=-1; 324 if(!ade_get_args(L, "o|o", l_Ship.GetPtr(&objh), l_Shipclass.Get(&idx))) 325 return ade_set_error(L, "o", l_Shipclass.Set(-1)); 326 327 if(!objh->IsValid()) 328 return ade_set_error(L, "o", l_Shipclass.Set(-1)); 329 330 ship *shipp = &Ships[objh->objp->instance]; 331 332 if(ADE_SETTING_VAR && idx > -1) { 333 change_ship_type(objh->objp->instance, idx, 1); 334 if (shipp == Player_ship) { 335 set_current_hud(); 336 } 337 } 338 339 if(shipp->ship_info_index < 0) 340 return ade_set_error(L, "o", l_Shipclass.Set(-1)); 341 342 return ade_set_args(L, "o", l_Shipclass.Set(shipp->ship_info_index)); 343 } 344 345 ADE_VIRTVAR(CountermeasuresLeft, l_Ship, "number", "Number of countermeasures left", "number", "Countermeasures left, or 0 if ship handle is invalid") 346 { 347 object_h *objh; 348 int newcm = -1; 349 if(!ade_get_args(L, "o|i", l_Ship.GetPtr(&objh), &newcm)) 350 return ade_set_error(L, "i", 0); 351 352 if(!objh->IsValid()) 353 return ade_set_error(L, "i", 0); 354 355 ship *shipp = &Ships[objh->objp->instance]; 356 357 if(ADE_SETTING_VAR && newcm > -1) 358 shipp->cmeasure_count = newcm; 359 360 return ade_set_args(L, "i", shipp->cmeasure_count); 361 } 362 363 ADE_VIRTVAR(CockpitDisplays, l_Ship, "displays", "An array of the cockpit displays on this ship.<br>NOTE: Only the ship of the player has these", "displays", "displays handle or invalid handle on error") 364 { 365 object_h *objh; 366 cockpit_displays_h *cdh = NULL; 367 if(!ade_get_args(L, "o|o", l_Ship.GetPtr(&objh), l_CockpitDisplays.GetPtr(&cdh))) 368 return ade_set_error(L, "o", l_CockpitDisplays.Set(cockpit_displays_h())); 369 370 if(!objh->IsValid()) 371 return ade_set_error(L, "o", l_CockpitDisplays.Set(cockpit_displays_h())); 372 373 if(ADE_SETTING_VAR) 374 { 375 LuaError(L, "Attempted to use incomplete feature: Cockpit displays copy"); 376 } 377 378 return ade_set_args(L, "o", l_CockpitDisplays.Set(cockpit_displays_h(objh->objp))); 379 } 380 381 ADE_VIRTVAR(CountermeasureClass, l_Ship, "weaponclass", "Weapon class mounted on this ship's countermeasure point", "weaponclass", "Countermeasure hardpoint weapon class, or invalid weaponclass handle if no countermeasure class or ship handle is invalid") 382 { 383 object_h *objh; 384 int newcm = -1; 385 if(!ade_get_args(L, "o|o", l_Ship.GetPtr(&objh), l_Weaponclass.Get(&newcm))) 386 return ade_set_error(L, "o", l_Weaponclass.Set(-1));; 387 388 if(!objh->IsValid()) 389 return ade_set_error(L, "o", l_Weaponclass.Set(-1));; 390 391 ship *shipp = &Ships[objh->objp->instance]; 392 393 if(ADE_SETTING_VAR) { 394 shipp->current_cmeasure = newcm; 395 } 396 397 if(shipp->current_cmeasure > -1) 398 return ade_set_args(L, "o", l_Weaponclass.Set(shipp->current_cmeasure)); 399 else 400 return ade_set_error(L, "o", l_Weaponclass.Set(-1));; 401 } 402 403 ADE_VIRTVAR(HitpointsMax, l_Ship, "number", "Total hitpoints", "number", "Ship maximum hitpoints, or 0 if handle is invalid") 404 { 405 object_h *objh; 406 float newhits = -1; 407 if(!ade_get_args(L, "o|f", l_Ship.GetPtr(&objh), &newhits)) 408 return ade_set_error(L, "f", 0.0f); 409 410 if(!objh->IsValid()) 411 return ade_set_error(L, "f", 0.0f); 412 413 ship *shipp = &Ships[objh->objp->instance]; 414 415 if(ADE_SETTING_VAR && newhits > -1) 416 shipp->ship_max_hull_strength = newhits; 417 418 return ade_set_args(L, "f", shipp->ship_max_hull_strength); 419 } 420 421 ADE_VIRTVAR(ShieldRegenRate, l_Ship, "number", "Maximum percentage/100 of shield energy regenerated per second. For example, 0.02 = 2% recharge per second.", "number", "Ship maximum shield regeneration rate, or 0 if handle is invalid") 422 { 423 object_h *objh; 424 float new_shield_regen = -1; 425 if (!ade_get_args(L, "o|f", l_Ship.GetPtr(&objh), &new_shield_regen)) 426 return ade_set_error(L, "f", 0.0f); 427 428 if(!objh->IsValid()) 429 return ade_set_error(L, "f", 0.0f); 430 431 ship *shipp = &Ships[objh->objp->instance]; 432 433 if (ADE_SETTING_VAR && new_shield_regen > -1) 434 shipp->max_shield_regen_per_second = new_shield_regen; 435 436 return ade_set_args(L, "f", shipp->max_shield_regen_per_second); 437 } 438 439 ADE_VIRTVAR(WeaponRegenRate, l_Ship, "number", "Maximum percentage/100 of weapon energy regenerated per second. For example, 0.02 = 2% recharge per second.", "number", "Ship maximum weapon regeneration rate, or 0 if handle is invalid") 440 { 441 object_h *objh; 442 float new_weapon_regen = -1; 443 if (!ade_get_args(L, "o|f", l_Ship.GetPtr(&objh), &new_weapon_regen)) 444 return ade_set_error(L, "f", 0.0f); 445 446 if(!objh->IsValid()) 447 return ade_set_error(L, "f", 0.0f); 448 449 ship *shipp = &Ships[objh->objp->instance]; 450 451 if (ADE_SETTING_VAR && new_weapon_regen > -1) 452 shipp->max_weapon_regen_per_second = new_weapon_regen; 453 454 return ade_set_args(L, "f", shipp->max_weapon_regen_per_second); 455 } 456 457 ADE_VIRTVAR(WeaponEnergyLeft, l_Ship, "number", "Current weapon energy reserves", "number", "Ship current weapon energy reserve level, or 0 if invalid") 458 { 459 object_h *objh; 460 float neweng = -1; 461 if(!ade_get_args(L, "o|f", l_Ship.GetPtr(&objh), &neweng)) 462 return ade_set_error(L, "f", 0.0f); 463 464 if(!objh->IsValid()) 465 return ade_set_error(L, "f", 0.0f); 466 467 ship *shipp = &Ships[objh->objp->instance]; 468 469 if(ADE_SETTING_VAR && neweng > -1) 470 shipp->weapon_energy = neweng; 471 472 return ade_set_args(L, "f", shipp->weapon_energy); 473 } 474 475 ADE_VIRTVAR(WeaponEnergyMax, l_Ship, "number", "Maximum weapon energy", "number", "Ship maximum weapon energy reserve level, or 0 if invalid") 476 { 477 object_h *objh; 478 float neweng = -1; 479 if(!ade_get_args(L, "o|f", l_Ship.GetPtr(&objh), &neweng)) 480 return ade_set_error(L, "f", 0.0f); 481 482 if(!objh->IsValid()) 483 return ade_set_error(L, "f", 0.0f); 484 485 ship_info *sip = &Ship_info[Ships[objh->objp->instance].ship_info_index]; 486 487 if(ADE_SETTING_VAR && neweng > -1) 488 sip->max_weapon_reserve = neweng; 489 490 return ade_set_args(L, "f", sip->max_weapon_reserve); 491 } 492 493 ADE_VIRTVAR(AutoaimFOV, l_Ship, "number", "FOV of ship's autoaim, if any", "number", "FOV (in degrees), or 0 if ship uses no autoaim or if handle is invalid") 494 { 495 object_h *objh; 496 float fov = -1; 497 if(!ade_get_args(L, "o|f", l_Ship.GetPtr(&objh), &fov)) 498 return ade_set_error(L, "f", 0.0f); 499 500 if(!objh->IsValid()) 501 return ade_set_error(L, "f", 0.0f); 502 503 ship *shipp = &Ships[objh->objp->instance]; 504 505 if(ADE_SETTING_VAR && fov >= 0.0f) { 506 if (fov > 180.0) 507 fov = 180.0; 508 509 shipp->autoaim_fov = fov * PI / 180.0f; 510 } 511 512 return ade_set_args(L, "f", shipp->autoaim_fov * 180.0f / PI); 513 } 514 515 ADE_VIRTVAR(PrimaryTriggerDown, l_Ship, "boolean", "Determines if primary trigger is pressed or not", "boolean", "True if pressed, false if not, nil if ship handle is invalid") 516 { 517 object_h *objh; 518 bool trig = false; 519 if(!ade_get_args(L, "o|b", l_Ship.GetPtr(&objh), &trig)) 520 return ADE_RETURN_NIL; 521 522 if(!objh->IsValid()) 523 return ADE_RETURN_NIL; 524 525 ship *shipp = &Ships[objh->objp->instance]; 526 527 if(ADE_SETTING_VAR) 528 { 529 if(trig) 530 shipp->flags.set(Ship::Ship_Flags::Trigger_down); 531 else 532 shipp->flags.remove(Ship::Ship_Flags::Trigger_down); 533 } 534 535 if (shipp->flags[Ship::Ship_Flags::Trigger_down]) 536 return ADE_RETURN_TRUE; 537 else 538 return ADE_RETURN_FALSE; 539 } 540 541 542 ADE_VIRTVAR(PrimaryBanks, l_Ship, "weaponbanktype", "Array of primary weapon banks", "weaponbanktype", "Primary weapon banks, or invalid weaponbanktype handle if ship handle is invalid") 543 { 544 object_h *objh; 545 ship_banktype_h *swh = nullptr; 546 if(!ade_get_args(L, "o|o", l_Ship.GetPtr(&objh), l_WeaponBankType.GetPtr(&swh))) 547 return ade_set_error(L, "o", l_WeaponBankType.Set(ship_banktype_h())); 548 549 if(!objh->IsValid()) 550 return ade_set_error(L, "o", l_WeaponBankType.Set(ship_banktype_h())); 551 552 ship_weapon *dst = &Ships[objh->objp->instance].weapons; 553 554 if(ADE_SETTING_VAR && swh && swh->IsValid()) { 555 ship_weapon *src = &Ships[swh->objp->instance].weapons; 556 557 dst->current_primary_bank = src->current_primary_bank; 558 dst->num_primary_banks = src->num_primary_banks; 559 560 memcpy(dst->next_primary_fire_stamp, src->next_primary_fire_stamp, sizeof(dst->next_primary_fire_stamp)); 561 memcpy(dst->primary_animation_done_time, src->primary_animation_done_time, sizeof(dst->primary_animation_done_time)); 562 memcpy(dst->primary_animation_position, src->primary_animation_position, sizeof(dst->primary_animation_position)); 563 memcpy(dst->primary_bank_ammo, src->primary_bank_ammo, sizeof(dst->primary_bank_ammo)); 564 memcpy(dst->primary_bank_capacity, src->primary_bank_capacity, sizeof(dst->primary_bank_capacity)); 565 memcpy(dst->primary_bank_rearm_time, src->primary_bank_rearm_time, sizeof(dst->primary_bank_rearm_time)); 566 memcpy(dst->primary_bank_start_ammo, src->primary_bank_start_ammo, sizeof(dst->primary_bank_start_ammo)); 567 memcpy(dst->primary_bank_weapons, src->primary_bank_weapons, sizeof(dst->primary_bank_weapons)); 568 } 569 570 return ade_set_args(L, "o", l_WeaponBankType.Set(ship_banktype_h(objh->objp, dst, SWH_PRIMARY))); 571 } 572 573 ADE_VIRTVAR(SecondaryBanks, l_Ship, "weaponbanktype", "Array of secondary weapon banks", "weaponbanktype", "Secondary weapon banks, or invalid weaponbanktype handle if ship handle is invalid") 574 { 575 object_h *objh; 576 ship_banktype_h *swh = nullptr; 577 if(!ade_get_args(L, "o|o", l_Ship.GetPtr(&objh), l_WeaponBankType.GetPtr(&swh))) 578 return ade_set_error(L, "o", l_WeaponBankType.Set(ship_banktype_h())); 579 580 if(!objh->IsValid()) 581 return ade_set_error(L, "o", l_WeaponBankType.Set(ship_banktype_h())); 582 583 ship_weapon *dst = &Ships[objh->objp->instance].weapons; 584 585 if(ADE_SETTING_VAR && swh && swh->IsValid()) { 586 ship_weapon *src = &Ships[swh->objp->instance].weapons; 587 588 dst->current_secondary_bank = src->current_secondary_bank; 589 dst->num_secondary_banks = src->num_secondary_banks; 590 591 memcpy(dst->next_secondary_fire_stamp, src->next_secondary_fire_stamp, sizeof(dst->next_secondary_fire_stamp)); 592 memcpy(dst->secondary_animation_done_time, src->secondary_animation_done_time, sizeof(dst->secondary_animation_done_time)); 593 memcpy(dst->secondary_animation_position, src->secondary_animation_position, sizeof(dst->secondary_animation_position)); 594 memcpy(dst->secondary_bank_ammo, src->secondary_bank_ammo, sizeof(dst->secondary_bank_ammo)); 595 memcpy(dst->secondary_bank_capacity, src->secondary_bank_capacity, sizeof(dst->secondary_bank_capacity)); 596 memcpy(dst->secondary_bank_rearm_time, src->secondary_bank_rearm_time, sizeof(dst->secondary_bank_rearm_time)); 597 memcpy(dst->secondary_bank_start_ammo, src->secondary_bank_start_ammo, sizeof(dst->secondary_bank_start_ammo)); 598 memcpy(dst->secondary_bank_weapons, src->secondary_bank_weapons, sizeof(dst->secondary_bank_weapons)); 599 memcpy(dst->secondary_next_slot, src->secondary_next_slot, sizeof(dst->secondary_next_slot)); 600 } 601 602 return ade_set_args(L, "o", l_WeaponBankType.Set(ship_banktype_h(objh->objp, dst, SWH_SECONDARY))); 603 } 604 605 ADE_VIRTVAR(TertiaryBanks, l_Ship, "weaponbanktype", "Array of tertiary weapon banks", "weaponbanktype", "Tertiary weapon banks, or invalid weaponbanktype handle if ship handle is invalid") 606 { 607 object_h *objh; 608 ship_banktype_h *swh = nullptr; 609 if(!ade_get_args(L, "o|o", l_Ship.GetPtr(&objh), l_WeaponBankType.GetPtr(&swh))) 610 return ade_set_error(L, "o", l_WeaponBankType.Set(ship_banktype_h())); 611 612 if(!objh->IsValid()) 613 return ade_set_error(L, "o", l_WeaponBankType.Set(ship_banktype_h())); 614 615 ship_weapon *dst = &Ships[objh->objp->instance].weapons; 616 617 if(ADE_SETTING_VAR && swh && swh->IsValid()) { 618 ship_weapon *src = &Ships[swh->objp->instance].weapons; 619 620 dst->current_tertiary_bank = src->current_tertiary_bank; 621 dst->num_tertiary_banks = src->num_tertiary_banks; 622 623 dst->next_tertiary_fire_stamp = src->next_tertiary_fire_stamp; 624 dst->tertiary_bank_ammo = src->tertiary_bank_ammo; 625 dst->tertiary_bank_capacity = src->tertiary_bank_capacity; 626 dst->tertiary_bank_rearm_time = src->tertiary_bank_rearm_time; 627 dst->tertiary_bank_start_ammo = src->tertiary_bank_start_ammo; 628 } 629 630 return ade_set_args(L, "o", l_WeaponBankType.Set(ship_banktype_h(objh->objp, dst, SWH_TERTIARY))); 631 } 632 633 ADE_VIRTVAR(Target, l_Ship, "object", "Target of ship. Value may also be a deriviative of the 'object' class, such as 'ship'.", "object", "Target object, or invalid object handle if no target or ship handle is invalid") 634 { 635 object_h *objh; 636 object_h *newh = nullptr; 637 //WMC - Maybe use two argument return capabilities of Lua to set/return subsystem? 638 if(!ade_get_args(L, "o|o", l_Ship.GetPtr(&objh), l_Object.GetPtr(&newh))) 639 return ade_set_error(L, "o", l_Object.Set(object_h())); 640 641 if(!objh->IsValid()) 642 return ade_set_error(L, "o", l_Object.Set(object_h())); 643 644 ai_info *aip = NULL; 645 if(Ships[objh->objp->instance].ai_index > -1) 646 aip = &Ai_info[Ships[objh->objp->instance].ai_index]; 647 else 648 return ade_set_error(L, "o", l_Object.Set(object_h())); 649 650 if(ADE_SETTING_VAR && newh) 651 { 652 if(aip->target_signature != newh->sig) 653 { 654 if(newh->IsValid()) 655 { 656 aip->target_objnum = OBJ_INDEX(newh->objp); 657 aip->target_signature = newh->sig; 658 aip->target_time = 0.0f; 659 660 if (aip == Player_ai) 661 hud_shield_hit_reset(newh->objp); 662 } 663 else 664 { 665 aip->target_objnum = -1; 666 aip->target_signature = -1; 667 aip->target_time = 0.0f; 668 } 669 670 set_targeted_subsys(aip, NULL, -1); 671 } 672 } 673 674 return ade_set_object_with_breed(L, aip->target_objnum); 675 } 676 677 ADE_VIRTVAR(TargetSubsystem, l_Ship, "subsystem", "Target subsystem of ship.", "subsystem", "Target subsystem, or invalid subsystem handle if no target or ship handle is invalid") 678 { 679 object_h *oh; 680 ship_subsys_h *newh = nullptr; 681 //WMC - Maybe use two argument return capabilities of Lua to set/return subsystem? 682 if(!ade_get_args(L, "o|o", l_Ship.GetPtr(&oh), l_Subsystem.GetPtr(&newh))) 683 return ade_set_error(L, "o", l_Subsystem.Set(ship_subsys_h())); 684 685 if(!oh->IsValid()) 686 return ade_set_error(L, "o", l_Subsystem.Set(ship_subsys_h())); 687 688 ai_info *aip = NULL; 689 if(Ships[oh->objp->instance].ai_index > -1) 690 aip = &Ai_info[Ships[oh->objp->instance].ai_index]; 691 else 692 return ade_set_error(L, "o", l_Subsystem.Set(ship_subsys_h())); 693 694 if(ADE_SETTING_VAR) 695 { 696 if(newh && newh->isSubsystemValid()) 697 { 698 if (aip == Player_ai) { 699 if (aip->target_signature != newh->sig) 700 hud_shield_hit_reset(newh->objp); 701 702 Ships[Objects[newh->ss->parent_objnum].instance].last_targeted_subobject[Player_num] = newh->ss; 703 } 704 705 aip->target_objnum = OBJ_INDEX(newh->objp); 706 aip->target_signature = newh->sig; 707 aip->target_time = 0.0f; 708 set_targeted_subsys(aip, newh->ss, aip->target_objnum); 709 } 710 else 711 { 712 aip->target_objnum = -1; 713 aip->target_signature = -1; 714 aip->target_time = 0.0f; 715 716 set_targeted_subsys(aip, NULL, -1); 717 } 718 } 719 720 return ade_set_args(L, "o", l_Subsystem.Set(ship_subsys_h(&Objects[aip->target_objnum], aip->targeted_subsys))); 721 } 722 723 ADE_VIRTVAR(Team, l_Ship, "team", "Ship's team", "team", "Ship team, or invalid team handle if ship handle is invalid") 724 { 725 object_h *oh=NULL; 726 int nt=-1; 727 if(!ade_get_args(L, "o|o", l_Ship.GetPtr(&oh), l_Team.Get(&nt))) 728 return ade_set_error(L, "o", l_Team.Set(-1)); 729 730 if(!oh->IsValid()) 731 return ade_set_error(L, "o", l_Team.Set(-1)); 732 733 ship *shipp = &Ships[oh->objp->instance]; 734 735 if(ADE_SETTING_VAR && nt > -1) { 736 shipp->team = nt; 737 } 738 739 return ade_set_args(L, "o", l_Team.Set(shipp->team)); 740 } 741 742 ADE_VIRTVAR(Textures, l_Ship, "shiptextures", "Gets ship textures", "shiptextures", "Ship textures, or invalid shiptextures handle if ship handle is invalid") 743 { 744 object_h *sh = nullptr; 745 object_h *dh; 746 if(!ade_get_args(L, "o|o", l_Ship.GetPtr(&dh), l_Ship.GetPtr(&sh))) 747 return ade_set_error(L, "o", l_ShipTextures.Set(object_h())); 748 749 if(!dh->IsValid()) 750 return ade_set_error(L, "o", l_ShipTextures.Set(object_h())); 751 752 if(ADE_SETTING_VAR && sh && sh->IsValid()) { 753 ship *src = &Ships[sh->objp->instance]; 754 ship *dest = &Ships[dh->objp->instance]; 755 756 if (src->ship_replacement_textures != NULL) 757 { 758 if (dest->ship_replacement_textures == NULL) 759 dest->ship_replacement_textures = (int *) vm_malloc(MAX_REPLACEMENT_TEXTURES * sizeof(int)); 760 761 memcpy(dest->ship_replacement_textures, src->ship_replacement_textures, MAX_REPLACEMENT_TEXTURES * sizeof(int)); 762 } 763 } 764 765 return ade_set_args(L, "o", l_ShipTextures.Set(object_h(dh->objp))); 766 } 767 768 ADE_VIRTVAR(FlagAffectedByGravity, l_Ship, "boolean", "Checks for the \"affected-by-gravity\" flag", "boolean", "True if flag is set, false if flag is not set and nil on error") 769 { 770 object_h *objh=NULL; 771 bool set = false; 772 773 if (!ade_get_args(L, "o|b", l_Ship.GetPtr(&objh), &set)) 774 return ADE_RETURN_NIL; 775 776 if (!objh->IsValid()) 777 return ADE_RETURN_NIL; 778 779 ship *shipp = &Ships[objh->objp->instance]; 780 781 if(ADE_SETTING_VAR) 782 { 783 shipp->flags.set(Ship::Ship_Flags::Affected_by_gravity, set); 784 } 785 786 if (shipp->flags[Ship::Ship_Flags::Affected_by_gravity]) 787 return ADE_RETURN_TRUE; 788 else 789 return ADE_RETURN_FALSE; 790 } 791 792 ADE_VIRTVAR(Disabled, l_Ship, "boolean", "The disabled state of this ship", "boolean", "true if ship is diabled, false otherwise") 793 { 794 object_h *objh=NULL; 795 bool set = false; 796 797 if (!ade_get_args(L, "o|b", l_Ship.GetPtr(&objh), &set)) 798 return ADE_RETURN_FALSE; 799 800 if (!objh->IsValid()) 801 return ADE_RETURN_FALSE; 802 803 ship *shipp = &Ships[objh->objp->instance]; 804 805 if(ADE_SETTING_VAR) 806 { 807 shipp->flags.set(Ship::Ship_Flags::Disabled, set); 808 if(set) 809 { 810 mission_log_add_entry(LOG_SHIP_DISABLED, shipp->ship_name, NULL ); 811 } 812 else 813 { 814 ship_reset_disabled_physics( &Objects[shipp->objnum], shipp->ship_info_index ); 815 } 816 } 817 818 if (shipp->flags[Ship::Ship_Flags::Disabled]) 819 return ADE_RETURN_TRUE; 820 else 821 return ADE_RETURN_FALSE; 822 } 823 824 ADE_VIRTVAR(Stealthed, l_Ship, "boolean", "Stealth status of this ship", "boolean", "true if stealthed, false otherwise or on error") 825 { 826 object_h *objh=NULL; 827 bool stealthed = false; 828 829 if (!ade_get_args(L, "o|b", l_Ship.GetPtr(&objh), &stealthed)) 830 return ADE_RETURN_FALSE; 831 832 if (!objh->IsValid()) 833 return ADE_RETURN_FALSE; 834 835 ship *shipp = &Ships[objh->objp->instance]; 836 837 if(ADE_SETTING_VAR) 838 { 839 shipp->flags.set(Ship::Ship_Flags::Stealth, stealthed); 840 } 841 842 if (shipp->flags[Ship::Ship_Flags::Stealth]) 843 return ADE_RETURN_TRUE; 844 else 845 return ADE_RETURN_FALSE; 846 } 847 848 ADE_VIRTVAR(HiddenFromSensors, l_Ship, "boolean", "Hidden from sensors status of this ship", "boolean", "true if invisible to hidden from sensors, false otherwise or on error") 849 { 850 object_h *objh=NULL; 851 bool hidden = false; 852 853 if (!ade_get_args(L, "o|b", l_Ship.GetPtr(&objh), &hidden)) 854 return ADE_RETURN_FALSE; 855 856 if (!objh->IsValid()) 857 return ADE_RETURN_FALSE; 858 859 ship *shipp = &Ships[objh->objp->instance]; 860 861 if(ADE_SETTING_VAR) 862 { 863 shipp->flags.set(Ship::Ship_Flags::Hidden_from_sensors, hidden); 864 } 865 866 if (shipp->flags[Ship::Ship_Flags::Hidden_from_sensors]) 867 return ADE_RETURN_TRUE; 868 else 869 return ADE_RETURN_FALSE; 870 } 871 872 ADE_VIRTVAR(Gliding, l_Ship, "boolean", "Specifies whether this ship is currently gliding or not.", "boolean", "true if gliding, false otherwise or in case of error") 873 { 874 object_h *objh=NULL; 875 bool gliding = false; 876 877 if (!ade_get_args(L, "o|b", l_Ship.GetPtr(&objh), &gliding)) 878 return ADE_RETURN_FALSE; 879 880 if (!objh->IsValid()) 881 return ADE_RETURN_FALSE; 882 883 ship *shipp = &Ships[objh->objp->instance]; 884 885 if(ADE_SETTING_VAR) 886 { 887 if (Ship_info[shipp->ship_info_index].can_glide) 888 { 889 object_set_gliding(&Objects[shipp->objnum], gliding, true); 890 } 891 } 892 893 if (objh->objp->phys_info.flags & PF_GLIDING || objh->objp->phys_info.flags & PF_FORCE_GLIDE) 894 return ADE_RETURN_TRUE; 895 else 896 return ADE_RETURN_FALSE; 897 } 898 899 ADE_VIRTVAR(EtsEngineIndex, l_Ship, "number", "(SET not implemented, see EtsSetIndexes)", "number", "Ships ETS Engine index value, 0 to MAX_ENERGY_INDEX") 900 { 901 object_h *objh=NULL; 902 int ets_idx = 0; 903 904 if (!ade_get_args(L, "o|i", l_Ship.GetPtr(&objh), &ets_idx)) 905 return ade_set_error(L, "i", 0); 906 907 if (!objh->IsValid()) 908 return ade_set_error(L, "i", 0); 909 910 if(ADE_SETTING_VAR) 911 LuaError(L, "Attempted to set incomplete feature: ETS Engine Index (see EtsSetIndexes)"); 912 913 return ade_set_args(L, "i", Ships[objh->objp->instance].engine_recharge_index); 914 } 915 916 ADE_VIRTVAR(EtsShieldIndex, l_Ship, "number", "(SET not implemented, see EtsSetIndexes)", "number", "Ships ETS Shield index value, 0 to MAX_ENERGY_INDEX") 917 { 918 object_h *objh=NULL; 919 int ets_idx = 0; 920 921 if (!ade_get_args(L, "o|i", l_Ship.GetPtr(&objh), &ets_idx)) 922 return ade_set_error(L, "i", 0); 923 924 if (!objh->IsValid()) 925 return ade_set_error(L, "i", 0); 926 927 if(ADE_SETTING_VAR) 928 LuaError(L, "Attempted to set incomplete feature: ETS Shield Index (see EtsSetIndexes)"); 929 930 return ade_set_args(L, "i", Ships[objh->objp->instance].shield_recharge_index); 931 } 932 933 ADE_VIRTVAR(EtsWeaponIndex, l_Ship, "number", "(SET not implemented, see EtsSetIndexes)", "number", "Ships ETS Weapon index value, 0 to MAX_ENERGY_INDEX") 934 { 935 object_h *objh=NULL; 936 int ets_idx = 0; 937 938 if (!ade_get_args(L, "o|i", l_Ship.GetPtr(&objh), &ets_idx)) 939 return ade_set_error(L, "i", 0); 940 941 if (!objh->IsValid()) 942 return ade_set_error(L, "i", 0); 943 944 if(ADE_SETTING_VAR) 945 LuaError(L, "Attempted to set incomplete feature: ETS Weapon Index (see EtsSetIndexes)"); 946 947 return ade_set_args(L, "i", Ships[objh->objp->instance].weapon_recharge_index); 948 } 949 950 ADE_VIRTVAR(Orders, l_Ship, "shiporders", "Array of ship orders", "shiporders", "Ship orders, or invalid handle if ship handle is invalid") 951 { 952 object_h *objh = NULL; 953 object_h *newh = NULL; 954 if(!ade_get_args(L, "o|o", l_Ship.GetPtr(&objh), l_ShipOrders.GetPtr(&newh))) 955 return ade_set_error(L, "o", l_ShipOrders.Set(object_h())); 956 957 if(!objh->IsValid()) 958 return ade_set_error(L, "o", l_ShipOrders.Set(object_h()));; 959 960 if(ADE_SETTING_VAR) 961 { 962 LuaError(L, "Attempted to use incomplete feature: Ai orders copy. Use giveOrder instead"); 963 } 964 965 return ade_set_args(L, "o", l_ShipOrders.Set(object_h(objh->objp))); 966 } 967 968 ADE_FUNC(getCenterPosition, l_Ship, nullptr, "Returns the position of the ship's physical center, which may not be the position of the origin of the model", "vector", "World position of the center of the ship, or nil if an error occurred") 969 { 970 object_h *shiph; 971 vec3d center_pos, actual_local_center; 972 973 if (!ade_get_args(L, "o", l_Ship.GetPtr(&shiph))) 974 return ADE_RETURN_NIL; 975 976 // find local center 977 ship_class_get_actual_center(&Ship_info[Ships[shiph->objp->instance].ship_info_index], &actual_local_center); 978 979 // find world position of the center 980 vm_vec_unrotate(¢er_pos, &actual_local_center, &shiph->objp->orient); 981 vm_vec_add2(¢er_pos, &shiph->objp->pos); 982 983 return ade_set_args(L, "o", l_Vector.Set(center_pos)); 984 } 985 986 ADE_FUNC(kill, l_Ship, "[object Killer, vector Hitpos]", "Kills the ship. Set \"Killer\" to a ship (or a weapon fired by that ship) to credit it for the kill in the mission log. Set it to the ship being killed to self-destruct. Set \"Hitpos\" to the world coordinates of the weapon impact.", "boolean", "True if successful, false or nil otherwise") 987 { 988 object_h *victim, *killer = nullptr; 989 vec3d *hitpos = nullptr; 990 if(!ade_get_args(L, "o|oo", l_Ship.GetPtr(&victim), l_Object.GetPtr(&killer), l_Vector.GetPtr(&hitpos))) 991 return ADE_RETURN_NIL; 992 993 if(!victim->IsValid()) 994 return ADE_RETURN_NIL; 995 996 if(killer && !killer->IsValid()) 997 return ADE_RETURN_NIL; 998 999 // use the current hull percentage for damage-after-death purposes 1000 // (note that this does not actually affect scoring) 1001 float percent_killed = get_hull_pct(victim->objp); 1002 1003 ship_hit_kill(victim->objp, killer ? killer->objp : nullptr, hitpos, percent_killed, (killer && victim->sig == killer->sig), true); 1004 1005 return ADE_RETURN_TRUE; 1006 } 1007 1008 ADE_FUNC(addShipEffect, l_Ship, "string name, number durationMillis", "Activates an effect for this ship. Effect names are defined in Post_processing.tbl, and need to be implemented in the main shader. This functions analogous to the ship-effect sexp. NOTE: only one effect can be active at any time, adding new effects will override effects already in progress.\n", "boolean", "Returns true if the effect was successfully added, false otherwise") { 1009 object_h *shiph; 1010 const char* effect = nullptr; 1011 int duration; 1012 int effect_num; 1013 1014 if (!ade_get_args(L, "o|si", l_Ship.GetPtr(&shiph), &effect, &duration)) 1015 return ade_set_error(L, "b", false); 1016 1017 if (!shiph->IsValid()) 1018 return ade_set_error(L, "b", false); 1019 1020 effect_num = get_effect_from_name(effect); 1021 if (effect_num == -1) 1022 return ade_set_error(L, "b", false); 1023 1024 ship* shipp = &Ships[shiph->objp->instance]; 1025 1026 shipp->shader_effect_active = true; 1027 shipp->shader_effect_num = effect_num; 1028 shipp->shader_effect_duration = duration; 1029 shipp->shader_effect_start_time = timer_get_milliseconds(); 1030 1031 return ade_set_args(L, "b", true); 1032 } 1033 1034 ADE_FUNC(hasShipExploded, l_Ship, NULL, "Checks if the ship explosion event has already happened", "number", "Returns 1 if first explosion timestamp is passed, 2 if second is passed, 0 otherwise") 1035 { 1036 object_h *shiph; 1037 if(!ade_get_args(L, "o", l_Ship.GetPtr(&shiph))) 1038 return ade_set_error(L, "i", 0); 1039 1040 if(!shiph->IsValid()) 1041 return ade_set_error(L, "i", 0); 1042 1043 ship *shipp = &Ships[shiph->objp->instance]; 1044 1045 if (shipp->flags[Ship::Ship_Flags::Dying]) { 1046 if (shipp->final_death_time == 0) { 1047 return ade_set_args(L, "i", 2); 1048 } 1049 if (shipp->pre_death_explosion_happened == 1) { 1050 return ade_set_args(L, "i", 1); 1051 } 1052 return ade_set_args(L, "i", 3); 1053 } 1054 1055 return ade_set_args(L, "i", 0); 1056 } 1057 1058 ADE_FUNC(isDepartingWarp, l_Ship, nullptr, "Checks if the ship is departing via warp", "boolean", "True if the Depart_warp flag is set, false otherwise") 1059 { 1060 object_h *shiph; 1061 if (!ade_get_args(L, "o", l_Ship.GetPtr(&shiph))) 1062 return ade_set_error(L, "b", false); 1063 1064 if (!shiph->IsValid()) 1065 return ade_set_error(L, "b", false); 1066 1067 ship *shipp = &Ships[shiph->objp->instance]; 1068 1069 return ade_set_args(L, "b", shipp->flags[Ship::Ship_Flags::Depart_warp]); 1070 } 1071 1072 ADE_FUNC(isDepartingDockbay, l_Ship, nullptr, "Checks if the ship is departing via warp", "boolean", "True if the Depart_dockbay flag is set, false otherwise") 1073 { 1074 object_h *shiph; 1075 if (!ade_get_args(L, "o", l_Ship.GetPtr(&shiph))) 1076 return ade_set_error(L, "b", false); 1077 1078 if (!shiph->IsValid()) 1079 return ade_set_error(L, "b", false); 1080 1081 ship *shipp = &Ships[shiph->objp->instance]; 1082 1083 return ade_set_args(L, "b", shipp->flags[Ship::Ship_Flags::Depart_dockbay]); 1084 } 1085 1086 ADE_FUNC(isDying, l_Ship, nullptr, "Checks if the ship is dying (doing its death roll or exploding)", "boolean", "True if the Dying flag is set, false otherwise") 1087 { 1088 object_h *shiph; 1089 if (!ade_get_args(L, "o", l_Ship.GetPtr(&shiph))) 1090 return ade_set_error(L, "b", false); 1091 1092 if (!shiph->IsValid()) 1093 return ade_set_error(L, "b", false); 1094 1095 ship *shipp = &Ships[shiph->objp->instance]; 1096 1097 return ade_set_args(L, "b", shipp->flags[Ship::Ship_Flags::Dying]); 1098 } 1099 1100 ADE_FUNC(fireCountermeasure, l_Ship, NULL, "Launches a countermeasure from the ship", "boolean", "Whether countermeasure was launched or not") 1101 { 1102 object_h *objh; 1103 if(!ade_get_args(L, "o", l_Ship.GetPtr(&objh))) 1104 return ade_set_error(L, "b", false); 1105 1106 if(!objh->IsValid()) 1107 return ade_set_error(L, "b", false); 1108 1109 return ade_set_args(L, "b", ship_launch_countermeasure(objh->objp) != 0); 1110 } 1111 1112 ADE_FUNC(firePrimary, l_Ship, NULL, "Fires ship primary bank(s)", "number", "Number of primary banks fired") 1113 { 1114 object_h *objh; 1115 if(!ade_get_args(L, "o", l_Ship.GetPtr(&objh))) 1116 return ade_set_error(L, "i", 0); 1117 1118 if(!objh->IsValid()) 1119 return ade_set_error(L, "i", 0); 1120 1121 int i = 0; 1122 i += ship_fire_primary(objh->objp, 0); 1123 i += ship_fire_primary(objh->objp, 1); 1124 1125 return ade_set_args(L, "i", i); 1126 } 1127 1128 ADE_FUNC(fireSecondary, l_Ship, NULL, "Fires ship secondary bank(s)", "number", "Number of secondary banks fired") 1129 { 1130 object_h *objh; 1131 if(!ade_get_args(L, "o", l_Ship.GetPtr(&objh))) 1132 return ade_set_error(L, "i", 0); 1133 1134 if(!objh->IsValid()) 1135 return ade_set_error(L, "i", 0); 1136 1137 return ade_set_args(L, "i", ship_fire_secondary(objh->objp, 0)); 1138 } 1139 1140 ADE_FUNC(getAnimationDoneTime, l_Ship, "number Type, number Subtype", "Gets time that animation will be done", "number", "Time (seconds), or 0 if ship handle is invalid") 1141 { 1142 object_h *objh; 1143 const char* s = nullptr; 1144 int subtype=-1; 1145 if(!ade_get_args(L, "o|si", l_Ship.GetPtr(&objh), &s, &subtype)) 1146 return ade_set_error(L, "f", 0.0f); 1147 1148 if(!objh->IsValid()) 1149 return ade_set_error(L, "f", 0.0f); 1150 1151 auto type = model_anim_match_type(s); 1152 if(type == AnimationTriggerType::None) 1153 return ADE_RETURN_FALSE; 1154 1155 int time_ms = model_anim_get_time_type(&Ships[objh->objp->instance], type, subtype); 1156 float time_s = (float)time_ms / 1000.0f; 1157 1158 return ade_set_args(L, "f", time_s); 1159 } 1160 1161 ADE_FUNC(clearOrders, l_Ship, NULL, "Clears a ship's orders list", "boolean", "True if successful, otherwise false or nil") 1162 { 1163 object_h *objh = NULL; 1164 if(!ade_get_args(L, "o", l_Object.GetPtr(&objh))) 1165 return ADE_RETURN_NIL; 1166 if(!objh->IsValid()) 1167 return ade_set_error(L, "b", false); 1168 1169 //The actual clearing of the goals 1170 ai_clear_ship_goals( &Ai_info[Ships[objh->objp->instance].ai_index]); 1171 1172 return ADE_RETURN_TRUE; 1173 } 1174 1175 ADE_FUNC(giveOrder, l_Ship, "enumeration Order, [object Target=nil, subsystem TargetSubsystem=nil, number Priority=1.0, shipclass TargetShipclass=nil]", "Uses the goal code to execute orders", "boolean", "True if order was given, otherwise false or nil") 1176 { 1177 object_h *objh = NULL; 1178 enum_h *eh = NULL; 1179 float priority = 1.0f; 1180 int sclass = -1; 1181 object_h *tgh = NULL; 1182 ship_subsys_h *tgsh = NULL; 1183 if(!ade_get_args(L, "oo|oofo", l_Object.GetPtr(&objh), l_Enum.GetPtr(&eh), l_Object.GetPtr(&tgh), l_Subsystem.GetPtr(&tgsh), &priority, l_Shipclass.Get(&sclass))) 1184 return ADE_RETURN_NIL; 1185 1186 if(!objh->IsValid() || !eh->IsValid()) 1187 return ade_set_error(L, "b", false); 1188 1189 //wtf... 1190 if(priority < 0.0f) 1191 return ade_set_error(L, "b", false); 1192 1193 if(priority > 1.0f) 1194 priority = 1.0f; 1195 1196 bool tgh_valid = tgh && tgh->IsValid(); 1197 bool tgsh_valid = tgsh && tgsh->isSubsystemValid(); 1198 int ai_mode = AI_GOAL_NONE; 1199 int ai_submode = -1234567; 1200 char *ai_shipname = NULL; 1201 switch(eh->index) 1202 { 1203 case LE_ORDER_ATTACK: 1204 { 1205 if(tgsh_valid) 1206 { 1207 ai_mode = AI_GOAL_DESTROY_SUBSYSTEM; 1208 ai_shipname = Ships[tgh->objp->instance].ship_name; 1209 ai_submode = ship_get_subsys_index( &Ships[tgsh->objp->instance], tgsh->ss->system_info->subobj_name ); 1210 } 1211 else if(tgh_valid && tgh->objp->type == OBJ_WEAPON) 1212 { 1213 ai_mode = AI_GOAL_CHASE_WEAPON; 1214 ai_submode = tgh->objp->instance; 1215 } 1216 else if(tgh_valid && tgh->objp->type == OBJ_SHIP) 1217 { 1218 ai_mode = AI_GOAL_CHASE; 1219 ai_shipname = Ships[tgh->objp->instance].ship_name; 1220 ai_submode = SM_ATTACK; 1221 } 1222 break; 1223 } 1224 case LE_ORDER_DOCK: 1225 { 1226 ai_shipname = Ships[tgh->objp->instance].ship_name; 1227 ai_mode = AI_GOAL_DOCK; 1228 ai_submode = AIS_DOCK_0; 1229 break; 1230 } 1231 case LE_ORDER_WAYPOINTS: 1232 { 1233 if(tgh_valid && tgh->objp->type == OBJ_WAYPOINT) 1234 { 1235 ai_mode = AI_GOAL_WAYPOINTS; 1236 waypoint_list *wp_list = find_waypoint_list_with_instance(tgh->objp->instance); 1237 if(wp_list != NULL) 1238 ai_shipname = wp_list->get_name(); 1239 } 1240 break; 1241 } 1242 case LE_ORDER_WAYPOINTS_ONCE: 1243 { 1244 if(tgh_valid && tgh->objp->type == OBJ_WAYPOINT) 1245 { 1246 ai_mode = AI_GOAL_WAYPOINTS_ONCE; 1247 waypoint_list *wp_list = find_waypoint_list_with_instance(tgh->objp->instance); 1248 if(wp_list != NULL) 1249 ai_shipname = wp_list->get_name(); 1250 } 1251 break; 1252 } 1253 case LE_ORDER_DEPART: 1254 { 1255 ai_mode = AI_GOAL_WARP; 1256 ai_submode = -1; 1257 break; 1258 } 1259 case LE_ORDER_FORM_ON_WING: 1260 { 1261 if(tgh_valid && tgh->objp->type == OBJ_SHIP) 1262 { 1263 ai_mode = AI_GOAL_FORM_ON_WING; 1264 ai_shipname = Ships[tgh->objp->instance].ship_name; 1265 ai_submode = 0; 1266 } 1267 break; 1268 } 1269 case LE_ORDER_UNDOCK: 1270 { 1271 ai_mode = AI_GOAL_UNDOCK; 1272 ai_submode = AIS_UNDOCK_0; 1273 1274 if(tgh_valid && tgh->objp->type == OBJ_SHIP) 1275 { 1276 ai_shipname = Ships[tgh->objp->instance].ship_name; 1277 } 1278 break; 1279 } 1280 case LE_ORDER_GUARD: 1281 { 1282 if(tgh_valid && tgh->objp->type == OBJ_SHIP) 1283 { 1284 ai_mode = AI_GOAL_GUARD; 1285 ai_submode = AIS_GUARD_PATROL; 1286 ai_shipname = Ships[tgh->objp->instance].ship_name; 1287 } 1288 break; 1289 } 1290 case LE_ORDER_DISABLE: 1291 { 1292 if(tgh_valid && tgh->objp->type == OBJ_SHIP) 1293 { 1294 ai_mode = AI_GOAL_DISABLE_SHIP; 1295 ai_submode = -SUBSYSTEM_ENGINE; 1296 ai_shipname = Ships[tgh->objp->instance].ship_name; 1297 } 1298 break; 1299 } 1300 case LE_ORDER_DISARM: 1301 { 1302 if(tgh_valid && tgh->objp->type == OBJ_SHIP) 1303 { 1304 ai_mode = AI_GOAL_DISARM_SHIP; 1305 ai_submode = -SUBSYSTEM_TURRET; 1306 ai_shipname = Ships[tgh->objp->instance].ship_name; 1307 } 1308 break; 1309 } 1310 case LE_ORDER_ATTACK_ANY: 1311 { 1312 ai_mode = AI_GOAL_CHASE_ANY; 1313 ai_submode = SM_ATTACK; 1314 break; 1315 } 1316 case LE_ORDER_IGNORE: 1317 { 1318 if(tgh_valid && tgh->objp->type == OBJ_SHIP) 1319 { 1320 ai_mode = AI_GOAL_IGNORE_NEW; 1321 ai_submode = 0; 1322 ai_shipname = Ships[tgh->objp->instance].ship_name; 1323 } 1324 break; 1325 } 1326 case LE_ORDER_EVADE: 1327 { 1328 if(tgh_valid && tgh->objp->type == OBJ_SHIP) 1329 { 1330 ai_mode = AI_GOAL_EVADE_SHIP; 1331 ai_shipname = Ships[tgh->objp->instance].ship_name; 1332 } 1333 break; 1334 } 1335 case LE_ORDER_STAY_NEAR: 1336 { 1337 if(tgh_valid && tgh->objp->type == OBJ_SHIP) 1338 { 1339 ai_mode = AI_GOAL_STAY_NEAR_SHIP; 1340 ai_shipname = Ships[tgh->objp->instance].ship_name; 1341 ai_submode = -1; 1342 } 1343 break; 1344 } 1345 case LE_ORDER_KEEP_SAFE_DISTANCE: 1346 { 1347 if(tgh_valid && tgh->objp->type == OBJ_SHIP) 1348 { 1349 ai_mode = AI_GOAL_KEEP_SAFE_DISTANCE; 1350 ai_shipname = Ships[tgh->objp->instance].ship_name; 1351 ai_submode = -1; 1352 } 1353 break; 1354 } 1355 case LE_ORDER_REARM: 1356 { 1357 if(tgh_valid && tgh->objp->type == OBJ_SHIP) 1358 { 1359 ai_mode = AI_GOAL_REARM_REPAIR; 1360 ai_shipname = Ships[tgh->objp->instance].ship_name; 1361 ai_submode = 0; 1362 } 1363 break; 1364 } 1365 case LE_ORDER_STAY_STILL: 1366 { 1367 ai_mode = AI_GOAL_STAY_STILL; 1368 if(tgh_valid && tgh->objp->type == OBJ_SHIP) 1369 { 1370 ai_shipname = Ships[tgh->objp->instance].ship_name; 1371 } 1372 break; 1373 } 1374 case LE_ORDER_PLAY_DEAD: 1375 { 1376 ai_mode = AI_GOAL_PLAY_DEAD; 1377 break; 1378 } 1379 case LE_ORDER_PLAY_DEAD_PERSISTENT: 1380 { 1381 ai_mode = AI_GOAL_PLAY_DEAD_PERSISTENT; 1382 break; 1383 } 1384 case LE_ORDER_FLY_TO: 1385 { 1386 if(tgh_valid && tgh->objp->type == OBJ_SHIP) 1387 { 1388 ai_mode = AI_GOAL_FLY_TO_SHIP; 1389 ai_shipname = Ships[tgh->objp->instance].ship_name; 1390 ai_submode = 0; 1391 } 1392 break; 1393 } 1394 case LE_ORDER_ATTACK_WING: 1395 { 1396 if(tgh_valid && tgh->objp->type == OBJ_SHIP) 1397 { 1398 ship *shipp = &Ships[tgh->objp->instance]; 1399 if (shipp->wingnum != -1) 1400 { 1401 ai_mode = AI_GOAL_CHASE_WING; 1402 ai_shipname = Wings[shipp->wingnum].name; 1403 ai_submode = SM_ATTACK; 1404 } 1405 } 1406 break; 1407 } 1408 case LE_ORDER_GUARD_WING: 1409 { 1410 if(tgh_valid && tgh->objp->type == OBJ_SHIP) 1411 { 1412 ship *shipp = &Ships[tgh->objp->instance]; 1413 if (shipp->wingnum != -1) 1414 { 1415 ai_mode = AI_GOAL_GUARD_WING; 1416 ai_shipname = Wings[shipp->wingnum].name; 1417 ai_submode = AIS_GUARD_STATIC; 1418 } 1419 } 1420 break; 1421 } 1422 case LE_ORDER_ATTACK_SHIP_CLASS: 1423 { 1424 if(sclass >= 0) 1425 { 1426 ai_mode = AI_GOAL_CHASE_SHIP_CLASS; 1427 ai_shipname = Ship_info[sclass].name; 1428 ai_submode = SM_ATTACK; 1429 } 1430 break; 1431 } 1432 } 1433 1434 //Nothing got set! 1435 if(ai_mode == AI_GOAL_NONE) 1436 return ade_set_error(L, "b", false); 1437 1438 //Fire off the goal 1439 ai_add_ship_goal_scripting(ai_mode, ai_submode, (int)(priority*100.0f), ai_shipname, &Ai_info[Ships[objh->objp->instance].ai_index]); 1440 1441 return ADE_RETURN_TRUE; 1442 } 1443 1444 ADE_FUNC(doManeuver, 1445 l_Ship, 1446 "number Duration, number Heading, number Pitch, number Bank, boolean ApplyAllRotation, number Vertical, number " 1447 "Sideways, number Forward, boolean ApplyAllMovement, number ManeuverBitfield", 1448 "Sets ship maneuver over the defined time period", 1449 "boolean", 1450 "True if maneuver order was given, otherwise false or nil") 1451 { 1452 object_h *objh; 1453 float heading, pitch, bank, up, sideways, forward; 1454 bool apply_all_rotate = false, apply_all_move = false; 1455 int duration, maneuver_flags = 0; 1456 if(!ade_get_args(L, "oifffbfffb|i", l_Ship.GetPtr(&objh), &duration, &heading, &pitch, &bank, &apply_all_rotate, &up, &sideways, &forward, &apply_all_move, &maneuver_flags)) 1457 return ADE_RETURN_NIL; 1458 1459 ship *shipp = &Ships[objh->objp->instance]; 1460 ai_info *aip = &Ai_info[shipp->ai_index]; 1461 control_info *cip = &aip->ai_override_ci; 1462 1463 if (!(maneuver_flags & CIF_DONT_OVERRIDE_OLD_MANEUVERS)) { 1464 aip->ai_override_flags.reset(); 1465 } 1466 1467 bool applied_rot = false; 1468 bool applied_lat = false; 1469 if (apply_all_rotate) { 1470 aip->ai_override_flags.set(AI::Maneuver_Override_Flags::Full_rot); 1471 cip->heading = heading; 1472 cip->pitch = pitch; 1473 cip->bank = bank; 1474 applied_rot = true; 1475 } else { 1476 if (heading != 0) { 1477 cip->heading = heading; 1478 aip->ai_override_flags.set(AI::Maneuver_Override_Flags::Heading); 1479 applied_rot = true; 1480 } 1481 if (pitch != 0) { 1482 cip->pitch = pitch; 1483 aip->ai_override_flags.set(AI::Maneuver_Override_Flags::Pitch); 1484 applied_rot = true; 1485 } 1486 if (bank != 0) { 1487 cip->bank = bank; 1488 aip->ai_override_flags.set(AI::Maneuver_Override_Flags::Roll); 1489 applied_rot = true; 1490 } 1491 } 1492 if (apply_all_move) { 1493 aip->ai_override_flags.set(AI::Maneuver_Override_Flags::Full_lat); 1494 cip->vertical = up; 1495 cip->sideways = sideways; 1496 cip->forward = forward; 1497 applied_lat = true; 1498 } else { 1499 if (up != 0) { 1500 cip->vertical = up; 1501 aip->ai_override_flags.set(AI::Maneuver_Override_Flags::Up); 1502 applied_lat = true; 1503 } 1504 if (sideways != 0) { 1505 cip->sideways = sideways; 1506 aip->ai_override_flags.set(AI::Maneuver_Override_Flags::Sideways); 1507 applied_lat = true; 1508 } 1509 if (forward != 0) { 1510 cip->forward = forward; 1511 aip->ai_override_flags.set(AI::Maneuver_Override_Flags::Forward); 1512 applied_lat = true; 1513 } 1514 } 1515 1516 // handle infinite timestamps 1517 if (duration >= 2) { 1518 if (applied_rot) 1519 aip->ai_override_rot_timestamp = timestamp(duration); 1520 if (applied_lat) 1521 aip->ai_override_lat_timestamp = timestamp(duration); 1522 } 1523 else { 1524 if (applied_rot) { 1525 aip->ai_override_rot_timestamp = timestamp(10); 1526 aip->ai_override_flags.set(AI::Maneuver_Override_Flags::Rotational_never_expire); 1527 } 1528 if (applied_lat) { 1529 aip->ai_override_lat_timestamp = timestamp(10); 1530 aip->ai_override_flags.set(AI::Maneuver_Override_Flags::Lateral_never_expire); 1531 } 1532 } 1533 1534 if (maneuver_flags & CIF_DONT_BANK_WHEN_TURNING) { 1535 aip->ai_override_flags.set(AI::Maneuver_Override_Flags::Dont_bank_when_turning); 1536 } 1537 if (maneuver_flags & CIF_DONT_CLAMP_MAX_VELOCITY) { 1538 aip->ai_override_flags.set(AI::Maneuver_Override_Flags::Dont_clamp_max_velocity); 1539 } 1540 if (maneuver_flags & CIF_INSTANTANEOUS_ACCELERATION) { 1541 aip->ai_override_flags.set(AI::Maneuver_Override_Flags::Instantaneous_acceleration); 1542 } 1543 1544 return ADE_RETURN_TRUE; 1545 } 1546 1547 ADE_FUNC(triggerAnimation, l_Ship, "string Type, [number Subtype, boolean Forwards, boolean Instant]", 1548 "Triggers an animation. Type is the string name of the animation type, " 1549 "Subtype is the subtype number, such as weapon bank #, Forwards and Instant are boolean, defaulting to true & false respectively." 1550 "<br><strong>IMPORTANT: Function is in testing and should not be used with official mod releases</strong>", 1551 "boolean", 1552 "True if successful, false or nil otherwise") 1553 { 1554 object_h *objh; 1555 const char* s = nullptr; 1556 bool b = true; 1557 bool instant = false; 1558 int subtype=-1; 1559 if(!ade_get_args(L, "o|sibb", l_Ship.GetPtr(&objh), &s, &subtype, &b, &instant)) 1560 return ADE_RETURN_NIL; 1561 1562 if(!objh->IsValid()) 1563 return ADE_RETURN_NIL; 1564 1565 auto type = model_anim_match_type(s); 1566 if(type == AnimationTriggerType::None) 1567 return ADE_RETURN_FALSE; 1568 1569 int dir = 1; 1570 if(!b) 1571 dir = -1; 1572 1573 model_anim_start_type(&Ships[objh->objp->instance], type, subtype, dir, instant); 1574 1575 return ADE_RETURN_TRUE; 1576 } 1577 1578 ADE_FUNC(warpIn, l_Ship, NULL, "Warps ship in", "boolean", "True if successful, or nil if ship handle is invalid") 1579 { 1580 object_h *objh; 1581 if(!ade_get_args(L, "o", l_Ship.GetPtr(&objh))) 1582 return ADE_RETURN_NIL; 1583 1584 if(!objh->IsValid()) 1585 return ADE_RETURN_NIL; 1586 1587 shipfx_warpin_start(objh->objp); 1588 1589 return ADE_RETURN_TRUE; 1590 } 1591 1592 ADE_FUNC(warpOut, l_Ship, NULL, "Warps ship out", "boolean", "True if successful, or nil if ship handle is invalid") 1593 { 1594 object_h *objh; 1595 if(!ade_get_args(L, "o", l_Ship.GetPtr(&objh))) 1596 return ADE_RETURN_NIL; 1597 1598 if(!objh->IsValid()) 1599 return ADE_RETURN_NIL; 1600 1601 shipfx_warpout_start(objh->objp); 1602 1603 return ADE_RETURN_TRUE; 1604 } 1605 1606 ADE_FUNC(canWarp, l_Ship, nullptr, "Checks whether ship has a working subspace drive, is allowed to use it, and is not disabled or limited by subsystem strength.", "boolean", "True if successful, or nil if ship handle is invalid") 1607 { 1608 object_h *objh; 1609 if(!ade_get_args(L, "o", l_Ship.GetPtr(&objh))) 1610 return ADE_RETURN_NIL; 1611 1612 if(!objh->IsValid()) 1613 return ADE_RETURN_NIL; 1614 1615 ship *shipp = &Ships[objh->objp->instance]; 1616 if( ship_can_warp_full_check(shipp) ){ 1617 return ADE_RETURN_TRUE; 1618 } 1619 1620 return ADE_RETURN_FALSE; 1621 } 1622 1623 ADE_FUNC(canBayDepart, l_Ship, nullptr, "Checks whether ship has a bay departure location and if its mother ship is present.", "boolean", "True if successful, or nil if ship handle is invalid") 1624 { 1625 object_h *objh; 1626 if(!ade_get_args(L, "o", l_Ship.GetPtr(&objh))) 1627 return ADE_RETURN_NIL; 1628 1629 if(!objh->IsValid()) 1630 return ADE_RETURN_NIL; 1631 1632 ship *shipp = &Ships[objh->objp->instance]; 1633 if( ship_can_bay_depart(shipp) ){ 1634 return ADE_RETURN_TRUE; 1635 } 1636 1637 return ADE_RETURN_FALSE; 1638 } 1639 1640 // Aardwolf's function for finding if a ship should be drawn as blue on the radar/minimap 1641 ADE_FUNC(isWarpingIn, l_Ship, NULL, "Checks if ship is warping in", "boolean", "True if the ship is warping in, false or nil otherwise") 1642 { 1643 object_h *objh; 1644 if(!ade_get_args(L, "o", l_Ship.GetPtr(&objh))) 1645 return ADE_RETURN_NIL; 1646 1647 if(!objh->IsValid()) 1648 return ADE_RETURN_NIL; 1649 1650 ship *shipp = &Ships[objh->objp->instance]; 1651 if(shipp->is_arriving(ship::warpstage::STAGE1, false)){ 1652 return ADE_RETURN_TRUE; 1653 } 1654 1655 return ADE_RETURN_FALSE; 1656 } 1657 1658 ADE_FUNC(getEMP, l_Ship, NULL, "Returns the current emp effect strength acting on the object", "number", "Current EMP effect strength or NIL if object is invalid") 1659 { 1660 object_h *objh = NULL; 1661 object *obj = NULL; 1662 1663 if (!ade_get_args(L, "o", l_Ship.GetPtr(&objh))) { 1664 return ADE_RETURN_NIL; 1665 } 1666 1667 if(!objh->IsValid()) 1668 return ADE_RETURN_NIL; 1669 1670 obj = objh->objp; 1671 1672 ship *shipp = &Ships[obj->instance]; 1673 1674 return ade_set_args(L, "f", shipp->emp_intensity); 1675 } 1676 1677 ADE_FUNC(getTimeUntilExplosion, l_Ship, nullptr, "Returns the time in seconds until the ship explodes (the ship's final_death_time timestamp)", "number", "Time until explosion or -1, if invalid handle or ship isn't exploding") 1678 { 1679 object_h *objh = nullptr; 1680 1681 if (!ade_get_args(L, "o", l_Ship.GetPtr(&objh))) 1682 return ade_set_error(L, "f", -1.0f); 1683 if(!objh->IsValid()) 1684 return ade_set_error(L, "f", -1.0f); 1685 1686 ship *shipp = &Ships[objh->objp->instance]; 1687 1688 if (!timestamp_valid(shipp->final_death_time)) 1689 return ade_set_args(L, "f", -1.0f); 1690 1691 int time_until = timestamp_until(shipp->final_death_time); 1692 1693 return ade_set_args(L, "f", (i2fl(time_until) / 1000.0f)); 1694 } 1695 1696 ADE_FUNC(setTimeUntilExplosion, l_Ship, "number Time", "Sets the time in seconds until the ship explodes (the ship's final_death_time timestamp). This function will only work if the ship is in its death roll but hasn't exploded yet, which can be checked via isDying() or getTimeUntilExplosion().", "boolean", "True if successful, false if the ship is invalid or not currently exploding") 1697 { 1698 object_h *objh = nullptr; 1699 float delta_s; 1700 1701 if (!ade_get_args(L, "of", l_Ship.GetPtr(&objh), &delta_s)) 1702 return ade_set_error(L, "b", false); 1703 if (!objh->IsValid()) 1704 return ade_set_error(L, "b", false); 1705 1706 ship *shipp = &Ships[objh->objp->instance]; 1707 1708 if (!timestamp_valid(shipp->final_death_time)) 1709 return ade_set_args(L, "b", false); 1710 1711 int delta_ms = fl2i(delta_s * 1000.0f); 1712 if (delta_ms < 2) 1713 delta_ms = 2; 1714 1715 shipp->final_death_time = timestamp(delta_ms); 1716 1717 return ade_set_args(L, "b", true); 1718 } 1719 1720 ADE_FUNC(getCallsign, l_Ship, NULL, "Gets the callsign of the ship in the current mission", "string", "The callsign or an empty string if the ship doesn't have a callsign or an error occurs") 1721 { 1722 object_h *objh = NULL; 1723 1724 if (!ade_get_args(L, "o", l_Ship.GetPtr(&objh))) { 1725 return ade_set_error(L, "s", ""); 1726 } 1727 1728 if(!objh->IsValid()) 1729 return ade_set_error(L, "s", ""); 1730 1731 ship *shipp = &Ships[objh->objp->instance]; 1732 1733 if (shipp->callsign_index < 0) 1734 return ade_set_args(L, "s", ""); 1735 1736 char temp_callsign[NAME_LENGTH]; 1737 1738 *temp_callsign = 0; 1739 strcpy(temp_callsign, mission_parse_lookup_callsign_index(shipp->callsign_index)); 1740 1741 if (*temp_callsign) 1742 return ade_set_args(L, "s", temp_callsign); 1743 else 1744 return ade_set_args(L, "s", ""); 1745 } 1746 1747 ADE_FUNC(getAltClassName, l_Ship, NULL, "Gets the alternate class name of the ship", "string", "The alternate class name or an empty string if the ship doesn't have such a thing or an error occurs") 1748 { 1749 object_h *objh = NULL; 1750 1751 if (!ade_get_args(L, "o", l_Ship.GetPtr(&objh))) { 1752 return ade_set_error(L, "s", ""); 1753 } 1754 1755 if(!objh->IsValid()) 1756 return ade_set_error(L, "s", ""); 1757 1758 ship *shipp = &Ships[objh->objp->instance]; 1759 1760 if (shipp->alt_type_index < 0) 1761 return ade_set_args(L, "s", ""); 1762 1763 char temp_altname[NAME_LENGTH]; 1764 1765 strcpy_s(temp_altname, mission_parse_lookup_alt_index(shipp->alt_type_index)); 1766 1767 if (*temp_altname) 1768 return ade_set_args(L, "s", temp_altname); 1769 else 1770 return ade_set_args(L, "s", ""); 1771 } 1772 1773 ADE_FUNC(getMaximumSpeed, l_Ship, "[number energy = 0.333]", "Gets the maximum speed of the ship with the given energy on the engines", "number", "The maximum speed or -1 on error") 1774 { 1775 object_h *objh = NULL; 1776 float energy = 0.333f; 1777 1778 if (!ade_get_args(L, "o|f", l_Ship.GetPtr(&objh), &energy)) { 1779 return ade_set_error(L, "f", -1.0f); 1780 } 1781 1782 if(!objh->IsValid()) 1783 return ade_set_error(L, "f", -1.0f); 1784 1785 if (energy < 0.0f || energy > 1.0f) 1786 { 1787 LuaError(L, "Invalid energy level %f! Needs to be in [0, 1].", energy); 1788 1789 return ade_set_args(L, "f", -1.0f); 1790 } 1791 else 1792 { 1793 return ade_set_args(L, "f", ets_get_max_speed(objh->objp, energy)); 1794 } 1795 } 1796 1797 ADE_FUNC(EtsSetIndexes, l_Ship, "number EngineIndex, number ShieldIndex, number WeaponIndex", 1798 "Sets ships ETS systems to specified values", 1799 "boolean", 1800 "True if successful, false if target ships ETS was missing, or only has one system") 1801 { 1802 object_h *objh=NULL; 1803 int ets_idx[num_retail_ets_gauges] = {0}; 1804 1805 if (!ade_get_args(L, "oiii", l_Ship.GetPtr(&objh), &ets_idx[ENGINES], &ets_idx[SHIELDS], &ets_idx[WEAPONS])) 1806 return ADE_RETURN_FALSE; 1807 1808 if (!objh->IsValid()) 1809 return ADE_RETURN_FALSE; 1810 1811 sanity_check_ets_inputs(ets_idx); 1812 1813 int sindex = objh->objp->instance; 1814 if (validate_ship_ets_indxes(sindex, ets_idx)) { 1815 Ships[sindex].engine_recharge_index = ets_idx[ENGINES]; 1816 Ships[sindex].shield_recharge_index = ets_idx[SHIELDS]; 1817 Ships[sindex].weapon_recharge_index = ets_idx[WEAPONS]; 1818 return ADE_RETURN_TRUE; 1819 } else { 1820 return ADE_RETURN_FALSE; 1821 } 1822 } 1823 1824 ADE_FUNC(getWing, l_Ship, NULL, "Returns the ship's wing", "wing", "Wing handle, or invalid wing handle if ship is not part of a wing") 1825 { 1826 object_h *objh = NULL; 1827 ship *shipp = NULL; 1828 1829 if (!ade_get_args(L, "o", l_Ship.GetPtr(&objh))) 1830 return ade_set_error(L, "o", l_Wing.Set(-1)); 1831 1832 if(!objh->IsValid()) 1833 return ade_set_error(L, "o", l_Wing.Set(-1)); 1834 1835 shipp = &Ships[objh->objp->instance]; 1836 return ade_set_args(L, "o", l_Wing.Set(shipp->wingnum)); 1837 } 1838 1839 ADE_FUNC(getDisplayString, l_Ship, nullptr, "Returns the string which should be used when displaying the name of the ship to the player", "string", "The display string or empty if handle is invalid") 1840 { 1841 object_h *objh = nullptr; 1842 ship *shipp = nullptr; 1843 1844 if (!ade_get_args(L, "o", l_Ship.GetPtr(&objh))) 1845 return ade_set_error(L, "s", ""); 1846 1847 if(!objh->IsValid()) 1848 return ade_set_error(L, "s", ""); 1849 1850 shipp = &Ships[objh->objp->instance]; 1851 return ade_set_args(L, "s", shipp->get_display_name()); 1852 } 1853 1854 ADE_FUNC(vanish, l_Ship, nullptr, "Vanishes this ship from the mission. Works in Singleplayer only and will cause the ship exit to not be logged.", "boolean", "True if the deletion was successful, false otherwise.") 1855 { 1856 1857 object_h* objh = nullptr; 1858 1859 if (!ade_get_args(L, "o", l_Ship.GetPtr(&objh))) 1860 return ade_set_error(L, "b", false); 1861 1862 if (!objh->IsValid()) 1863 return ade_set_error(L, "b", false); 1864 1865 ship_actually_depart(objh->objp->instance, SHIP_VANISHED); 1866 1867 return ade_set_args(L, "b", true); 1868 } 1869 1870 1871 } 1872 } 1873