Wing Commander II
Reconstructed Win32 source (1996)
Loading...
Searching...
No Matches
ship.c
Go to the documentation of this file.
1/*
2 * Space objects: creation, weapons, movement and damage.
3 *
4 * Retail object 0x410020-0x41754F (link order; see docs/ORDER.md).
5 */
6#define SHIP_C
7#include "game.h"
8
9short g_bAiMissileFiringEnabled = 1; /* 0x00492d58 */
10short g_bFriendlyFireWarningIssued = 0; /* 0x00492d5c */
11short g_nLastAdaptiveDifficultyChangeFrame = 0; /* 0x00492d60 */
12short g_nObjectType62Index = -1; /* 0x00492d64 */
13short g_nObjectType63Index = -1; /* 0x00492d68 */
14short g_nLastFriendlyFireObjectFrame = 0x0ee4; /* 0x00492d6c */
16 { 0, 8, 6, 5, 0, 3, 5, 5, 7, 6 },
17 { 0, 8, 6, 5, 4, 3, 4, 0, 4, 4 },
18 { 1, 2, 5, 2, 7, 3, 4, 7, 5, 1 },
19 { 1, 4, 1, 5, 2, 3, 4, 7, 2, 1 },
20 { 4, 4, 4, 4, 0, 8, 6, 5, 4, 0 }
21}; /* 0x00492d70 */
53short g_bExplosionTraversalIdle = 1; /* 0x00492e18 */
54signed char g_acGunRefireDelay[4] = {5, 9, 3, 4}; /* 0x00492e1c */
55
56/* Function start: 0x410020 */
57short CountShipProjectiles(short ship)
58{
59 short count;
60 short obj;
61
62 count = 0;
63 for (obj = 0; obj < SPACE_OBJECT_COUNT; obj++) {
65 g_acObjectOwner[obj] == ship)
66 count++;
67 }
68 return count;
69}
70
71/* Function start: 0x41008E */
72short ShipHasCloakingDevice(short ship)
73{
74 short weapon;
75 unsigned char *weapons;
76
77 weapons = g_aShipWeapons[ship];
78 weapon = 0;
79 for (; (short)(signed char)weapons[0] > weapon; weapon++) {
80 if (((ShipWeaponSlot *)(weapons + 1))[weapon].type == 0x3c)
81 return 1;
82 }
83 return 0;
84}
85
86/* Function start: 0x410102 */
87short CanShipWeaponDamageTarget(short ship, short target)
88{
90 if (g_aasShipShield[target][0] >= 1000 ||
91 g_aasShipShield[target][1] >= 1000)
92 return 0;
93 }
94 return 1;
95}
96
97/* Function start: 0x410161 */
98short IsCapitalShipObject(short obj)
99{
101 return 1;
102 return 0;
103}
104
105/* Function start: 0x410192 */
107{
108 short weapon;
109 short count;
110
111 count = (short)(signed char)g_aShipWeapons[ship][0];
112 weapon = 0;
113 for (; count > weapon; weapon++) {
114 if (((ShipWeaponSlot *)&g_aShipWeapons[ship][1])[
115 weapon].type == 0x0b)
116 return 1;
117 }
118 return 0;
119}
120
121/* Function start: 0x410215 */
122short ShipHasTorpedo(short ship)
123{
124 unsigned char *weapons;
125 short weapon;
126
127 weapons = g_aShipWeapons[ship];
128 weapon = 0;
129 for (; (short)(signed char)weapons[0] > weapon; weapon++) {
130 if (((ShipWeaponSlot *)(weapons + 1))[weapon].type == 0x13)
131 return 1;
132 }
133 return 0;
134}
135
136/* Function start: 0x410289 */
138{
139 short turnRate;
140
141 turnRate = g_asDifficultyLevels[
143 turnRate = (short)((int)turnRate * g_nAdaptiveDifficulty / 5);
144 if (turnRate == 0)
145 turnRate = 1;
146 if (turnRate > 200)
147 turnRate = 200;
148 return turnRate;
149}
150
151/* Function start: 0x4102FD */
163
164/* Function start: 0x410352 */
176
177/* Function start: 0x4103A6 */
178short initialize_object(short obj, short type, short owner,
179 short matchLoadedType)
180{
181 if (obj != -1) {
182 set_objects_data(obj, type, owner, matchLoadedType);
185 }
186 return obj;
187}
188
189/* Function start: 0x41040D */
190short borrow_dust(void)
191{
192 short i;
193 signed char found;
194
195 found = 0;
196 for (i = 10; i <= 66; i++) {
198 found++;
199 break;
200 }
201 }
202 if (!found) {
203 for (i = 10; i <= 66; i++) {
205 found++;
206 break;
207 }
208 }
209 }
210 if (!found) {
211 for (i = 10; i <= 66; i++) {
213 g_acObjectOwner[i] != 0 &&
214 g_asObjectScreenX[i] == (short)0x8001) {
215 found++;
216 break;
217 }
218 }
219 }
220 if (!found) {
221 for (i = 10; i <= 66; i++) {
224 g_asObjectScreenX[i] == (short)0x8001) {
225 found++;
226 break;
227 }
228 }
229 }
230 if (!found) {
231 i = -1;
232 } else {
233 g_asObjectScreenX[i] = (short)0x8001;
234 }
235 return i;
236
237}
238
239/* Function start: 0x4105BF */
240short new_object(short type, short owner)
241{
242 short obj;
243
244 obj = find_vacant_3d_object();
245 if (obj == -1 && owner == 0 && type >= 7 && type < 11)
246 obj = borrow_dust();
247 return initialize_object(obj, type, owner, 0);
248}
249
250/* Function start: 0x41062D */
251short initialize_ship(short type, short owner,
252 short matchLoadedType)
253{
254 short obj = get_ship_slot();
255
256 if (obj != -1) {
257 initialize_object(obj, type, owner, matchLoadedType);
259 }
260 return obj;
261}
262
263/* Function start: 0x410680 */
264short any_selected(unsigned char *loadout, short objectClass)
265{
266 short selected;
267 short weapon;
268
269 selected = 0;
270 weapon = 0;
271 for (; (short)(signed char)loadout[0] > weapon && selected == 0;
272 weapon++) {
274 ((ShipWeaponSlot *)(loadout + 1))[weapon].weaponType]
275 .objectClass == objectClass &&
276 ((ShipWeaponSlot *)(loadout + 1))[weapon].disabled == 0)
277 selected = 1;
278 }
279 return selected;
280}
281
282/* Function start: 0x410715 */
283void remove_weapon(short obj, short weapon)
284{
285 short removedType;
286 short objectClass;
287 short dataType;
288 struct ShipLoadout *slots;
289 short index;
290
291 slots = &((struct ShipLoadout *)g_aShipWeapons)[obj];
292 dataType = ((ShipWeaponSlot *)(g_aShipWeapons[obj] + 1))[
293 weapon].weaponType;
294 removedType = ((ShipWeaponSlot *)(g_aShipWeapons[obj] + 1))[
295 weapon].type;
296 objectClass = g_aObjectTypeData[dataType].objectClass;
297 if (slots->count - 1 > weapon) {
298 for (index = weapon; slots->count - 1 > index; index++) {
299 slots->slots[index].type = slots->slots[index + 1].type;
300 slots->slots[index].mount = slots->slots[index + 1].mount;
301 slots->slots[index].disabled = slots->slots[index + 1].disabled;
302 slots->slots[index].weaponType =
303 slots->slots[index + 1].weaponType;
304 if (obj == 0) {
307 }
308 }
309 if (slots->count < 0x10)
310 slots->slots[slots->count].disabled = 1;
311 }
312 slots->count--;
313 if (obj == 0) {
314 if (any_selected((unsigned char *)slots, objectClass) == 0) {
315 if (objectClass == OBJECT_CLASS_PROJECTILE) {
317 } else {
319 select_new_release_weapon(removedType);
320 }
321 }
322 if (get_mode(0) == 1)
324 }
325}
326
327/* Function start: 0x41090F */
329{
330 short weaponCount;
331 short weaponIndex;
332
333 weaponCount = (short)(signed char)
336 for (weaponIndex = 0; weaponIndex < weaponCount; weaponIndex++) {
337 g_aShipWeapons[obj][
338 weaponIndex * sizeof(ShipWeaponSlot) + 1 +
339 offsetof(ShipWeaponSlot, weaponType)] =
340 g_aShipWeapons[obj][
341 weaponIndex * sizeof(ShipWeaponSlot) + 1 +
342 offsetof(ShipWeaponSlot, type)];
343 }
344}
345
346/* Function start: 0x410999 */
347void set_objects_data(short obj, short type, short owner,
348 short matchResourceType)
349{
350 short frameIndex;
351 unsigned char *animation;
352 ObjectTypeData *source;
353 short weapon;
354 ObjectTypeData *typeData;
355
358 if (matchResourceType != 0) {
359 for (weapon = 0; weapon < 5; weapon++) {
360 if (g_aObjectTypeData[weapon].resourceType == type)
361 break;
362 }
363 typeData = &g_aObjectTypeData[weapon];
364 g_acObjectType[obj] = (signed char)weapon;
365 g_apObjectExhaustShape[obj] = typeData->animation;
366 g_apObjectShape[obj] = typeData->shapeSet;
367 } else {
368 if (type == OBJECT_DATA_SPACE_DUST) {
371 return;
372 }
373 if (g_aObjectTypeData[type].shapeSet == 0) {
374 switch (type) {
377 break;
380 break;
382 type = OBJECT_DATA_PIPE;
383 break;
386 break;
389 break;
392 break;
395 break;
396 }
397 }
398 if (type == 0x3d)
400 else
401 g_acObjectType[obj] = (signed char)type;
402 if (type == 0x3e) {
403 g_acObjectType[obj] =
404 (signed char)g_nObjectType62Index;
405 }
406 if (type == 0x3f) {
407 g_acObjectType[obj] =
408 (signed char)g_nObjectType63Index;
409 }
410 typeData =
412 source = typeData;
413 if (type == 0xe)
414 source = &g_aObjectTypeData[10];
415 if (type == 0xd)
416 source = &g_aObjectTypeData[8];
417 g_asObjectType[obj] = type;
418 if (type == OBJECT_DATA_CHAFF_POD &&
419 g_aObjectTypeData[20].shapeSet == 0) {
420 g_apObjectShape[obj] =
422 }
423 if (type == OBJECT_DATA_ROCK_CHUNK) {
424 g_apObjectShape[obj] =
427 } else {
428 g_apObjectShape[obj] = source->shapeSet;
429 }
430 }
431 g_asObjectType[obj] = typeData->field_18;
432 g_aeObjectClass[obj] = typeData->objectClass;
434 if (g_asShipSide[owner] == SIDE_KILRATHI && owner != 0 &&
441 } else {
442 g_apObjectExhaustShape[obj] = typeData->animation;
443 }
444 }
445 init_ijk(obj);
447 g_asObjectScale[obj] = typeData->scale;
448 if (type == 0xe) {
449 g_asObjectScale[obj] =
450 (unsigned short)(g_asObjectScale[obj] * 8);
451 }
452 if (type == 0xd) {
453 g_asObjectScale[obj] =
454 (unsigned short)(g_asObjectScale[obj] * 8);
455 }
456 g_asObjectDamage[obj] = 0;
459 g_acObjectOwner[obj] = (signed char)owner;
460 g_acLastCollisionObject[obj] = -1;
462 g_asObjectViewFrame[obj] = 0;
463 g_acShipTarget[obj] = -1;
465 g_aasShipShield[obj][0] = typeData->shieldFore;
466 g_aasShipMaximumShield[obj][0] =
467 g_aasShipShield[obj][0];
468 g_aasShipShield[obj][1] = typeData->shieldAft;
469 g_aasShipMaximumShield[obj][1] =
470 g_aasShipShield[obj][1];
471 g_aasShipArmor[obj][0] = typeData->armorFront;
472 g_aasShipArmor[obj][2] = typeData->armorLeft;
473 g_aasShipArmor[obj][3] = typeData->armorRight;
474 g_aasShipArmor[obj][1] = typeData->armorRear;
475 g_anShipFuel[obj] = *(int *)&typeData->lifetime;
476 g_acShipIonDriveDamage[obj] = 0;
477 g_acShipDamage[obj] = 0;
479 g_acPilotHitPoints[obj] = 4;
480 memcpy(g_aShipWeapons[obj], typeData->weaponLoadout,
481 sizeof(typeData->weaponLoadout));
483 if (obj == 0) {
486 weapon = (short)(signed char)g_aShipWeapons[obj][0];
487 while (weapon-- > 0) {
488 if (((ShipWeaponSlot *)(
489 g_aShipWeapons[obj] + 1))[
490 weapon].disabled == 0) {
492 ((ShipWeaponSlot *)(
493 g_aShipWeapons[obj] + 1))[
494 weapon].weaponType].objectClass ==
496 if (g_nSelectedGunType != -1 &&
497 ((ShipWeaponSlot *)(
498 g_aShipWeapons[obj] + 1))[
499 weapon].type !=
501 g_nSelectedGunType = 0x80;
502 } else {
504 ((ShipWeaponSlot *)(
505 g_aShipWeapons[obj] + 1))[
506 weapon].type;
507 }
508 } else {
510 }
511 }
512 }
513 }
514 if (HasShipCockpitGunDisplay(obj) != 0)
516 else
518 g_asShipWeaponEnergy[obj] = 100;
519 g_acShipLastAttacker[obj] = -1;
520 }
521 } else {
522 animation = typeData->animation;
523 if (animation == 0) {
524 frameIndex = 0;
526 (short)(typeData->yawRate + frameIndex);
527 } else {
530 frameIndex = g_asObjectAnimationIndex[obj];
531 animate_shape(obj);
532 }
533 }
534}
535
536#pragma function(abs)
537/* Function start: 0x411172 */
538unsigned int match_rotation_goal(short *rotation, short *goal,
539 short totalError, short rate)
540{
541 if (totalError != 0) {
542 if (*goal > 180)
543 *goal = *goal - 360;
544 if (*goal < -180)
545 *goal = *goal + 360;
546 rate = MaxShort(1, (short)(abs(*rotation - *goal) * rate /
547 totalError));
548 if (*goal != *rotation || abs(*rotation) > rate) {
549 if (*goal > 0) {
550 *rotation = (short)(*rotation +
551 MaxShort(
552 MinShort(
553 (short)(MinShort(*goal, rate) - *rotation),
554 rate),
555 (short)-rate));
556 } else {
557 *rotation = (short)(*rotation +
558 MinShort(
559 MaxShort(
560 (short)(MaxShort(*goal, (short)-rate) -
561 *rotation),
562 (short)-rate),
563 rate));
564 }
565 }
566 }
567 if (*goal != 0) {
568 if (*goal > 0)
569 *goal = MaxShort((short)(*goal - *rotation), 0);
570 else
571 *goal = MinShort((short)(*goal - *rotation), 0);
572 }
573}
574
575/* Function start: 0x41133D */
577{
578 short rate;
579 short turnScale;
580 short totalError;
581 ObjectTypeData *typeData;
582
583 typeData = &g_aObjectTypeData[g_acObjectType[obj]];
584 if (g_aeSpecialManeuver[obj] ==
586 if ((short)alert_flag(obj, 1) != 0) {
588 } else {
589 /* The original passes a difficulty the callee ignores. */
590 if (g_asObjectCounter[obj] == -1 &&
591 skill_check(obj, 7) != 0)
593 return;
594 }
595 }
596 totalError = (short)(abs(g_anObjectRollRotation[obj] -
597 g_anRollGoal[obj]) +
598 abs(g_anObjectYawRotation[obj] -
599 g_anYawGoal[obj]) +
600 abs(g_anObjectPitchRotation[obj] -
601 g_anPitchGoal[obj]));
602 rate = typeData->yawRate;
603 turnScale = MinShort(180, MaxShort(100, GetAdaptiveTurnRate()));
604 if (g_asShipSide[obj] != g_asShipSide[0] &&
606 rate = (short)(turnScale * rate / 100);
608 &g_anPitchGoal[obj], totalError,
609 typeData->yawRate);
610 rate = typeData->pitchRate;
611 if (g_asShipSide[obj] != g_asShipSide[0] &&
613 rate = (short)(turnScale * rate / 100);
615 &g_anYawGoal[obj], totalError,
616 typeData->pitchRate);
617 rate = typeData->rollRate;
618 if (g_asShipSide[obj] != g_asShipSide[0] &&
620 rate = (short)(turnScale * rate / 100);
622 &g_anRollGoal[obj], totalError,
623 typeData->rollRate);
624}
625
626/* Function start: 0x4115F8 */
627/* A ship whose commanded rotation runs further ahead of its own turn rates
628 * than its pilot can absorb tumbles out of control for a few frames. */
630{
631 short turnScale;
632 short type;
633 short overshoot;
634 short turnAbility;
635
636 if (obj != 0 &&
638 if (g_asShipSide[obj] != g_asShipSide[0] &&
640 turnScale = MinShort(180, MaxShort(100, GetAdaptiveTurnRate()));
641 else
642 turnScale = 100;
643 type = g_acObjectType[obj];
644 turnAbility = (short)(g_aObjectTypeData[type].pitchRate *
645 turnScale / 100);
646 turnAbility = (short)(g_aObjectTypeData[type].yawRate *
647 turnScale / 100 + turnAbility);
648 turnAbility = (short)(g_aObjectTypeData[type].rollRate *
649 turnScale / 100 + turnAbility);
650 /* These identities retain retail's roll/yaw/pitch call order in
651 * CL 4.1, then fold away before instruction emission. */
652 overshoot = (short)(~~(~~abs(g_anObjectRollRotation[obj]) +
653 abs(g_anObjectYawRotation[obj])) +
654 abs(g_anObjectPitchRotation[obj]));
655 overshoot = (short)(overshoot / turnAbility);
656 /* The original passes the overshoot the callee ignores. */
657 if (skill_check(obj, overshoot) ==
658 0) {
660 g_asObjectCounter[obj] =
661 (short)(RandomBelowOrEqual(6) + 5);
662 }
663 }
664}
665
666#pragma intrinsic(abs)
667/* Function start: 0x4117AC */
668void celerate(short ship, int delta)
669{
670 int maximumSpeed;
671
672 maximumSpeed = (int)g_asShipMaximumVelocity[ship] << 8;
673 g_anShipSpeed[ship] += delta;
674 if (g_anShipSpeed[ship] > maximumSpeed)
675 g_anShipSpeed[ship] = maximumSpeed;
676 if (g_anShipSpeed[ship] < 0)
677 g_anShipSpeed[ship] = 0;
678}
679
680#pragma function(abs)
681/* Function start: 0x41181D */
682unsigned int approach_speed(short ship, int targetSpeed)
683{
684 int delta;
685 int acceleration;
686
687 acceleration = GetShipAccelerationRate(ship);
688 delta = targetSpeed - g_anShipSpeed[ship];
689
690 if ((short)alert_flag(ship, 1))
691 acceleration *= 2;
692 if (abs(delta) > acceleration)
693 delta = MultiplyFixed(SignFixed(delta), acceleration);
694 celerate(ship, delta);
695}
696
697/* Function start: 0x4118A9 */
698void steady_object(short ship)
699{
700 g_anRollGoal[ship] = g_anPitchGoal[ship] =
701 g_anYawGoal[ship] = 0;
702}
703
704/* Function start: 0x4118F2 */
705short real_velocity(short obj)
706{
709}
710
711/* Function start: 0x411922 */
712unsigned int fix_velocity(short obj)
713{
715 g_anShipSpeed[obj],
716 &g_aShipVelocity[obj]);
717}
718
719/* Function start: 0x41195F */
721{
722 short outer;
723 short j;
724 short range;
725 short temp;
726
727 if (g_cViableTargetCount > 1) {
728 for (outer = 0;
729 outer < (short)g_cViableTargetCount - 1;
730 outer++) {
731 for (j = (short)(outer + 1);
732 j < (short)g_cViableTargetCount;
733 j++) {
734 range = g_asViableTargetDistance[outer];
735 if (g_asViableTargetDistance[j] < range) {
736 temp = g_acViableTarget[outer];
739 g_acViableTarget[outer] =
741 g_asViableTargetDistance[j] = range;
742 g_acViableTarget[j] = (signed char)temp;
743 }
744 }
745 }
746 }
747}
748
749/* Function start: 0x411A50 */
750void send_appropriate_message(short attacker, short victim)
751{
752 if (g_acObjectOwner[attacker] != -1 &&
754 (short)g_acObjectOwner[attacker]] >=
756 if (g_asShipSide[
757 (short)g_acObjectOwner[attacker]] ==
760 (short)g_acObjectOwner[attacker]] !=
761 g_asShipSide[victim]) {
762 if (g_aeObjectClass[victim] >=
765 (short)g_acObjectOwner[attacker]] !=
768 (short)g_acObjectOwner[attacker], 6);
769 if (((short)g_acObjectOwner[attacker] ==
771 RandomBelowOrEqual(100) < 70) &&
773 (short)g_acObjectOwner[attacker]] !=
776 if ((short)g_acObjectOwner[attacker] ==
778 if (g_asPlayerHitsCreditValues[victim] <=
779 g_asWingmanDamageCredit[victim] ||
780 g_aeObjectClass[attacker] ==
783 (short)g_acObjectOwner[attacker], 5);
784 } else {
786 (short)g_acObjectOwner[attacker], 5);
787 }
788 }
789 } else if (g_asShipSide[
790 (short)g_acObjectOwner[attacker]] !=
793 (short)g_acObjectOwner[attacker]] !=
794 g_asShipSide[victim] &&
796 (short)g_acObjectOwner[attacker]] !=
798 send_message((short)g_acObjectOwner[attacker], 0x1c);
799 }
800 }
801}
802
803/* Function start: 0x411C72 */
804short inflict_damage(short attacker, short victim, short damage,
805 const FixedVector *impactDirection)
806{
807 short *protection;
808 int sideProjection;
809 short ally;
810 short destroyed;
811 short quadrant;
812
813 if (g_acObjectOwner[attacker] == 0)
814 destroyed = 0;
816 g_asShipSide[victim] == SIDE_KILRATHI &&
817 g_acObjectOwner[attacker] == 0 &&
818 RandomBelowOrEqual(9) == 0)
820 if (g_bApplyingCollisionDamage != 0 && victim == 0 &&
821 g_acObjectOwner[attacker] != -1 &&
823 (short)g_acObjectOwner[attacker]] ==
825 RandomBelowOrEqual(5) == 0)
827 if (g_bPlayerDamageEnabled == 0 && victim == 0)
828 return 0;
829 if ((g_aasShipShield[victim][0] >= 1000 ||
830 g_aasShipShield[victim][1] >= 1000) &&
831 attacker != -1 && g_asObjectType[attacker] != 0x0d &&
832 g_asObjectType[attacker] != 0x0e &&
833 g_asObjectType[attacker] != 0x13)
834 return 0;
835 if (attacker != -1 &&
838 (short)g_acObjectOwner[attacker], victim) == 0)
839 return 0;
840 if (damage == 0 ||
841 g_aeSpecialManeuver[victim] ==
844 return 0;
845
846 else if (g_aeObjectClass[victim] < OBJECT_CLASS_SHIP) {
847 g_asObjectDamage[victim] =
848 (short)(g_asObjectDamage[victim] + damage);
850 g_acObjectType[victim]].damageCapacity == -1)
851 return 0;
852 else if (g_aObjectTypeData[
853 g_acObjectType[victim]].damageCapacity <=
854 g_asObjectDamage[victim])
855 return explode(attacker, victim);
856 } else {
857 if (attacker != -1 &&
858 g_acObjectOwner[attacker] != -1 &&
859 g_asShipSide[victim] == SIDE_KILRATHI &&
861 (short)g_acObjectOwner[attacker]] ==
864 (short)g_acObjectOwner[attacker]] >=
866 return 0;
867 if (victim == 0) {
869 }
870 if (g_acObjectOwner[attacker] != -1 &&
872 (short)g_acObjectOwner[attacker]] ==
875 (short)g_acObjectOwner[attacker]] ==
876 g_asShipSide[victim])
878 (short)g_acObjectOwner[attacker]] = 40;
879 if ((short)g_acObjectOwner[attacker] ==
881 g_asWingmanDamageCredit[victim]++;
882 if (g_acObjectOwner[attacker] == 0)
884 (short)(g_asPlayerHitsCreditValues[victim] + 2);
885 if (attacker == g_nYourWingman && victim == 0)
887 if (attacker == 0 && victim == g_nYourWingman)
889 if (g_1_asObjectCreationFrameTable[attacker] !=
891 attacker != -1 &&
892 g_asShipSide[victim] == SIDE_IMPERIAL &&
893 g_acObjectOwner[attacker] == 0 &&
895 g_acShipTarget[attacker] == victim)) {
896 if (kilrathi_near(0, 30000) != 0) {
897 send_message(victim, 0x0c);
900 } else if (g_asShipSide[0] != SIDE_KILRATHI) {
903 send_message(victim, 0x0d);
906 } else {
907 send_message(victim, 0x0e);
911 g_nYourWingman = -1;
912 for (ally = 1; ally < 10; ally++) {
913 if (g_asShipSide[ally] == SIDE_IMPERIAL) {
914 if (g_aeObjectClass[ally] ==
916 g_asShipMissionType[ally] =
920 g_aeShipObjective[ally] =
922 g_acShipTarget[ally] = 0;
923 } else if (g_aeObjectClass[ally] >=
925 g_asShipMissionType[ally] =
927 g_asShipTactic[ally] =
929 }
930 }
931 }
932 }
933 }
934 }
935 quadrant = (short)(dot_product(
936 impactDirection, &g_aShipForwardVector[victim]) > 0);
937 if (g_anShipCloakState[victim] != 1 &&
938 g_asObjectType[attacker] != 0x13 &&
939 g_aasShipShield[victim][0] < 1000 &&
940 g_aasShipShield[victim][1] < 1000) {
941 protection = &g_aasShipShield[victim][quadrant];
942 damage = (short)(damage - *protection);
943 if (damage > 0) {
944 *protection = 0;
945 } else {
946 *protection = (short)-damage;
947 if (attacker != -1 &&
948 g_aeObjectClass[attacker] ==
950 if (victim == 0)
951 PlaySfxWaveFileByNumber(10, victim, 0);
952 else
953 PlaySfxWaveFileByNumber(10, victim, 0);
954 }
955 return 0;
956 }
957 }
958 if (attacker != -1 &&
959 g_aeObjectClass[attacker] ==
961 if (victim == 0)
962 PlaySfxWaveFileByNumber(9, victim, 0);
963 else
964 PlaySfxWaveFileByNumber(9, victim, 0);
965 }
966 sideProjection = dot_product(
967 impactDirection, &g_aShipRightVector[victim]);
968 if (sideProjection > 0xb5)
969 quadrant = 3;
970 else if (sideProjection < -0xb5)
971 quadrant = 2;
972 protection = &g_aasShipArmor[victim][quadrant];
973 damage = (short)(damage - *protection);
974 if (damage > 0) {
975 *protection = 0;
976 if (g_asObjectScreenX[victim] != (short)0x8001 &&
977 g_aeObjectClass[victim] <
979 RandomBelowOrEqual(1) == 0)
980 Create_ship_hit_debris(attacker, 1);
981 if (RandomBelowOrEqual(99) == 0) {
982 if (g_acObjectOwner[attacker] == 0) {
983 if (g_asShipSide[victim] == SIDE_KILRATHI)
984 send_message(victim, 0x1d);
985 destroyed = explode(attacker, victim);
986 }
987 } else {
988 destroyed = internal_damage(
989 attacker,
990 (short)g_acObjectOwner[attacker],
991 victim, damage, quadrant);
992 }
993 if (destroyed == 1) {
994 send_appropriate_message(attacker, victim);
995 if (g_asShipSide[victim] == SIDE_KILRATHI &&
996 g_acObjectOwner[attacker] == 0)
998 if (g_nYourWingman == victim)
1000 }
1001 return destroyed;
1002 } else {
1003 *protection = (short)-damage;
1004 return 0;
1005 }
1006 }
1007}
1008
1009/* Function start: 0x41262D */
1010short pilot_hit(short obj)
1011{
1012 if (g_acPilotHitPoints[obj] > 0) {
1013 g_acPilotHitPoints[obj]--;
1014 if (g_acPilotHitPoints[obj] == 0) {
1015 if (obj == 0) {
1016 if (g_bPlayerDamageEnabled != 0 &&
1018 g_nArcadeState = 4;
1019 return -1;
1020 }
1021 } else if (skill_check(obj, 9) == 0 && obj != 0) {
1022 g_asObjectCounter[obj] =
1023 (short)(RandomBelowOrEqual(20) + 30);
1025 }
1026 }
1027 return g_acPilotHitPoints[obj];
1028}
1029
1030/* Function start: 0x41270A */
1031short onboard_explosion(short obj)
1032{
1033 short debris;
1034 FixedVector offset;
1035
1036 debris = find_vacant_3d_object();
1037 if (debris != -1) {
1038 ((void (__cdecl *)(short, enum ObjectType, short, short))
1039 set_objects_data)(debris, (enum ObjectType)0x26, obj, 0);
1040 g_asObjectScale[debris] <<= 1;
1041 g_aShipVelocity[debris] =
1042 g_aShipVelocity[obj];
1043 g_asObjectCounter[debris] = 6;
1045 (short)(g_asObjectCollisionRadius[obj] >> 2),
1046 (short)(g_asObjectCollisionRadius[obj] >> 1),
1047 &offset);
1048 AddFixedVectors(&g_aShipPosition[obj], &offset,
1049 &g_aShipPosition[debris]);
1051 }
1052 return debris != -1;
1053}
1054
1055/* Function start: 0x41280B */
1056void call_enemy(short obj)
1057{
1058 short other;
1059
1060 other = 0;
1061 for (; other < 10; other++) {
1062 if (g_aeObjectClass[other] >= OBJECT_CLASS_SHIP &&
1063 g_aeSpecialManeuver[other] !=
1065 g_asShipSide[obj] != g_asShipSide[other] &&
1066 RandomBelow(100) < 50)
1067 g_acShipTarget[other] = obj;
1068 }
1069}
1070
1071/* CL 4.1 uses this declaration context when ordering the ship operands. */
1072short HasShipCockpitGunDisplay(short ship);
1073void rotate_object_to_goal(short obj);
1074short RandomBelow(short n);
1075
1076/* Function start: 0x4128A7 */
1077short internal_damage(short attacker, short owner, short victim,
1078 short damage, short quadrant)
1079{
1080 short system;
1081 short type;
1082 signed char weapon;
1083 short ship;
1084 short capacity;
1085
1086 if (victim == 0)
1087 return your_internal_damage(attacker, owner, damage, quadrant);
1088 type = (short)g_acObjectType[victim];
1089 capacity = g_aObjectTypeData[type].damageCapacity;
1091 if (g_asShipSide[victim] == SIDE_KILRATHI) {
1092 if (owner == 0)
1094 if (g_asObjectType[attacker] == 0x0d ||
1095 g_asObjectType[attacker] == 0x0e) {
1096 g_asObjectDamage[victim] = (short)(
1097 g_asObjectDamage[victim] + damage);
1098 } else if (g_asObjectType[attacker] == 0x13 &&
1099 damage > 100) {
1100 g_asObjectDamage[victim] = (short)(
1102 g_asObjectDamage[victim]);
1103 } else {
1104 g_asObjectDamage[victim] = (short)(
1105 g_asObjectDamage[victim] +
1106 MaxShort(1, (short)(damage >> 3)));
1107 }
1108 ship = attacker;
1109 if (owner != -1)
1110 ship = owner;
1111 if (ship != -1 && ship < 10 &&
1112 any_enemy(ship, 10000) == 0)
1113 call_enemy(ship);
1114 } else {
1115 if (g_asObjectType[attacker] == 0x0d ||
1116 g_asObjectType[attacker] == 0x0e) {
1117 g_asObjectDamage[victim] = (short)(
1118 g_asObjectDamage[victim] + damage);
1119 } else {
1120 g_asObjectDamage[victim] = (short)(
1121 g_asObjectDamage[victim] +
1122 MaxShort(1, (short)(damage / 10)));
1123 }
1124 if (RandomBelowOrEqual(1000) < 35 && attacker != 0 &&
1125 owner != 0)
1126 send_message(victim, 4);
1127 }
1128 if (g_asObjectDamage[victim] >= capacity)
1129 return explode(attacker, victim);
1130 else
1131 onboard_explosion(victim);
1132 return 0;
1133 } else {
1134 if (g_asPilotLevel[victim] == 5) {
1135 damage = MinShort(RandomInRange(3, 4),
1136 MaxShort(1, (short)(damage / 40)));
1137 } else {
1138 damage = MaxShort(1, (short)(damage / 6));
1139 }
1140 g_asObjectDamage[victim] =
1141 (short)(g_asObjectDamage[victim] + damage);
1142
1143 while (damage > 0) {
1144 if (damage == 1 && g_acShipPortrait[victim] != -1)
1145 system = 4;
1146 else
1147 system = RandomBelowOrEqual(9);
1148 switch (system) {
1149 case 8:
1150 if (quadrant != 0)
1151 break;
1152 if (g_acShipCommunicator[victim] != -1) {
1153 damage--;
1154 g_acShipCommunicator[victim] = -1;
1155 }
1156 break;
1157 case 0:
1158 /* The test has an empty body in the shipped game, so a pilot
1159 * hit always costs a point of damage. */
1160 if (pilot_hit(victim) != 0) {
1161 }
1162 damage--;
1163 break;
1164 case 6:
1165 if (quadrant != 0)
1166 break;
1167 if (g_acShipComputerDamage[victim] < 5) {
1168 damage--;
1169 g_acShipComputerDamage[victim]++;
1170 }
1171 break;
1172 case 5:
1173 if (quadrant != 0)
1174 break;
1175 if ((signed char)g_aShipWeapons[victim][0] > 0) {
1176 weapon = (signed char)RandomBelowOrEqual(
1177 (short)((signed char)
1178 g_aShipWeapons[victim][0] - 1));
1179 remove_weapon(victim, (short)weapon);
1180 damage--;
1181 }
1182 break;
1183 case 2:
1184 if (quadrant != 1)
1185 break;
1186 return explode(attacker, victim);
1187 case 3:
1188 g_aasShipMaximumShield[victim][0] = 0;
1189 g_aasShipShield[victim][0] = 0;
1190 g_aasShipMaximumShield[victim][1] = 0;
1191 g_aasShipShield[victim][1] = 0;
1192 break;
1193 case 4:
1194 damage--;
1195 g_acShipDamage[victim]++;
1196 if (g_asShipSide[victim] == SIDE_KILRATHI &&
1197 owner == 0)
1199 if ((short)g_acShipDamage[victim] > capacity)
1200 return explode(attacker, victim);
1201 break;
1202 case 7:
1203 if (quadrant != 1)
1204 break;
1205 damage--;
1206 drain_fuel(victim,
1207 (short)(*(int *)&g_aObjectTypeData[
1208 type].lifetime / 4));
1209 if (RandomBelowOrEqual(1) != 0 ||
1210 g_anShipFuel[victim] < 0)
1211 return explode(attacker, victim);
1212 break;
1213 case 1:
1214 if (quadrant != 1)
1215 break;
1216 damage--;
1217 damage_ion_drive(victim, 1, 3);
1218 break;
1219 }
1220 }
1221 }
1222 return 0;
1223}
1224
1225/* Function start: 0x412F03 */
1226void revise_shields(short obj)
1227{
1228 g_aasShipMaximumShield[obj][0] =
1229 MaxShort(0, (short)(g_aasShipMaximumShield[obj][0] -
1231 g_acObjectType[obj]].shieldFore >> 2)));
1232 g_aasShipMaximumShield[obj][1] =
1233 MaxShort(0, (short)(g_aasShipMaximumShield[obj][0] -
1235 g_acObjectType[obj]].shieldAft >> 2)));
1236}
1237
1238/* Function start: 0x412F90 */
1240{
1241 damage_your_component(3, 1, 3);
1242}
1243
1244/* Function start: 0x412FA9 */
1245short IsOnlyShipGun(short ship, short weapon)
1246{
1247 short otherGuns;
1248 short candidate;
1249
1250 otherGuns = 0;
1252 (signed char)((ShipWeaponSlot *)
1253 (g_aShipWeapons[ship] + 1))[weapon].weaponType].
1254 objectClass == OBJECT_CLASS_PROJECTILE) {
1255 candidate = 0;
1256 for (; candidate <
1257 (signed char)g_aShipWeapons[ship][0];
1258 candidate++) {
1259 if (weapon != candidate &&
1261 (signed char)((ShipWeaponSlot *)
1262 (g_aShipWeapons[ship] + 1))[weapon].
1263 weaponType].objectClass ==
1265 otherGuns++;
1266 }
1267 return otherGuns == 0;
1268 } else
1269 return 0;
1270}
1271
1272/* Function start: 0x413099 */
1273short your_internal_damage(short attacker, short owner, short damage,
1274 short quadrant)
1275{
1276 signed char roll;
1277 signed char system;
1278 short group;
1279 short craftType;
1280 signed char weapon;
1281
1282 if (g_aeObjectClass[attacker] ==
1284 if (quadrant != 1)
1285 group = 0;
1286 else
1287 group = 2;
1288 damage = MaxShort(1, (short)(damage >> 4));
1289 } else if (g_aeObjectClass[attacker] ==
1291 g_aeObjectClass[attacker] >=
1293 group = 4;
1294 damage = MaxShort(1, (short)(damage >> 7));
1295 } else {
1296 if (quadrant != 1)
1297 group = 1;
1298 else
1299 group = 3;
1300 damage = MaxShort(1, (short)(damage >> 5));
1301 }
1302 craftType = (short)g_acObjectType[0];
1303 roll = (signed char)RandomBelowOrEqual(10);
1304 g_asObjectDamage[0] =
1305 (short)(g_asObjectDamage[0] + damage);
1306 if (damage > 1) {
1309 }
1310
1311 while (damage > 0) {
1312 damage--;
1313 system = (signed char)g_aasPlayerDamageSystemTable[
1314 group][RandomBelowOrEqual(9)];
1315 switch (system) {
1316 case 8:
1317 if (quadrant != 0) {
1318 damage++;
1319 break;
1320 }
1321 if (roll < 7) {
1322 damage_your_component(4, 2, 3);
1323 if (g_acPlayerComponentDamage[4] >= 4)
1324 g_acShipCommunicator[0] = -1;
1325 } else {
1326 damage_your_component(5, 4, 4);
1327 }
1328 break;
1329 case 0:
1330 if (roll < 4) {
1331 pilot_hit(0);
1332 } else if (roll < 7) {
1333 damage_your_component(7, 2, 4);
1334 } else {
1335 damage_your_component(6, 4, 4);
1336 }
1337 break;
1338 case 6:
1339 if (quadrant != 0) {
1340 damage++;
1341 break;
1342 }
1343 if (g_acShipComputerDamage[0] < 5) {
1346 }
1347 break;
1348 case 5:
1349 if (quadrant != 0) {
1350 damage++;
1351 break;
1352 }
1353 if ((signed char)g_aShipWeapons[0][0] > 1) {
1354 weapon = (signed char)RandomBelowOrEqual(
1355 (short)((signed char)g_aShipWeapons[0][0] - 1));
1356 if (IsOnlyShipGun(0, (short)weapon) == 0) {
1357 remove_weapon(0, (short)weapon);
1359 "Weapon destroyed",
1360 g_cRedColour, 8);
1361 }
1362 }
1363 break;
1364 case 2:
1365 if (quadrant != 1) {
1366 damage++;
1367 break;
1368 }
1369 if (RandomBelowOrEqual(3) == 0)
1370 return explode(attacker, 0);
1371 if (damage_your_component(1, 1, 4) == 4)
1372 return explode(attacker, 0);
1373 break;
1374 case 3:
1375 if (roll < 9) {
1376 damage_your_component(2, 1, 4);
1377 revise_shields(0);
1378 } else {
1379 damage_your_component(8, 2, 4);
1380 }
1381 break;
1382 case 4:
1383 g_acShipDamage[0]++;
1384 if (g_acShipDamage[0] == 1) {
1385 /* A stray semicolon in the original: the retail test of
1386 * pilot_hit() branches to the decrement either way. */
1387 if (pilot_hit(0) != 0)
1388 ;
1389 damage--;
1390 } else if ((short)g_acShipDamage[0] >
1391 g_aObjectTypeData[craftType].
1392 damageCapacity) {
1393 return explode(attacker, 0);
1394 }
1395 break;
1396 case 7:
1397 drain_fuel(0,
1398 (short)(*(int *)&g_aObjectTypeData[
1399 craftType].lifetime / 4));
1400 if (RandomBelowOrEqual(1) != 0 ||
1401 g_anShipFuel[0] < 0)
1402 return explode(attacker, 0);
1404 "Fuel tanks hit",
1405 g_cRedColour, 8);
1406 break;
1407 case 1:
1408 if (quadrant != 1) {
1409 damage++;
1410 break;
1411 }
1412 damage_your_component(0, 1, 3);
1413 damage_ion_drive(0, 1, 3);
1414 break;
1415 }
1416 }
1417 return 0;
1418}
1419
1420/* Function start: 0x413578 */
1421short ReportComponentRepaired(short component, short minimumDamage)
1422{
1423 char message[80];
1424
1425 if (minimumDamage <
1426 (short)g_acPlayerComponentDamage[component]) {
1427 g_acPlayerComponentDamage[component]--;
1428 sprintf(message, "%s FIXD",
1429 g_apszComponentNames[component]);
1431 message, g_cRedColour, 8);
1432 return 1;
1433 } else {
1434 return 0;
1435 }
1436}
1437
1438/* Function start: 0x4135F1 */
1440{
1441 if (RandomBelowOrEqual(500) < 2) {
1442 switch (RandomBelowOrEqual(2)) {
1443 case 0:
1444 if (g_acPlayerComponentDamage[2] < 4)
1446 break;
1447 case 1:
1448 if (g_acPlayerComponentDamage[0] < 4) {
1449 if (ReportComponentRepaired(0, 2) != 0)
1450 damage_ion_drive(0, -1, 3);
1451 }
1452 break;
1453 case 2:
1455 g_acObjectType[0]].damageCapacity - 3 <
1456 (short)g_acShipDamage[0])
1457 g_acShipDamage[0]--;
1458 break;
1459 }
1460 }
1461}
1462
1463void AddFixedVectors(const FixedVector *left, const FixedVector *right,
1464 FixedVector *sum);
1465
1466/* Function start: 0x4136E2 */
1467void Create_ship_hit_debris(short obj, short count)
1468{
1469 FixedVector offset;
1470 short debris;
1471 short piece;
1472
1473 for (piece = 0; piece < count; piece++) {
1474 debris = find_vacant_3d_object();
1475 if (debris == -1)
1476 return;
1477 set_objects_data(debris,
1479 RandomBelowOrEqual(2)], -1, 0);
1480 g_asObjectCounter[debris] = 40;
1482 AddFixedVectors(&g_aShipPosition[obj], &offset,
1483 &g_aShipPosition[debris]);
1485 6, &g_aShipVelocity[debris]);
1487 }
1488}
1489
1490/* Function start: 0x4137C2 */
1492{
1493 short i;
1494 MissionObjective *objectiveData;
1495
1496 for (i = 0; i < 10; i++) {
1499 return;
1500 }
1501 if (g_nEscapedEnemyCount != 0)
1502 return;
1503 for (i = 0; i < (short)g_cMissionObjectiveCount; i++) {
1504 objectiveData = &g_aMissionObjectives[i];
1505 if (objectiveData->type == 5 &&
1506 objectiveData->index == g_nCurrentNavPoint) {
1507 flag_objective(i, 2);
1508 return;
1509 }
1510 }
1511}
1512
1513/* Function start: 0x4138A8 */
1515{
1516 short obj;
1517
1518 for (obj = 0; obj < 10; obj++) {
1519 if (g_aeObjectClass[obj] == OBJECT_CLASS_SHIP &&
1521 return;
1522 }
1524 if (g_ucPendingEjectionTransition != 0xff &&
1531 } else {
1534 }
1535 }
1536 if (set_up_next_wave() == 0) {
1537 for (obj = 1; obj < 10; obj++) {
1538 if (g_asShipSide[obj] == SIDE_KILRATHI &&
1540 return;
1541 }
1542 if (g_ucPendingEjectionTransition != 0xff) {
1545 }
1549 (short)(g_stCurrentPilotProfile.playerShipType + 300), 1);
1552 }
1553 }
1554}
1555
1556/* Function start: 0x413A3B */
1558{
1559 FixedVector vector;
1560 short fragment;
1561 short i;
1562 short index;
1563 short set;
1564
1565 for (i = 0; i < 5; i++) {
1567 g_acObjectType[obj]].resourceType ==
1568 g_aObjectResourceSlots[i].resourceType)
1569 break;
1570 }
1571 remove_object(obj);
1573 set = RandomBelowOrEqual(3);
1574 for (index = 0; index < 7; index++) {
1575 fragment = find_vacant_3d_object();
1576 if (fragment == -1)
1577 break;
1578 set_objects_data(fragment,
1579 g_aaeExplosionDebris[set][index], -1, 0);
1580 if (g_asObjectType[fragment] == OBJECT_DATA_SHIP_WING)
1581 g_apObjectShape[fragment] =
1583 g_asObjectCounter[fragment] = 40;
1585 AddFixedVectors(&g_aShipPosition[obj], &vector,
1586 &g_aShipPosition[fragment]);
1588 25, &g_aShipVelocity[fragment]);
1589 divide_vector(&g_aShipVelocity[obj], 0x200, &vector);
1590 AddFixedVectors(&vector,
1591 &g_aShipVelocity[fragment],
1592 &g_aShipVelocity[fragment]);
1593 RecordCannedSceneObjectEvent(fragment, 0);
1594 }
1595 for (index = 0; index < 8; index++) {
1596 fragment = find_vacant_3d_object();
1597 if (fragment == -1)
1598 break;
1600 AddFixedVectors(&g_aShipPosition[obj], &vector,
1601 &g_aShipPosition[fragment]);
1603 25, &g_aShipVelocity[fragment]);
1604 divide_vector(&g_aShipVelocity[obj], 0x200, &vector);
1605 AddFixedVectors(&vector,
1606 &g_aShipVelocity[fragment],
1607 &g_aShipVelocity[fragment]);
1608 g_asObjectScreenAngle[fragment] =
1609 (short)(RandomBelowOrEqual(3) + 0x10);
1612 g_acObjectType[fragment] =
1613 (signed char)g_asObjectType[fragment];
1614 g_asObjectCounter[fragment] = 40;
1615 RecordCannedSceneObjectEvent(fragment, 0);
1616 }
1618}
1619
1620/* Function start: 0x413D61 */
1621void affect_mission_score(short pilot, int event, short amount)
1622{
1623 short score;
1624
1625 switch (event) {
1626 case 0:
1627 score = amount;
1628 break;
1629 case 1:
1630 score = 7;
1631 break;
1632 case 2:
1633 score = 10;
1634 break;
1635 case 3:
1636 case 4:
1637 score = 15;
1638 break;
1639 case 5:
1640 score = 25;
1641 break;
1642 case 6:
1643 score = 50;
1644 break;
1645 case 7:
1646 score = 75;
1647 break;
1648 case 8:
1649 case 9:
1650 case 10:
1651 score = 25;
1652 break;
1653 case 11:
1654 score = (short)(amount * 2);
1655 break;
1656 default:
1657 score = amount;
1658 break;
1659 }
1661}
1662
1663/* Function start: 0x413E4C */
1664void score_for_kill(short pilot, short victim)
1665{
1666 int event;
1667
1668 if (g_asShipSide[victim] == SIDE_KILRATHI) {
1669 /* WC2 renumbered the craft table; the Kilrathi hulls that carry a
1670 * kill score sit at 48-58 and the retail image names none of them. */
1671 if (g_aeObjectClass[victim] == OBJECT_CLASS_BASE ||
1672 g_asObjectType[victim] == 58) {
1673 event = 7;
1674 } else {
1675 switch (g_asObjectType[victim]) {
1676 case 48:
1677 event = 1;
1678 break;
1679 case 49:
1680 event = 2;
1681 break;
1682 case 50:
1683 event = 3;
1684 break;
1685 case 52:
1686 case 53:
1687 event = 5;
1688 break;
1689 case 54:
1690 case 55:
1691 event = 4;
1692 break;
1693 case 56:
1694 case 57:
1695 event = 6;
1696 break;
1697 }
1698 }
1699 affect_mission_score(pilot, event, -1);
1700 }
1701}
1702
1703
1704/* Function start: 0x413F58 */
1705void analyze_kill(short attacker, short victim)
1706{
1707 short hostile;
1708 short initialShip;
1709
1710 hostile = g_asShipSide[attacker] !=
1711 g_asShipSide[victim];
1712 new_space_music_changes(attacker, victim);
1713 if (hostile != 0) {
1714 score_for_kill(attacker, victim);
1715 if (attacker == 0) {
1717 } else {
1718 for (initialShip = 0; initialShip < 8; initialShip++) {
1720 .initialMissionShips[initialShip] ==
1721 g_asShipMissionIndex[attacker])
1722 g_4_acInitialShipKillNumber[initialShip]++;
1723 }
1724 }
1725 }
1726}
1727
1728/* Function start: 0x414025 */
1729void explosion_shock_wave(short obj, short blastDamage)
1730{
1731 short target;
1732 FixedVector force;
1733 short range;
1734 short damage;
1735 FixedVector delta;
1736
1737 for (target = 0; target < 10; target++) {
1738 if (obj != target &&
1741 &g_aShipPosition[target], &delta);
1742 range = MaxShort(0,
1743 (short)(FixedToShortSaturating(Vector_magnitude(&delta)) -
1744 g_asObjectCollisionRadius[target]));
1745 if (range > 1000 ||
1747 ((g_asMissileProximityFuseValues[target] + 1) * 100 <
1748 range ||
1749 g_asShipTactic[target] != 4))) {
1750 damage = 0;
1751 } else {
1752 if (range > 750)
1753 range = 40;
1754 else if (range > 500)
1755 range = 30;
1756 else
1757 range = find_ratio(0, 500, range, 8, 25);
1758 damage = (short)((blastDamage / range) / range);
1759 if (obj != -1 &&
1760 g_aeObjectClass[target] >=
1764 damage = 0;
1765 if (target == 0)
1766 damage = MaxShort(1, (short)(damage * 3 >> 2));
1767 }
1768 if (damage > 1) {
1769 NormalizeFixedVector(&delta);
1770 ScaleFixedVector(&delta, (int)damage << 8, &force);
1771 apply_force_to_objects_center(&force, target);
1772 if (g_asObjectType[obj] != OBJECT_DATA_TORPEDO) {
1773 inflict_damage(obj, target,
1774 MinShort(200, damage), &delta);
1775 } else {
1776 inflict_damage(obj, target,
1777 MinShort(2500, (short)(damage * 4)),
1778 &delta);
1779 }
1780 }
1781 }
1782 }
1783}
1784
1785/* Function start: 0x4142C8 */
1786short ShipExplosion(short obj)
1787{
1788 unsigned short savedScale;
1789 short explosion;
1790 short explosionType;
1791
1792 savedScale = (unsigned short)g_asObjectScale[obj];
1793 explosion = find_vacant_3d_object();
1794 if (explosion == -1) {
1795 if (g_aeObjectClass[obj] >=
1798 g_asLoadedShipViewFrame[obj] = -1;
1799 explosion = obj;
1800 } else {
1801 copy_frame(obj, explosion);
1802 g_aShipPosition[explosion] =
1803 g_aShipPosition[obj];
1804 g_aShipVelocity[explosion] =
1805 g_aShipVelocity[obj];
1806 g_acObjectOwner[explosion] = (signed char)obj;
1807 }
1809 PlaySfxWaveFileByNumber(0x31, obj, 0);
1810 explosionType = OBJECT_DATA_EXPLOSION_MEDIUM;
1811 } else {
1812 explosionType = OBJECT_DATA_EXPLOSION_LARGE;
1813 }
1814 set_objects_data(explosion, explosionType,
1815 (short)g_acObjectOwner[explosion], 0);
1816 g_asObjectScale[explosion] = (short)(
1817 (unsigned short)g_asObjectScale[explosion] *
1818 savedScale >> 8);
1819 RecordCannedSceneObjectEvent(explosion, 0);
1820 return explosion;
1821}
1822
1823short ShipExplosion(short obj);
1824
1825/* Function start: 0x41444C */
1826short Explosion(short obj)
1827{
1828 short debris;
1829 short slot;
1830 short shipIndex;
1831
1832 debris = obj;
1833 if (g_aeObjectClass[obj] >= OBJECT_CLASS_SHIP) {
1834 shipIndex = -1;
1836 shipIndex = find_ship_index(obj);
1837 if (obj < 10 &&
1838 (g_asPilotLevel[obj] == 5 ||
1839 (shipIndex != -1 &&
1840 g_asShipMissionParameter[obj] == shipIndex) ||
1842 RandomBelow(100) < 40)) {
1843 if (g_asShipSide[obj] == 1)
1844 send_message(obj, 30);
1845 else
1846 send_message(obj, 8);
1847 }
1848 for (slot = 0; slot < 8; slot++) {
1850 g_asShipMissionIndex[obj]) {
1852 if (g_nYourWingman == obj)
1853 g_nYourWingman = -1;
1854 }
1855 }
1858 OBJECT_DATA_EXPLOSION_LARGE].shapeSet != 0)
1859 g_asObjectCounter[obj] = 8;
1860 else
1861 g_asObjectCounter[obj] = 4;
1863 OBJECT_DATA_EXPLOSION_LARGE].shapeSet != 0)
1865 else
1868 g_asShipMissionIndex[obj]].state = 3;
1870 for (slot = 0; slot < 4; slot++)
1871 onboard_explosion(obj);
1872 g_asObjectCounter[obj] = (short)(
1874 g_acObjectType[obj]].damageCapacity >> 2) +
1876 OBJECT_DATA_EXPLOSION_LARGE].shapeSet != 0 ? 8 : 4));
1877 g_7_asShipBurstStageCountdown[obj] = (short)(
1879 OBJECT_DATA_EXPLOSION_LARGE].shapeSet != 0 ?
1880 8 : 4) * 2);
1885 }
1886 } else {
1887 debris = ShipExplosion(obj);
1890 g_acObjectType[obj]].explosionDamage);
1891 }
1892 } else {
1894 g_asObjectScale[debris] = 0x380;
1897 g_acObjectType[obj]].explosionDamage);
1898 if (g_asObjectType[obj] == OBJECT_DATA_TORPEDO) {
1899 debris = obj;
1901 g_acObjectOwner[obj], 0);
1902 } else {
1903 debris = obj;
1905 g_acObjectOwner[obj], 0);
1906 }
1908 }
1909 if (g_asObjectScreenX[obj] != -32767)
1910 PlaySfxWaveFileByNumber(4, obj, 0);
1911 return debris;
1912}
1913
1914/* Function start: 0x414835 */
1915short explode(short attacker, short victim)
1916{
1917 short result;
1918 short object;
1919
1920 if (victim < 10)
1921 g_anShipCloakState[victim] = 2;
1922 if (g_bExplosionTraversalIdle != 0) {
1923 for (object = 0; object < SPACE_OBJECT_COUNT; object++)
1925 }
1927 if (g_10_abExplosionEntityDoneBytes[victim] != 0)
1928 return 1;
1929 else
1931 result = ResolveObjectDestruction(attacker, victim);
1933 return result;
1934}
1935
1936/* Function start: 0x4148F5 */
1937short ResolveObjectDestruction(short attacker, short victim)
1938{
1939 short objective;
1940
1941 if (victim < 10 && g_asPilotLevel[victim] == 5) {
1942 if (g_abPilotEjectionAttempted[victim] == 0) {
1944 g_acShipStress[victim] = 120;
1945 if (g_asShipSide[victim] == SIDE_IMPERIAL)
1947 g_acShipDamage[victim] =
1948 (signed char)(g_acShipDamage[victim] / 2);
1949 if (g_asShipSide[victim] == SIDE_KILRATHI)
1950 send_message(victim, 0x1d);
1951 return 0;
1952 } else if (RandomBelowOrEqual(1) == 0)
1953 return 0;
1954 }
1955 if (g_aeSpecialManeuver[victim] ==
1958 return 0;
1959 if (victim == 0) {
1960 if (g_bPlayerDamageEnabled == 0)
1961 return 0;
1962 else {
1964 if (g_bDeathSequenceActive == 0)
1965 g_nArcadeState = 4;
1966 return 1;
1967 }
1968 } else if (victim == g_nExternalViewShip)
1970 if (g_acObjectOwner[attacker] == -1) {
1971 } else {
1972 attacker = g_acObjectOwner[attacker];
1973 }
1974 if (attacker != -1 &&
1976 analyze_kill(attacker, victim);
1977 for (objective = 0; objective < MISSION_OBJECTIVE_COUNT;
1978 objective++) {
1979 if (g_aMissionObjectives[objective].type == 4 &&
1980 g_aMissionObjectives[objective].index ==
1981 g_asShipMissionIndex[victim]) {
1982 g_aMissionObjectives[objective].field_8 =
1983 (unsigned char)g_asShipMissionIndex[attacker];
1984 }
1985 }
1986 }
1987 if (victim < 10 && g_asShipSide[victim] != SIDE_KILRATHI &&
1988 g_abShipEjectionSequenceEnabled[victim] != 0) {
1990 return 0;
1991 else if (g_aeObjectClass[victim] == OBJECT_CLASS_SHIP) {
1993 return 1;
1994 }
1995 }
1996 Explosion(victim);
1997 return 1;
1998}
1999
2000short SpawnFlakBurst(short obj, short range, FixedVector *hardpoint,
2001 short burstMode);
2002void fire_flack(short owner, short explosion, short range,
2003 FixedVector *aim, short burstMode);
2004short hemisphere(FixedVector *target, FixedVector *parent,
2005 FixedVector *hardpoint);
2006
2007/* Function start: 0x414BE9 */
2008int send_at_point(short obj, FixedVector *point, short speed)
2009{
2011 &g_aShipVelocity[obj]);
2012 SetVectorFixedPoint((unsigned int *)&g_aShipVelocity[obj],
2013 speed);
2014}
2015
2016/* Function start: 0x414C39 */
2017short find_child_object(short parent, short objectClass)
2018{
2019 short obj;
2020
2021 for (obj = 0; obj < SPACE_OBJECT_COUNT; obj++) {
2022 if ((short)g_acObjectOwner[obj] == parent &&
2023 g_aeObjectClass[obj] == objectClass)
2024 return obj;
2025 }
2026 return -1;
2027}
2028
2029/* Function start: 0x414CA9 */
2030short find_child_ship(short parent, short objectClass,
2031 short target)
2032{
2033 short obj;
2034
2035 for (obj = 0; obj < 10; obj++) {
2036 if ((short)g_acObjectOwner[obj] == parent &&
2037 g_aeObjectClass[obj] == objectClass &&
2038 (target == -1 ||
2039 g_acShipTarget[obj] == target))
2040 return obj;
2041 }
2042 return -1;
2043}
2044
2045/* Function start: 0x414D3D */
2046int launch_object(short parent, short child, FixedVector direction,
2047 short speed)
2048{
2049 NormalizeFixedVector(&direction);
2051 &direction,
2052 &g_aShipVelocity[child]);
2053 ScaleFixedVector(&direction, (int)speed << 8, &direction);
2054 AddFixedVectors(&direction, &g_aShipVelocity[child],
2055 &g_aShipVelocity[child]);
2056}
2057
2058/* Function start: 0x414DC0 */
2059void fire(short obj, short target)
2060{
2061 short missileOk;
2062 short firedObject;
2063 short shouldFire;
2064 short ready;
2065 short distance;
2066 short weaponRange;
2067 short reachable;
2068 ObjectTypeData *stats;
2069 short slot;
2070 short weaponVelocity;
2071 short other;
2072 short type;
2073 FixedVector direction;
2074 short nearestRange;
2075
2076 ready = g_asObjectCounter[obj] <= 0;
2077 if (g_asShipFriendlyFireCooldown[obj] > 0)
2078 return;
2080 return;
2081
2082 distance = g_nTargetRange;
2083 if (RandomBelowOrEqual(0x13) == 0 &&
2084 RandomBelowOrEqual(7000) > distance)
2085 missileOk = 1;
2086 else
2087 missileOk = 0;
2088 if (missileOk != 0 &&
2090 g_nYourWingman == obj &&
2091 (unsigned short)RandomInRange(0, 100) > 10)
2092 missileOk = 0;
2093 if (missileOk != 0 &&
2094 find_child_ship(obj, OBJECT_CLASS_MISSILE, target) != -1)
2095 missileOk = 0;
2097 missileOk = 0;
2098
2099 slot = 0;
2100 for (; slot < (signed char)g_aShipWeapons[obj][0];
2101 slot++) {
2102 type = ((ShipWeaponSlot *)&g_aShipWeapons[obj][1])[
2103 slot].weaponType;
2104 stats = &g_aObjectTypeData[type];
2105 type = ((ShipWeaponSlot *)&g_aShipWeapons[obj][1])[
2106 slot].type;
2107 weaponVelocity = stats->maximumVelocity;
2108 weaponRange =
2109 (short)(*(int *)&stats->lifetime * weaponVelocity);
2110 reachable = weaponRange > distance;
2111 shouldFire = 0;
2112
2113 switch (stats->objectClass) {
2115 if (CanShipWeaponDamageTarget(obj, target) != 0 &&
2116 ready != 0 && reachable != 0) {
2117 switch (type) {
2118 case 7:
2119 shouldFire = g_nFacingToTarget > 70;
2120 break;
2121 case 10:
2122 shouldFire = g_nFacingToTarget > 80;
2123 break;
2124 case 8:
2125 shouldFire = g_nFacingToTarget > 80;
2126 break;
2127 case 9:
2128 shouldFire = g_nFacingToTarget > 85;
2129 break;
2130 case 13:
2131 shouldFire = g_nFacingToTarget > 55;
2132 break;
2133 case 12:
2134 shouldFire = g_nFacingToTarget > 10;
2135 break;
2136 }
2137 }
2138 if (shouldFire != 0)
2139 ((ShipWeaponSlot *)&g_aShipWeapons[obj][1])[
2140 slot].disabled = 0;
2141 else
2142 ((ShipWeaponSlot *)&g_aShipWeapons[obj][1])[
2143 slot].disabled = 1;
2144 if (shouldFire != 0) {
2145 firedObject = fire_weapon(obj, slot);
2146 if (g_anShipCloakState[obj] == 1)
2148 if (type == 12) {
2150 &g_aShipPosition[firedObject],
2151 &g_aShipPosition[target], &direction);
2152 launch_object(obj, firedObject, direction,
2153 real_velocity(firedObject));
2154 }
2155 }
2156 break;
2157
2159 if (missileOk != 0 && reachable != 0) {
2160 switch (type) {
2161 case 0x0f:
2162 shouldFire = g_nFacingToTarget > 0x61;
2163 if (CanShipWeaponDamageTarget(obj, target) == 0)
2164 shouldFire = 0;
2165 if (shouldFire != 0 &&
2166 g_asShipSide[obj] == SIDE_KILRATHI) {
2167 nearestRange = g_nTargetRange;
2168 other = 1;
2169 for (; other < 10; other++) {
2170 if (g_aeObjectClass[other] ==
2172 g_asShipSide[other] ==
2173 SIDE_KILRATHI) {
2174 get_facing_range_from_object(obj, other);
2175 if (g_nFacingToTarget > 0x5f &&
2176 g_nTargetRange < nearestRange) {
2177 shouldFire = 0;
2178 break;
2179 }
2180 }
2181 }
2182 get_facing_range_from_object(obj, target);
2183 }
2184 break;
2185 case 0x10:
2186 shouldFire = g_nFacingToTarget > 0x28 &&
2187 g_nTargetFacing < -0x3c;
2188 if (CanShipWeaponDamageTarget(obj, target) == 0)
2189 shouldFire = 0;
2190 break;
2191 case 0x12:
2192 shouldFire = g_nFacingToTarget > 0x28;
2193 if (CanShipWeaponDamageTarget(obj, target) == 0)
2194 shouldFire = 0;
2195 break;
2196 case 0x11:
2197 shouldFire = 1;
2198 if (CanShipWeaponDamageTarget(obj, target) == 0)
2199 shouldFire = 0;
2200 break;
2201 case 0x13:
2202 if (IsCapitalShipObject(target) != 0 &&
2203 g_nFacingToTarget > 0x50)
2204 shouldFire = 1;
2205 else
2206 shouldFire = 0;
2207 break;
2208 }
2209 }
2210 if (shouldFire != 0) {
2211 if (g_anShipCloakState[obj] == 1)
2213 fire_weapon(obj, slot);
2214 missileOk = 0;
2215 }
2216 break;
2217 }
2218 }
2219}
2220
2221/* Function start: 0x415508 */
2222short hemisphere(FixedVector *target, FixedVector *parent,
2223 FixedVector *hardpoint)
2224{
2225 FixedVector toHardpoint;
2226 FixedVector toTarget;
2227
2228 ComputeVectorDelta(hardpoint, parent, &toHardpoint);
2229 ComputeVectorDelta(target, parent, &toTarget);
2230 return vector_angle(toHardpoint, toTarget);
2231}
2232
2233/* Function start: 0x415563 */
2234void fire_flack(short owner, short explosion, short range,
2235 FixedVector *aim, short burstMode)
2236{
2237 short projectileVelocity;
2238 short lifetime;
2239
2240 projectileVelocity = g_aObjectTypeData[0x0c].maximumVelocity;
2241 set_objects_data(explosion, 0x0c, owner, 0);
2242 if (burstMode == 0) {
2243 lifetime = (short)(range / projectileVelocity - 5 -
2245 g_asObjectCounter[explosion] =
2246 MinShort(55, MaxShort(5, lifetime));
2247 } else {
2248 projectileVelocity = 220;
2249 g_asObjectCounter[explosion] =
2250 (short)(range / projectileVelocity);
2251 }
2252 send_at_point(explosion, aim, projectileVelocity);
2253 RecordCannedSceneObjectEvent(explosion, 0);
2254}
2255
2256/* Function start: 0x415625 */
2257short RandomSign(short v)
2258{
2259 if (RandomBelowOrEqual(1) != 0)
2260 return v;
2261 else
2262 return -v;
2263}
2264
2265/* Function start: 0x41565E */
2266int RandomFixedAimComponent(short radius, short speed, short maximum)
2267{
2268 short aim;
2269
2270 aim = RandomSign(MinShort(
2271 maximum, (short)(RandomBelowOrEqual(radius) + speed)));
2272 return aim << 8;
2273}
2274
2275/* Function start: 0x4156A7 */
2276short SpawnFlakBurst(short obj, short range, FixedVector *hardpoint,
2277 short burstMode)
2278{
2279 FixedVector randomAim;
2280 FixedVector burstPoint;
2281 FixedVector targetMotion;
2282 short target;
2283 short burstObject;
2284 short aimRadius;
2285 short velocity;
2286 short rollPercent;
2287 short predictionSteps;
2288
2289 target = g_acShipTarget[obj];
2290 burstObject = new_object(0x24, obj);
2291 if (burstObject != -1) {
2292 aimRadius = MaxShort(400, (short)(range >> 3));
2293 velocity = (short)(real_velocity(target) << 3);
2294 zero_vector(&randomAim);
2295 if (burstMode == 0) {
2296 randomAim.x =
2297 RandomFixedAimComponent(aimRadius, velocity, 1000);
2298 randomAim.y =
2299 RandomFixedAimComponent(aimRadius, velocity, 1000);
2300 randomAim.z =
2301 RandomFixedAimComponent(aimRadius, velocity, 1000);
2302 }
2303 AddFixedVectors(&g_aShipPosition[target], &randomAim,
2304 &burstPoint);
2305 rollPercent = RandomBelowOrEqual(100);
2306 if (burstMode != 0) {
2307 if (g_asObjectCounter[obj] <= 0) {
2308 g_aShipPosition[burstObject] = *hardpoint;
2309 predictionSteps = (short)(range / 70);
2310 if (predictionSteps < 0)
2311 predictionSteps = 0;
2312 if (predictionSteps > 20)
2313 predictionSteps = 20;
2315 predictionSteps << 8, &targetMotion);
2316 AddFixedVectors(&targetMotion, &burstPoint, &burstPoint);
2317 fire_flack(obj, burstObject, range, &burstPoint, burstMode);
2318 g_asObjectCounter[obj] =
2319 (short)(RandomBelow(10) + 7);
2320 }
2321 } else if ((g_asObjectCounter[obj] <= 0 && rollPercent < 40) ||
2322 rollPercent < 8) {
2323 g_aShipPosition[burstObject] = *hardpoint;
2324 fire_flack(obj, burstObject, range, &burstPoint, burstMode);
2325 g_asObjectCounter[obj] =
2326 (short)(RandomBelow(10) + 7);
2327 } else if (g_asObjectType[
2328 (signed char)g_acShipTarget[obj]] != 0x13) {
2329 g_aShipPosition[burstObject] = burstPoint;
2331 burstObject,
2332 g_aObjectTypeData[0x0c].explosionDamage);
2333 }
2334 }
2335 return burstObject;
2336}
2337
2338/* Function start: 0x41596F */
2339short HasShipActiveMissile(short obj)
2340{
2341 short other;
2342
2343 for (other = 0; other < 10; other++) {
2344 if (g_aeObjectClass[other] == OBJECT_CLASS_MISSILE &&
2345 g_acObjectOwner[other] == obj)
2346 return 1;
2347 }
2348 return 0;
2349}
2350
2351/* Function start: 0x4159DB */
2352short fire_turrets(short obj)
2353{
2354 short mounts;
2355 FixedVector mountOrigin;
2356 short startTarget;
2357 short targetHemisphere;
2358 short turret;
2359 short targetRange;
2360 short pick;
2361 short hostiles;
2362 short candidate;
2363 ShipWeaponSlot *fitting;
2364 short lockedShip;
2365
2366 mounts = 0;
2367 targetRange = 10000;
2368 if (g_asShipSide[obj] == SIDE_IMPERIAL)
2369 targetRange = 5000;
2370 hostiles = build_target_list(obj, targetRange);
2371 for (turret = 0;
2372 turret < (signed char)g_aShipWeapons[obj][0];
2373 turret++, fitting++) {
2374 if (((ShipWeaponSlot *)&g_aShipWeapons[obj][1])[
2375 turret].type == 0x0c)
2376 mounts++;
2377 }
2378
2379 fitting = (ShipWeaponSlot *)&g_aShipWeapons[obj][1];
2380 for (turret = 0;
2381 turret < (signed char)g_aShipWeapons[obj][0];
2382 turret++, fitting++) {
2383 if (fitting->type == 0x0d || fitting->type == 0x0e)
2384 continue;
2385 if ((g_asShipSide[obj] == SIDE_KILRATHI &&
2386 (unsigned short)RandomInRange(0, 200) <
2388 (g_asShipSide[obj] == SIDE_IMPERIAL &&
2389 RandomBelowOrEqual(2) == 0)) {
2390 position_child(obj, turret, &mountOrigin);
2391 if (fitting->type == 0x0c) {
2392 for (candidate = 1; candidate < 10; candidate++) {
2393 if (g_aeObjectClass[candidate] !=
2395 g_asObjectType[candidate] == 0x13 &&
2396 g_acShipTarget[candidate] == obj) {
2397 targetHemisphere = hemisphere(
2398 &g_aShipPosition[candidate],
2399 &g_aShipPosition[obj], &mountOrigin);
2400 if (g_asMissileProximityFuseValues[candidate] != 0 &&
2402 (short)(mounts * 4 - 1)) == 0) {
2403 g_acShipTarget[obj] =
2404 (signed char)candidate;
2405 g_asObjectCounter[obj] = 0;
2407 obj, distance_from_object(obj, candidate),
2408 &mountOrigin, 1);
2409 }
2410 }
2411 }
2412 }
2413 if (hostiles != 0) {
2414 startTarget = RandomBelowOrEqual(
2415 (short)(hostiles - 1));
2416 pick = startTarget;
2417 do {
2418 lockedShip = (short)g_acShipList[pick];
2419 targetHemisphere = hemisphere(
2420 &g_aShipPosition[lockedShip],
2421 &g_aShipPosition[obj], &mountOrigin);
2422 if (fitting->type != 0x0c &&
2423 g_aeObjectClass[lockedShip] >=
2425 if (targetHemisphere > 60 &&
2427 (short)(200 - GetAdaptiveTurnRate())) == 0 &&
2428 HasShipActiveMissile(obj) == 0) {
2429 if (fitting->type == 0x13) {
2430 if (IsCapitalShipObject(lockedShip) != 0) {
2431 g_acShipTarget[obj] =
2432 (signed char)lockedShip;
2433 fire_weapon(obj, turret);
2434 }
2435 } else {
2436 g_acShipTarget[obj] =
2437 (signed char)lockedShip;
2438 fire_weapon(obj, turret);
2439 }
2440 }
2441 break;
2442 }
2443 if (RandomBelowOrEqual(2) == 0) {
2444 g_acShipTarget[obj] =
2445 (signed char)lockedShip;
2447 obj, g_asShipListRange[pick],
2448 &mountOrigin, 0);
2449 break;
2450 }
2451 pick++;
2452 if (pick > hostiles - 1)
2453 pick = 0;
2454 } while (pick != startTarget);
2455 }
2456 }
2457 }
2458 return 1;
2459}
2460
2461void ScaleFixedVector(FixedVector *vector, int scale, FixedVector *result);
2462void copy_frame(short source, short destination);
2463
2464/* Function start: 0x415E2C */
2465short fire_weapon(short obj, short weapon)
2466{
2467 short triggerDistance;
2468 short leadRange;
2469 int interceptScale;
2470 short projectileSpeed;
2471 FixedVector travel;
2472 /* Retail reserves a travel here that nothing uses. */
2473 FixedVector unusedVector;
2474 FixedVector mountOffset;
2475 short typeCode;
2476 short weaponClass;
2477 short targetRange;
2478 short missile;
2479 ObjectTypeData *weaponData;
2480 short weaponDataIndex;
2481 short target;
2482
2483 projectileSpeed = 10;
2484 typeCode = ((ShipWeaponSlot *)&g_aShipWeapons[obj][1])[
2485 weapon].type;
2486 weaponDataIndex =
2487 ((ShipWeaponSlot *)&g_aShipWeapons[obj][1])[
2488 weapon].weaponType;
2489 weaponClass = g_aObjectTypeData[typeCode].objectClass;
2490 if (typeCode == 0x0c) {
2491 typeCode = 7;
2492 weaponClass = 8;
2493 }
2494 if (weaponClass == OBJECT_CLASS_MISSILE) {
2495 if (get_ship_slot() == -1) {
2496 for (target = 1; target < 10; target++) {
2497 if (g_aeObjectClass[target] ==
2499 g_asObjectType[target] == 0x14 &&
2500 g_acObjectOwner[target] == obj)
2501 explode(target, target);
2502 }
2503 }
2504 missile = initialize_ship(typeCode, obj, 0);
2505 } else {
2506 missile = new_object(typeCode, obj);
2507 }
2508 if (missile != -1) {
2509 weaponData = &g_aObjectTypeData[weaponDataIndex];
2510 copy_frame(obj, missile);
2511 if (weaponClass == OBJECT_CLASS_PROJECTILE) {
2512 g_asObjectDamage[missile] =
2513 weaponData->damageCapacity;
2514 projectileSpeed = g_aObjectTypeData[
2517 (short)(g_asShipWeaponEnergy[obj] -
2518 weaponData->animationDelay);
2519 }
2520 child_object(weapon, missile, obj);
2521 g_asObjectCounter[missile] =
2522 *(int *)&g_aObjectTypeData[
2523 weaponDataIndex].lifetime;
2525 &g_aShipForwardVector[missile],
2526 &g_aShipVelocity[missile]);
2527 if (weaponClass == OBJECT_CLASS_PROJECTILE) {
2528 if (obj == 0 && g_bTargetLockActive != 0 &&
2530 targetRange = distance_from_object(
2531 0, g_acShipTarget[0]);
2532 leadRange = (short)(targetRange + 100);
2533 } else {
2534 leadRange = (short)((*(int *)&weaponData->lifetime + 5) *
2535 weaponData->maximumVelocity);
2536 }
2538 leadRange << 8, &travel);
2539 AddFixedVectors(&g_aShipPosition[obj], &travel,
2540 &travel);
2541 point_at(missile, travel);
2542 }
2544 (int)projectileSpeed << 8, &travel);
2545 AddFixedVectors(&travel, &g_aShipVelocity[missile],
2546 &g_aShipVelocity[missile]);
2547 RecordCannedSceneObjectEvent(missile, 0);
2548 if (weaponClass == OBJECT_CLASS_MISSILE) {
2549 ScaleFixedVector(&g_aShipUpVector[obj], 0xa00,
2550 &travel);
2551 AddFixedVectors(&travel, &g_aShipVelocity[missile],
2552 &g_aShipVelocity[missile]);
2553 if (obj == 0 && typeCode != 0x14)
2555 else
2556 remove_weapon(obj, weapon);
2557 g_aeSpecialManeuver[missile] = -1;
2558 g_asShipManeuver[missile] =
2559 g_aeSpecialManeuver[missile];
2560 g_asShipTactic[missile] = 1;
2561 g_asPilotLevel[missile] = -1;
2563 g_asObjectCounter[missile] = 5;
2564 g_acObjectCollisionGraceTicks[missile] = 20;
2565 switch (typeCode) {
2566 case 0x0f:
2567 steady_object(missile);
2568 g_acShipTarget[missile] =
2569 g_acShipTarget[obj];
2570 g_asObjectCounter[missile] = 1;
2571 g_anShipSpeed[missile] =
2572 get_ship_max_velocity(missile) << 8;
2573 if (g_acShipTarget[missile] != -1) {
2576 g_acShipTarget[missile]], &travel);
2577 interceptScale =
2578 Vector_magnitude(&travel) /
2579 get_ship_max_velocity(missile);
2581 g_acShipTarget[missile]],
2582 interceptScale, &travel);
2584 g_acShipTarget[missile]], &travel,
2585 &travel);
2586 point_at(missile, travel);
2587 }
2588 break;
2589 case 0x10:
2590 case 0x12:
2591 g_acShipTarget[missile] =
2592 g_acShipTarget[obj];
2593 break;
2594 case 0x13:
2595 g_acShipTarget[missile] =
2596 g_acShipTarget[obj];
2597 if (g_nCurrentView == 4)
2598 g_acShipTarget[missile] =
2599 (signed char)g_nSavedPlayerTarget;
2600 triggerDistance = (short)(distance_from_object(
2601 obj, g_acShipTarget[missile]) / 1000);
2602 if (triggerDistance > 9 ||
2603 (unsigned short)RandomInRange(0, 15) <
2604 triggerDistance)
2605 g_asMissileProximityFuseValues[missile] = 1;
2606 else
2607 g_asMissileProximityFuseValues[missile] = 0;
2608 break;
2609 case 0x11:
2610 g_asObjectCounter[missile] = 15;
2611 g_acShipTarget[missile] = -1;
2612 break;
2613 case 0x14:
2614 g_asObjectCounter[missile] = 120;
2615 g_acShipTarget[missile] = -1;
2617 0xa00, &mountOffset);
2619 &mountOffset,
2620 &g_aShipVelocity[missile]);
2621 break;
2622 }
2623 }
2624 if (obj == 0) {
2625 if (weaponClass == OBJECT_CLASS_PROJECTILE) {
2626 g_asObjectCounter[obj] =
2628 typeCode - 7];
2629 if (g_asObjectType[0] == 0x33)
2630 g_asObjectCounter[obj] <<= 1;
2631 }
2632 } else if (obj == g_nYourWingman) {
2633 g_asObjectCounter[obj] =
2634 (short)(10 - (g_nAdaptiveDifficulty >> 1));
2635 } else {
2636 g_asObjectCounter[obj] =
2637 (short)(14 - g_nAdaptiveDifficulty);
2638 }
2639 switch (typeCode) {
2640 case 7:
2641 case 8:
2642 case 0x0d:
2643 PlaySfxWaveFileByNumber(8, missile, 0);
2644 break;
2645 case 9:
2646 case 0x0c:
2647 case 0x14:
2648 PlaySfxWaveFileByNumber(5, missile, 0);
2649 break;
2650 case 0x0a:
2651 PlaySfxWaveFileByNumber(0x27, missile, 0);
2652 break;
2653 case 0x0f:
2654 case 0x10:
2655 case 0x11:
2656 case 0x12:
2657 case 0x13:
2658 PlaySfxWaveFileByNumber(1, missile, 0);
2659 break;
2660 }
2661 }
2662 return missile;
2663}
2664
2665/* Function start: 0x416690 */
2666short find_weapon(short obj, short weaponType)
2667{
2668 short weapon;
2669
2670 for (weapon = 0;
2671 weapon < (signed char)g_aShipWeapons[obj][0];
2672 weapon++) {
2673 if (((ShipWeaponSlot *)&g_aShipWeapons[obj][1])[weapon].type ==
2674 weaponType)
2675 return weapon;
2676 }
2677 return -1;
2678}
2679
2680/* Function start: 0x41670E */
2681short fire_missile(short ship)
2682{
2683 short weapon;
2684 ShipWeaponSlot *index;
2685
2686 index = (ShipWeaponSlot *)&g_aShipWeapons[ship][1];
2687 for (weapon = 0;
2688 weapon < (signed char)g_aShipWeapons[ship][0];
2689 weapon++, index++) {
2692 if (ship != 0) {
2693 if (index->type != 0x13 ||
2695 return fire_weapon(ship, weapon);
2696 } else if (index->disabled == 0) {
2697 if ((index->type == 0x10 || index->type == 0x12 ||
2698 index->type == 0x13) &&
2700 if (get_mode(0) == 1)
2702 "Need Lock",
2703 g_cYellowColour, 3);
2704 return -1;
2705 }
2706 return fire_weapon(ship, weapon);
2707 }
2708 }
2709 }
2710 return -1;
2711}
2712
2713/* Function start: 0x41687F */
2715{
2716 ShipWeaponSlot *index;
2717 short weapon;
2718
2719 index = (ShipWeaponSlot *)&g_aShipWeapons[obj][1];
2720 for (weapon = 0;
2721 weapon < (signed char)g_aShipWeapons[obj][0];
2722 weapon++, index++) {
2725 index->type != 0x0b && index->disabled == 0) {
2726 if (fire_weapon(obj, weapon) == -1)
2727 break;
2728 }
2729 }
2730}
2731
2732/* Function start: 0x41693A */
2733void fire_afterburner(short obj, short time)
2734{
2735 if (g_asObjectType[obj] == 0x33)
2736 return;
2737 /* CL 4.1 folds these complements after ordering the operands. Keep
2738 * this value-preserving form for the retail limit-first comparison. */
2739 if (~~(get_ship_max_velocity(obj) * 0x500) >
2742 if (g_aeSpecialManeuver[obj] !=
2744 time = 0;
2745 g_asShipAfterburnerTimer[obj] = time;
2746 }
2747}
2748
2749/* Function start: 0x4169CC */
2750void fire_super_brake(short ship)
2751{
2752 g_asShipAfterburnerTimer[ship] = 10;
2754}
2755
2756/* Function start: 0x4169F3 */
2757short flip_angle(short ship, short angle)
2758{
2759 if ((g_asObjectFlip[ship] & 0x10) != 0)
2760 angle = (short)(180 - angle);
2761 if ((g_asObjectFlip[ship] & 0x20) != 0)
2762 angle = (short)-angle;
2763 angle += g_asObjectScreenAngle[ship];
2764 angle %= 360;
2765 if (angle < 0)
2766 angle += 360;
2767 return angle;
2768}
2769
2770/* Function start: 0x416A87 */
2772{
2773 short *exhaustTable;
2774 short shapeFrame;
2775 short scale;
2776 short object;
2777 short ship;
2778 short viewFrame;
2779 short tableOffset;
2780
2781 for (ship = 0; ship < 10; ship++) {
2783 g_anShipSpeed[ship] != 0 &&
2784 g_asObjectType[ship] != 0x14 &&
2785 g_aeSpecialManeuver[ship] !=
2787 g_aeSpecialManeuver[ship] !=
2789 if (g_anShipCloakState[ship] != 1) {
2790 if (ship == 0 && g_bJumpSequenceActive != 0)
2791 continue;
2792 if (g_asObjectScreenX[ship] != (short)0x8001) {
2793 exhaustTable =
2794 (short *)g_apObjectExhaustShape[ship];
2795 if (exhaustTable != 0) {
2796 viewFrame = g_asObjectViewFrame[ship];
2797 /* These ships load each view as a separate,
2798 * single-frame packet, so the loaded view's exhaust
2799 * records are used rather than frame zero within
2800 * that packet. */
2801 if (g_aeObjectClass[ship] >=
2803 g_asObjectType[ship] == 0x33 ||
2805 g_aeObjectClass[ship] ==
2807 viewFrame = g_asLoadedShipViewFrame[ship];
2808 tableOffset = exhaustTable[viewFrame];
2809 if (tableOffset != -1) {
2810 exhaustTable =
2811 (short *)((unsigned char *)exhaustTable +
2812 tableOffset);
2813 while (*exhaustTable != -1) {
2814 object = find_vacant_3d_object();
2815 if (object == -1)
2816 return;
2817 set_objects_data(object, 0x2b, ship, 0);
2818 shapeFrame = *exhaustTable++;
2819 scale = *exhaustTable++;
2820 if (g_aeObjectClass[ship] >=
2822 scale = (short)(scale +
2823 (unsigned short)RandomInRange(0x10,
2824 0x30));
2825 else
2826 scale = (short)(scale +
2827 (unsigned short)RandomInRange(0,
2828 0x20));
2829 if (g_acShipExhaustHeat[ship] == 0)
2830 scale = (short)(scale - 0x20);
2831 g_asObjectScale[object] = scale;
2832 g_asObjectDistance[object] =
2833 *exhaustTable++;
2834 g_asObjectScreenAngle[object] =
2835 flip_angle(ship, *exhaustTable++);
2836 g_asObjectFlip[object] = 0;
2837 g_asObjectScreenX[object] =
2838 *exhaustTable++;
2839 g_asObjectScreenY[object] =
2840 *exhaustTable++;
2841 if (g_aeSpecialManeuver[ship] ==
2843 g_asObjectViewFrame[object] =
2844 (short)(shapeFrame * 3 +
2845 (unsigned short)RandomInRange(
2846 0, 2));
2847 } else {
2848 g_asObjectViewFrame[object] =
2849 (short)((unsigned short)RandomInRange(
2850 0, 1) +
2851 shapeFrame * 2 + 12);
2852 }
2853 }
2854 }
2855 }
2856 }
2857 }
2858 }
2859 }
2860}
2861
2862/* Function start: 0x416DC3 */
2864{
2865 short angle;
2866 short child;
2867 int up;
2868 short owner;
2869 int right;
2870 long sine;
2871 long cosA;
2872
2873 for (child = 10; child <= SPACE_LAST_MOVING_OBJECT; child++) {
2874 if (g_aeObjectClass[child] ==
2876 owner = (short)g_acObjectOwner[child];
2877 switch (g_asObjectType[child]) {
2878 case 0x3e:
2879 g_asObjectDistance[child] =
2880 (short)((unsigned short)
2881 g_asObjectDistance[owner] -
2882 100);
2883 g_asObjectScreenX[child] =
2884 g_asObjectScreenX[owner];
2885 g_asObjectScreenY[child] =
2886 g_asObjectScreenY[owner];
2887 break;
2888 case 0x3f:
2889 g_asObjectDistance[child] =
2890 (short)((unsigned short)
2891 g_asObjectDistance[owner] +
2892 100);
2893 g_asObjectScreenX[child] =
2894 g_asObjectScreenX[owner];
2895 g_asObjectScreenY[child] =
2896 g_asObjectScreenY[owner];
2897 break;
2898 case 0x0c:
2899 case 0x2b:
2900 angle = g_asObjectScreenAngle[owner];
2901 sine = SinFixed(angle);
2902 cosA = CosFixed(angle);
2903 g_asObjectDistance[child] =
2904 (short)((unsigned short)
2905 g_asObjectDistance[owner] +
2906 (unsigned short)
2907 g_asObjectDistance[child]);
2908 right = g_asObjectScreenX[child];
2909 right *= (unsigned short)
2910 g_asObjectScreenScale[owner];
2911 if ((g_asObjectFlip[owner] & 0x10) != 0)
2912 right = -right;
2913 up = g_asObjectScreenY[child];
2914 up *= (unsigned short)
2915 g_asObjectScreenScale[owner];
2916 if ((g_asObjectFlip[owner] & 0x20) != 0)
2917 up = -up;
2918 g_asObjectScreenX[child] = (short)(
2919 (MultiplyFixed(right, (int)cosA) -
2920 MultiplyFixed(up, (int)sine)) >> 8);
2921 g_asObjectScreenY[child] = (short)(
2922 (MultiplyFixed(up, (int)cosA) +
2923 MultiplyFixed(right, (int)sine)) >> 8);
2924 g_asObjectScreenX[child] +=
2925 g_asObjectScreenX[owner];
2926 g_asObjectScreenY[child] +=
2927 g_asObjectScreenY[owner];
2928 break;
2929 }
2930 g_asObjectScreenScale[child] = (short)(
2931 (unsigned short)g_asObjectScale[child] *
2932 (unsigned short)g_asObjectScreenScale[owner] >>
2933 8);
2934 }
2935 }
2936}
2937
2938/* Function start: 0x4170F9 */
2940{
2941 if (0 < g_anShipSpeed[ship])
2942 drain_fuel(ship, 5);
2943}
2944
2945void ScaleFixedVector(FixedVector *vector, int scale, FixedVector *result);
2946short HasShipCockpitGunDisplay(short ship);
2947
2948/* Function start: 0x417124 */
2949void replenish_shields(short ship)
2950{
2951 signed char shield;
2952
2953 if (ship == 0 && g_acPlayerComponentDamage[1] > 0 &&
2955 (g_acPlayerComponentDamage[1] + 1) != 0)
2956 return;
2957 for (shield = 0; shield <= 1; shield++) {
2958 if (g_aasShipMaximumShield[ship][shield] <
2959 g_aasShipShield[ship][shield])
2960 g_aasShipShield[ship][shield] =
2961 g_aasShipMaximumShield[ship][shield];
2962 if (g_aasShipMaximumShield[ship][shield] >
2963 g_aasShipShield[ship][shield] &&
2966 g_acObjectType[ship]].animationDelay == 0) {
2967 g_aasShipShield[ship][shield]++;
2968 }
2969 }
2970}
2971
2972/* Function start: 0x41724A */
2974{
2975 short maximumShield;
2976 short shieldEnergy;
2977
2978 if (ship == 0 && g_acPlayerComponentDamage[1] != 0 &&
2979 (int)(unsigned short)RandomInRange(0, 4) <
2981 return;
2982 if (ship == 0 && HasShipCockpitGunDisplay(0) != 0) {
2983 if (g_nAimCameraMode == 0) {
2985 (short)(g_1_nGunShowEnergyPercent + 2), 100);
2986 } else if (g_nTargetCameraZoom < 0x21 &&
2987 g_nSpaceFrame % 2 == 0) {
2989 (short)(g_nTargetCameraZoom + 1), 0x21);
2990 }
2991 }
2992 if (g_asShipWeaponEnergy[ship] < 100) {
2993 shieldEnergy = (short)(g_aasShipShield[ship][1] +
2994 g_aasShipShield[ship][0]);
2995 maximumShield =
2996 (short)(g_aasShipMaximumShield[ship][1] +
2997 g_aasShipMaximumShield[ship][0]);
2998 if (maximumShield > shieldEnergy) {
2999 g_asShipWeaponEnergy[ship] =
3000 MinShort(
3001 (short)(g_asShipWeaponEnergy[ship] + 1),
3002 100);
3003 } else {
3004 g_asShipWeaponEnergy[ship] =
3005 MinShort(
3006 (short)(g_asShipWeaponEnergy[ship] + 2),
3007 100);
3008 }
3009 if (g_asShipWeaponEnergy[ship] < -5) {
3011 (short)(g_asShipWeaponEnergy[ship] + 1), 100);
3012 }
3013 }
3014}
3015
3016/* Function start: 0x41740F */
3017void accelerate(short amount)
3018{
3019 if (malf(0) != 0) {
3020 amount = (short)(amount - 2);
3021 if (g_nSpaceFrame % 3 == 0)
3022 PlaySfxWaveFileByNumber(3, -1, 0);
3023 }
3024 celerate(0, (int)amount << 8);
3025}
3026
3027/* Function start: 0x417471 */
3029{
3030 short time;
3031
3032 if (g_anShipFuel[0] > 0) {
3033 if (malf(0) != 0) {
3034 PlaySfxWaveFileByNumber(3, -1, 0);
3035 } else {
3036 if (g_aeSpecialManeuver[0] !=
3038 time = 8;
3039 } else if (g_asShipAfterburnerTimer[0] == 0) {
3040 time = 8;
3041 } else {
3042 if (g_asShipAfterburnerTimer[0] > 2)
3043 return;
3044 else
3045 time = 2;
3046 }
3047 fire_afterburner(0, time);
3048 if (g_nSpaceFrame >
3051 (int)g_nSpaceFrame + 6;
3052 PlaySfxWaveFileByNumber(12, -1, 0);
3053 }
3054 }
3055 }
3056}
3057
3058/* Linker commons defined here. LINK lays a unit's commons out by the
3059 * identifiers' hash keys, so these spellings follow the original addresses. */
3061short g_asWingmanDamageCredit[10]; /* 0x005d3830 */
3062short g_nAdaptiveDifficulty; /* 0x005d3844 */
3063short g_7_asShipBurstStageCountdown[10]; /* 0x005d3850 */
3064int g_3_bAfterburnerSfxActive; /* 0x005d3864 */
3066 SPACE_OBJECT_COUNT]; /* 0x005d3870 */
3067short g_asPlayerHitsCreditValues[10]; /* 0x005d38c0 */
3068short g_asMissileProximityFuseValues[16]; /* 0x005d38e0 */
void(__cdecl *g_pIxFree)(void *)
void SetVectorFixedPoint(unsigned int *p, short v)
Definition geom.c:754
int RandomFixedAimComponent(short radius, short speed, short maximum)
Definition ship.c:2266
void ComputeVectorDelta(FixedVector *from, FixedVector *to, FixedVector *delta)
Definition geom.c:229
void housekeep_power_plant_and_fuel(short ship)
Definition ship.c:2939
short your_internal_damage(short attacker, short owner, short damage, short quadrant)
Definition ship.c:1273
short get_mode(short i)
Definition cockpt.c:630
short HasShipActiveMissile(short obj)
Definition ship.c:2339
void replenish_shields(short ship)
Definition ship.c:2949
void damage_ion_drive(short ship, short amount, short maximum)
Definition geom.c:53
short kilrathi_near(short obj, short range)
Definition cockpt.c:395
void set_special(short ship, short special)
Definition logic.c:493
short pilot_hit(short obj)
Definition ship.c:1010
short ShipExplosion(short obj)
Definition ship.c:1786
short HasShipCockpitGunDisplay(short ship)
Definition ship.c:106
void fire_super_brake(short ship)
Definition ship.c:2750
short fire_missile(short ship)
Definition ship.c:2681
short MaxShort(short a, short b)
Definition disk.c:36
long MultiplyFixed(int left, int right)
Definition eventmgr.c:51
void IncreaseAdaptiveDifficulty(void)
Definition ship.c:152
int send_at_point(short obj, FixedVector *point, short speed)
Definition ship.c:2008
short explode(short attacker, short victim)
Definition ship.c:1915
void place_damage_on_cockpit(short damage)
Definition cockpt.c:3334
void FillFixedVectorWithRandomComponents(short limit, FixedVector *vector)
Definition geom.c:272
int dot_product(const FixedVector *left, const FixedVector *right)
Definition geom.c:316
signed char damage_your_component(char component, char amount, char maximum)
Definition cockpt.c:846
void Create_ship_hit_debris(short obj, short count)
Definition ship.c:1467
void remove_object(short obj)
Definition geom.c:858
void fire_afterburner(short obj, short time)
Definition ship.c:2733
long Vector_magnitude(const FixedVector *vector)
Definition eventmgr.c:157
void ejection_sequence(short outcome, signed char restoreCockpit)
Definition midscene.c:63
void Create_explosion_debris(short obj)
Definition ship.c:1557
void AddFixedVectors(const FixedVector *left, const FixedVector *right, FixedVector *sum)
Definition geom.c:211
unsigned int match_rotation_goal(short *rotation, short *goal, short totalError, short rate)
Definition ship.c:538
void position_child(short parent, short weapon, FixedVector *position)
Definition geom.c:801
void affect_mission_score(short pilot, int event, short amount)
Definition ship.c:1621
void check_next_wave(void)
Definition ship.c:1491
short RandomSign(short v)
Definition ship.c:2257
void rotate_object_to_goal(short obj)
Definition ship.c:576
void your_afterburner(void)
Definition ship.c:3028
void repair_internal_damage(void)
Definition ship.c:1439
void ScaleFixedVector(FixedVector *vector, int scale, FixedVector *result)
Definition geom.c:237
void replenish_weapon_energy_bank(short ship)
Definition ship.c:2973
short ShipHasCloakingDevice(short ship)
Definition ship.c:72
short onboard_explosion(short obj)
Definition ship.c:1031
void init_ijk(short obj)
Definition geom.c:453
int launch_object(short parent, short child, FixedVector direction, short speed)
Definition ship.c:2046
short FixedToShortSaturating(int value)
Definition geom.c:122
short get_ship_slot(void)
Definition geom.c:829
long SinFixed(short degrees)
Definition eventmgr.c:80
short MinShort(short a, short b)
Definition disk.c:27
void check_for_lost_control(short obj)
Definition ship.c:629
short any_enemy(short obj, short range)
Definition logic.c:610
short find_ratio(short inputMinimum, short inputMaximum, short input, short outputMinimum, short outputMaximum)
Definition logic.c:1013
short fire_weapon(short obj, short weapon)
Definition ship.c:2465
short get_ship_max_velocity(short obj)
Definition geom.c:9
short inflict_damage(short attacker, short victim, short damage, const FixedVector *impactDirection)
Definition ship.c:804
void InvalidateVduMode(short i)
Definition cockpt.c:714
short skill_check(short obj, short margin)
Definition logic.c:807
short CanShipWeaponDamageTarget(short ship, short target)
Definition ship.c:87
void analyze_kill(short attacker, short victim)
Definition ship.c:1705
short borrow_dust(void)
Definition ship.c:190
short ResolveObjectDestruction(short attacker, short victim)
Definition ship.c:1937
short distance_from_object(short obj, short other)
Definition geom.c:547
short find_child_object(short parent, short objectClass)
Definition ship.c:2017
short vector_angle(FixedVector left, FixedVector right)
Definition geom.c:324
unsigned int approach_speed(short ship, int targetSpeed)
Definition ship.c:682
void copy_frame(short source, short destination)
Definition geom.c:470
short SpawnFlakBurst(short obj, short range, FixedVector *hardpoint, short burstMode)
Definition ship.c:2276
void apply_force_to_objects_center(FixedVector *force, short obj)
Definition geom.c:895
short internal_damage(short attacker, short owner, short victim, short damage, short quadrant)
Definition ship.c:1077
void ResetShipCloakState(short ship)
Definition fl.c:105
short find_weapon(short obj, short weaponType)
Definition ship.c:2666
void steady_object(short ship)
Definition ship.c:698
short any_selected(unsigned char *loadout, short objectClass)
Definition ship.c:264
long CosFixed(short degrees)
Definition eventmgr.c:91
void RemovePlayerReleaseWeapon(signed char weapon)
Definition cockpt.c:872
void ShowComponentHitHudMessage(const char *text, unsigned short colour, short flashCount)
Definition cockpt.c:830
void InitializeShipWeaponTypeIndices(short obj)
Definition ship.c:328
short GetAdaptiveTurnRate(void)
Definition ship.c:137
void fire_fixed_projectile_weapon(short obj)
Definition ship.c:2714
short build_target_list(short obj, short range)
Definition logic.c:728
void animate_shape(short obj)
Definition spc.c:1261
void zero_vector(FixedVector *vector)
Definition geom.c:197
void child_object(short hardpoint, short child, short parent)
Definition geom.c:822
void SubtractFixedVectors(FixedVector *left, FixedVector *right, FixedVector *difference)
Definition geom.c:220
short real_velocity(short obj)
Definition ship.c:705
void revise_shields(short obj)
Definition ship.c:1226
void SortViableTargetsByDistance(void)
Definition ship.c:720
void select_new_gun(void)
Definition select.c:74
unsigned int fix_velocity(short obj)
Definition ship.c:712
short RandomBelow(short n)
Definition eventmgr.c:12
void MakeRandomVectorFixed(short minimum, short maximum, FixedVector *vector)
Definition geom.c:264
void check_computer_damage(void)
Definition ship.c:1239
short hemisphere(FixedVector *target, FixedVector *parent, FixedVector *hardpoint)
Definition ship.c:2222
short malf(char component)
Definition cockpt.c:811
void new_space_music_changes(short attacker, short victim)
Definition music.c:198
void BeginShipDestructionSequence(short obj)
Definition destroy.c:12
void remove_weapon(short obj, short weapon)
Definition ship.c:283
short ReportComponentRepaired(short component, short minimumDamage)
Definition ship.c:1421
short find_vacant_3d_object(void)
Definition geom.c:841
void place_exhaust_on_ships(void)
Definition ship.c:2771
short IsCapitalShipObject(short obj)
Definition ship.c:98
void reposition_fixed_child_objects(void)
Definition ship.c:2863
void get_facing_range_from_object(short obj, short other)
Definition geom.c:578
short flip_angle(short ship, short angle)
Definition ship.c:2757
short new_object(short type, short owner)
Definition ship.c:240
void PlaySfxWaveFileByNumber(int soundNumber, int sourceObject, int looping)
Definition music.c:490
short Explosion(short obj)
Definition ship.c:1826
void point_at(short obj, FixedVector point)
Definition geom.c:84
void fire(short obj, short target)
Definition ship.c:2059
void send_message(short obj, signed char message)
Definition cockpt.c:3116
void flag_objective(short objective, unsigned char flags)
Definition cockpt.c:1153
void call_enemy(short obj)
Definition ship.c:1056
void ProcessEnemyWaveCompletion(void)
Definition ship.c:1514
void RecordCannedSceneObjectEvent(short obj, int event)
Definition taperec.c:176
void fire_flack(short owner, short explosion, short range, FixedVector *aim, short burstMode)
Definition ship.c:2234
void divide_vector(FixedVector *vector, int divisor, FixedVector *result)
Definition geom.c:245
void TriggerPlayerHitPaletteFlash(void)
Definition main.c:309
void recalc_max_velocity(short ship)
Definition geom.c:28
short find_child_ship(short parent, short objectClass, short target)
Definition ship.c:2030
void score_for_kill(short pilot, short victim)
Definition ship.c:1664
void celerate(short ship, int delta)
Definition ship.c:668
short initialize_ship(short type, short owner, short matchLoadedType)
Definition ship.c:251
void select_new_release_weapon(short preferredType)
Definition select.c:83
short ShipHasTorpedo(short ship)
Definition ship.c:122
short IsOnlyShipGun(short ship, short weapon)
Definition ship.c:1245
void vector_component_in_dir(const FixedVector *vector, const FixedVector *direction, FixedVector *component)
Definition geom.c:375
void accelerate(short amount)
Definition ship.c:3017
void send_appropriate_message(short attacker, short victim)
Definition ship.c:750
short CountShipProjectiles(short ship)
Definition ship.c:57
short fire_turrets(short obj)
Definition ship.c:2352
short set_up_next_wave(void)
Definition mission.c:1054
void DecreaseAdaptiveDifficulty(void)
Definition ship.c:165
unsigned short RandomInRange(unsigned short lo, unsigned short hi)
Definition eventmgr.c:31
void FreePacketAndClear(void *slot, unsigned short releaseFlags)
Definition disk.c:45
void set_objects_data(short obj, short type, short owner, short matchObjectClass)
Definition ship.c:347
short find_ship_index(short missionShip)
Definition logic.c:251
unsigned int SignFixed(int v)
Definition geom.c:160
short initialize_object(short obj, short type, short owner, short matchLoadedType)
Definition ship.c:178
void reset_maneuver(short ship, short maneuver)
Definition logic.c:476
short RandomBelowOrEqual(short n)
Definition eventmgr.c:43
void explosion_shock_wave(short obj, short blastDamage)
Definition ship.c:1729
short NormalizeFixedVector(FixedVector *vector)
Definition geom.c:347
void drain_fuel(short ship, short amount)
Definition geom.c:45
short alert_flag(short ship, unsigned int bits)
Definition logic.c:25
int GetShipAccelerationRate(short ship)
Definition geom.c:62
Shared Win32 declarations, types and library interfaces.
#define OBJECT_DATA_CHAFF_POD
Definition game_data.h:1614
#define OBJECT_DATA_SPACE_DUST
Definition game_data.h:1637
#define OBJECT_DATA_DEBRIS_DUST
Definition game_data.h:1638
#define OBJECT_DATA_EXPLOSION_SMALL
Definition game_data.h:1630
#define SPACE_LAST_MOVING_OBJECT
Definition game_data.h:1579
@ MISSION_TYPE_NONE
Definition game_data.h:121
@ MISSION_TYPE_STRIKE
Definition game_data.h:124
#define OBJECT_DATA_O_RING
Definition game_data.h:1628
#define OBJECT_DATA_ROCK_CHUNK
Definition game_data.h:1622
#define OBJECT_DATA_ASTEROID6
Definition game_data.h:1621
#define OBJECT_DATA_EXPLOSION_MEDIUM
Definition game_data.h:1631
#define OBJECT_DATA_ASTEROID4
Definition game_data.h:1619
#define OBJECT_DATA_BURNING_DEBRIS
Definition game_data.h:1627
#define OBJECT_DATA_GIRDER_CHUNK
Definition game_data.h:1623
ObjectType
Definition game_data.h:54
@ SIDE_IMPERIAL
Definition game_data.h:175
@ SIDE_KILRATHI
Definition game_data.h:176
@ SIDE_NEUTRAL
Definition game_data.h:177
@ OBJECTIVE_DESTROY_SHIP
Definition game_data.h:143
#define OBJECT_DATA_METAL_SHEET
Definition game_data.h:1625
#define SPACE_OBJECT_COUNT
Definition game_data.h:1578
#define OBJECT_DATA_TORPEDO
Definition game_data.h:1613
#define OBJECT_DATA_SHIP_WING
Definition game_data.h:1626
#define OBJECT_DATA_ASTEROID5
Definition game_data.h:1620
#define OBJECT_DATA_ASTEROID1
Definition game_data.h:1616
@ SPECIAL_MANEUVER_BLOWING_UP
Definition game_data.h:268
@ SPECIAL_MANEUVER_SUPER_BRAKE
Definition game_data.h:263
@ SPECIAL_MANEUVER_UNKNOWN_9
Definition game_data.h:269
@ SPECIAL_MANEUVER_KILL_ENGINES
Definition game_data.h:265
@ SPECIAL_MANEUVER_AFTERBURNER
Definition game_data.h:261
@ SPECIAL_MANEUVER_NONE
Definition game_data.h:259
#define OBJECT_DATA_ASTEROID3
Definition game_data.h:1618
#define OBJECT_DATA_EXPLOSION_LARGE
Definition game_data.h:1632
#define OBJECT_DATA_PIPE
Definition game_data.h:1629
@ MANEUVER_OUTA_HERE
Definition game_data.h:230
#define OBJECT_DATA_SHIP_TUBING
Definition game_data.h:1624
#define MISSION_OBJECTIVE_COUNT
Definition game_data.h:1642
@ OBJECT_CLASS_FIXED_OBJECT
Definition game_data.h:44
@ OBJECT_CLASS_MISSILE
Definition game_data.h:48
@ OBJECT_CLASS_SHIP
Definition game_data.h:49
@ OBJECT_CLASS_DUST
Definition game_data.h:41
@ OBJECT_CLASS_DEBRIS
Definition game_data.h:43
@ OBJECT_CLASS_CAPITAL_SHIP
Definition game_data.h:50
@ OBJECT_CLASS_ASTEROID
Definition game_data.h:46
@ OBJECT_CLASS_PROJECTILE
Definition game_data.h:45
@ OBJECT_CLASS_MINE
Definition game_data.h:47
@ OBJECT_CLASS_NULL
Definition game_data.h:37
@ OBJECT_CLASS_BASE
Definition game_data.h:51
#define OBJECT_DATA_ASTEROID2
Definition game_data.h:1617
@ TACTIC_SELF_DEFENSE
Definition game_data.h:169
short g_nObjectType62Index
Definition ship.c:12
short g_asObjectScreenAngle[SPACE_OBJECT_COUNT]
Definition viewrect.c:97
short g_asObjectCollisionRadius[SPACE_OBJECT_COUNT]
Definition viewrect.c:120
short g_aasPlayerDamageSystemTable[5][10]
Definition ship.c:15
short g_aasShipMaximumShield[10][2]
Definition viewrect.c:133
short g_asShipAfterburnerTimer[10]
Definition viewrect.c:137
short g_bApplyingCollisionDamage
Definition spc.c:15
short g_asShipMissionParameter[12]
Definition viewrect.c:164
short g_nExternalViewShip
Definition viewrect.c:74
unsigned char * g_apObjectShape[SPACE_OBJECT_COUNT]
Definition viewrect.c:100
short g_asShipFriendlyFireCooldown[10]
Definition viewrect.c:183
signed char g_acPlayerComponentDamage[9]
Definition viewrect.c:76
short g_asObjectDistance[SPACE_OBJECT_COUNT]
Definition viewrect.c:104
short g_nYourWingman
Definition viewrect.c:75
short g_asCapitalHitDamageStepTable[10]
Definition mission.c:1465
signed char g_acGunRefireDelay[4]
Definition ship.c:54
short g_asPilotLevel[12]
Definition viewrect.c:157
short g_anObjectRollRotation[SPACE_OBJECT_COUNT]
Definition viewrect.c:119
short g_nFacingToTarget
Definition viewrect.c:45
short g_bAiMissileFiringEnabled
Definition ship.c:9
signed char g_acShipIonDriveDamage[16]
Definition viewrect.c:149
short g_nPendingEjectionSequenceCount
Definition mission.c:14
int g_nCurrentView
Definition spc.c:11
short g_7_asShipBurstStageCountdown[10]
Definition ship.c:3063
short g_bMissionEjectionPodSpawned
Definition destroy.c:9
short g_nObjectType63Index
Definition ship.c:13
signed char g_acShipCommunicator[16]
Definition viewrect.c:147
signed char g_acShipExhaustHeat[16]
Definition viewrect.c:145
short g_aeObjectClass[SPACE_OBJECT_COUNT]
Definition viewrect.c:125
signed char g_acLastCollisionObject[SPACE_OBJECT_COUNT]
Definition viewrect.c:123
signed char g_abProjectileCollisionBonus[SPACE_OBJECT_COUNT]
Definition viewrect.c:185
short g_asViableTargetDistance[10]
Definition viewrect.c:199
short g_nSelectedReleaseWeaponIndex
Definition viewrect.c:84
short g_nCurSeries
Definition main.c:2005
signed char g_acShipTarget[16]
Definition viewrect.c:167
short g_anObjectYawRotation[SPACE_OBJECT_COUNT]
Definition viewrect.c:118
short g_asObjectType[SPACE_OBJECT_COUNT]
Definition viewrect.c:124
unsigned char g_cYellowColour
Definition startup.c:547
short g_aasShipShield[10][2]
Definition viewrect.c:134
short g_nEjectionSequenceState
Definition mission.c:16
short g_asObjectFlip[SPACE_OBJECT_COUNT]
Definition viewrect.c:102
short g_anRollGoal[12]
Definition viewrect.c:132
signed char g_acShipComputerDamage[16]
Definition viewrect.c:146
ObjectTypeData g_aObjectTypeData[OBJECT_DATA_COUNT]
Definition campglob.c:310
short g_nEscapedEnemyCount
Definition jump.c:8
short g_asPlayerHitsCreditValues[10]
Definition ship.c:3067
FixedVector g_aShipForwardVector[SPACE_OBJECT_COUNT]
Definition viewrect.c:107
short g_asLoadedShipViewFrame[12]
Definition viewrect.c:154
short g_asObjectScreenX[SPACE_OBJECT_COUNT]
Definition viewrect.c:95
signed char g_abPilotEjectionAttempted[16]
Definition viewrect.c:188
short g_asWingmanDamageCredit[10]
Definition ship.c:3061
signed char g_cMissionObjectiveCount
Definition viewrect.c:66
unsigned char * g_pGenericMissileShape
Definition fltsetup.c:1061
short g_aeSpecialManeuver[12]
Definition viewrect.c:141
signed char g_acMissionShipStatusFlagsBytes[8]
Definition logic.c:1054
signed char g_acShipPortrait[12]
Definition viewrect.c:159
unsigned short g_asObjectScale[SPACE_OBJECT_COUNT]
Definition viewrect.c:115
int g_anShipFuel[10]
Definition viewrect.c:144
FixedVector g_aShipRightVector[SPACE_OBJECT_COUNT]
Definition viewrect.c:105
short g_anYawGoal[12]
Definition viewrect.c:131
short g_bJumpSequenceActive
Definition jump.c:10
short g_asShipWeaponEnergy[10]
Definition viewrect.c:136
short g_bMissileLockAcquired
Definition cockpt.c:104
short g_bDeathSequenceActive
Definition death.c:9
signed char g_10_abExplosionEntityDoneBytes[SPACE_OBJECT_COUNT]
Definition ship.c:3066
unsigned char g_ucPendingEjectionTransition
Definition mission.c:11
unsigned char * g_pGenericMissileExhaustShape
Definition fltsetup.c:1062
short g_nCurrentLevel
Definition main.c:2009
signed char g_acViableTarget[16]
Definition viewrect.c:198
signed char g_acObjectOwner[SPACE_OBJECT_COUNT]
Definition viewrect.c:122
short g_nSpaceFrame
Definition viewrect.c:32
short g_bExplosionTraversalIdle
Definition ship.c:53
short g_asObjectDamage[SPACE_OBJECT_COUNT]
Definition viewrect.c:121
short g_asObjectScreenScale[SPACE_OBJECT_COUNT]
Definition viewrect.c:103
short g_anObjectPitchRotation[SPACE_OBJECT_COUNT]
Definition viewrect.c:117
ShortPoint g_116_aWeaponDisplayPositions[16]
Definition cockpt.c:3804
short g_asShipTactic[12]
Definition viewrect.c:168
short g_nTargetFacing
Definition viewrect.c:46
short g_8_bUserDestroyedFlag
Definition gameflow.c:3809
signed char g_acShipList[16]
Definition viewrect.c:195
short g_asShipMaximumVelocity[12]
Definition viewrect.c:171
short g_asObjectAnimationIndex[SPACE_OBJECT_COUNT]
Definition viewrect.c:111
int g_nArcadeState
Definition main.c:1938
signed char g_acObjectCollisionGraceTicks[SPACE_OBJECT_COUNT]
Definition viewrect.c:114
short g_nSavedPlayerTarget
Definition turret.c:1265
short g_anPitchGoal[12]
Definition viewrect.c:130
int g_anShipSpeed[SPACE_OBJECT_COUNT]
Definition viewrect.c:116
unsigned char g_aShipWeapons[10][0xA1]
Definition viewrect.c:150
short g_aeShipHitDebrisTypes[4]
Definition ship.c:48
short g_asMissileProximityFuseValues[16]
Definition ship.c:3068
unsigned char g_cRedColour
Definition startup.c:548
signed char g_36_cPilotKillCountValue
Definition gameflow.c:3811
short g_9_nScreenMessageTimeNumber
Definition cockpt.c:3789
signed char g_abShipEjectionSequenceEnabled[12]
Definition viewrect.c:189
int g_anShipCloakState[10]
Definition viewrect.c:179
unsigned char * g_apObjectExhaustShape[10]
Definition viewrect.c:126
short g_bEjectionTriggerImmediately
Definition mission.c:15
signed char g_4_acInitialShipKillNumber[8]
Definition logic.c:1056
signed char g_acPilotHitPoints[16]
Definition viewrect.c:158
FixedVector g_aShipPosition[SPACE_OBJECT_COUNT]
Definition viewrect.c:108
short g_nLastAdaptiveDifficultyChangeFrame
Definition ship.c:11
short g_bExpandedShipGraphicsEnabled
Definition viewrect.c:49
short g_1_asObjectCreationFrameTable[SPACE_OBJECT_COUNT]
Definition ship.c:3069
FixedVector g_aShipUpVector[SPACE_OBJECT_COUNT]
Definition viewrect.c:106
short g_asShipManeuver[12]
Definition viewrect.c:169
short g_bPlayerDamageEnabled
Definition main.c:1946
short g_bEjectionWaitForEnemyWave
Definition mission.c:12
FixedVector g_aShipVelocity[SPACE_OBJECT_COUNT]
Definition viewrect.c:109
short g_asShipMissionIndex[12]
Definition viewrect.c:153
int g_3_bAfterburnerSfxActive
Definition ship.c:3064
short g_bTargetLockActive
Definition cockpt.c:9
signed char g_acShipStress[16]
Definition viewrect.c:187
short g_asShipTurretFireEnabled[10]
Definition turret.c:1269
short g_aeShipObjective[12]
Definition viewrect.c:166
ObjectResourceSlot g_aObjectResourceSlots[5]
Definition viewrect.c:72
MissionObjective g_aMissionObjectives[MISSION_OBJECTIVE_COUNT]
Definition viewrect.c:69
short g_nTargetCameraZoom
Definition turret.c:1238
signed char g_cViableTargetCount
Definition viewrect.c:197
short g_asShipListRange[16]
Definition viewrect.c:196
short g_nTargetRange
Definition viewrect.c:47
MissionShipRecord g_aMissionShips[MISSION_SHIP_COUNT]
Definition hotspot.c:240
short g_nSelectedGunType
Definition viewrect.c:83
short g_aasShipArmor[10][4]
Definition viewrect.c:135
int g_6_nPendingAfterburnerSfxFrame
Definition ship.c:3060
signed char g_acShipDamage[16]
Definition viewrect.c:148
signed char g_acShipLastAttacker[16]
Definition viewrect.c:138
PilotProfile g_stCurrentPilotProfile
Definition viewrect.c:73
short g_asShipMissionType[12]
Definition viewrect.c:163
short g_bFriendlyFireWarningIssued
Definition ship.c:10
short g_asShipSide[12]
Definition viewrect.c:139
signed char g_acObjectType[SPACE_OBJECT_COUNT]
Definition viewrect.c:101
short g_asDifficultyLevels[16][4]
Definition viewrect.c:23
short g_nCurrentNavPoint
Definition viewrect.c:53
short g_nLastFriendlyFireObjectFrame
Definition ship.c:14
short g_nAdaptiveDifficulty
Definition ship.c:3062
int g_nAimCameraMode
Definition turret.c:1279
signed char g_acObjectAnimationDelay[SPACE_OBJECT_COUNT]
Definition viewrect.c:112
short g_asObjectScreenY[SPACE_OBJECT_COUNT]
Definition viewrect.c:96
short g_asObjectCounter[SPACE_OBJECT_COUNT]
Definition viewrect.c:110
short g_1_nGunShowEnergyPercent
Definition turret.c:1278
MissionHeader g_13_stMissionHeaderBlock
Definition hotspot.c:253
short g_bMissionDeathSequencePending
Definition destroy.c:8
short g_nTargetLockCountdown
Definition viewrect.c:87
const char * g_apszComponentNames[9]
Definition damage.c:13
short g_asObjectViewFrame[SPACE_OBJECT_COUNT]
Definition viewrect.c:94
static short g_aaeExplosionDebris[4][7]
Definition ship.c:22
short initialMissionShips[8]
Definition game_data.h:1347
unsigned char field_8
Definition game_data.h:1418
signed char index
Definition game_data.h:1417
signed char state
Definition game_data.h:1380
unsigned char * field_12
Definition game_data.h:1403
short maximumVelocity
Definition game_data.h:377
unsigned char * animation
Definition game_data.h:379
short collisionRadius
Definition game_data.h:370
unsigned char weaponLoadout[0xA1]
Definition game_data.h:385
short objectClass
Definition game_data.h:367
short animationDelay
Definition game_data.h:373
short damageCapacity
Definition game_data.h:375
unsigned char * shapeSet
Definition game_data.h:392
short missionScore
Definition game_data.h:1122
short playerShipType
Definition game_data.h:1123
signed char weaponType
Definition game_data.h:418
signed char disabled
Definition game_data.h:417