-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathentity.cpp
More file actions
5968 lines (5463 loc) · 258 KB
/
entity.cpp
File metadata and controls
5968 lines (5463 loc) · 258 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* entity.cpp - Entity behavior loop and player movement sub-functions
* Addresses: FUN_0044b0b0 (Entity_Behavior_Loop), FUN_0044bb70, FUN_0044b990,
* FUN_0044bbb0, FUN_0044bf20, FUN_0044bfa0, FUN_0044e1c0,
* FUN_0044e510, FUN_00450630
*/
#include "tou.h"
#include <dinput.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
/* ===== Globals defined in this module ===== */
int DAT_00486944[4] = {0}; /* per-team stat counters A */
int DAT_00486954[4] = {0}; /* per-team stat counters B */
int DAT_00486964 = 0; /* team stat counter total */
int DAT_00486968[80] = {0}; /* per-player kills stat array */
int DAT_00486aa8[80] = {0}; /* per-player deaths stat array */
int DAT_00486be8[80] = {0}; /* per-player damage received stats */
int DAT_00486d28[80] = {0}; /* per-player building stats */
int DAT_00486e68[80] = {0}; /* per-player damage dealt stats */
int DAT_00486fa8[80] = {0}; /* per-player distance traveled */
int DAT_004870e8[80] = {0}; /* per-player explosion stats */
char DAT_00483747 = '\0'; /* weapon auto-release mode flag */
char DAT_00483745 = '\0'; /* detonation mode flag */
/* Positional sound globals */
char DAT_0048371f = 1; /* sound effects enabled flag */
/* DAT_00487840 is DAT_00487834[3] in the original binary — aliased via tou.h */
int DAT_0048382c = 0; /* game scaling constant 3 (fire rate scale) */
/* Float constants for positional audio (from binary at 0x4753xx) */
static float _DAT_004753fc = 6.6666667e-05f; /* 1.0f / 15000.0f */
static float _DAT_004753e8 = 1.0f; /* min distance clamp */
static double _DAT_004753e0_d = 0.4; /* very close threshold (double in original) */
/* Terrain/collision globals */
void *DAT_004876b8 = 0; /* color degradation palette LUT */
unsigned short DAT_00481e8c = 0; /* tile explosion color accumulator */
unsigned short DAT_00481e8e = 0; /* tile explosion count accumulator */
/* DAT_00487880 == g_PhysicsParams (defined in memory.cpp) */
char DAT_0048373b = '\0'; /* shared lives mode flag */
char DAT_00483744 = '\0'; /* respawn delay mode */
/* ===== AI / Pathfinding Globals ===== */
int DAT_00481eb4 = 0; /* pathfinding frontier count A */
int DAT_00481eb8 = 0; /* pathfinding frontier count B */
int DAT_00481ebc = 0; /* pathfinding frontier count C */
int DAT_00481ec0 = 0; /* pathfinding frontier count D */
int DAT_00481ec4 = 0; /* AI vision range X */
int DAT_00481ec8 = 0; /* AI vision range Y */
int *DAT_00481ea4 = NULL; /* pathfinding read buffer A */
int *DAT_00481e90 = NULL; /* pathfinding write buffer A */
int *DAT_00481e9c = NULL; /* pathfinding read count ptr A */
int *DAT_00481eac = NULL; /* pathfinding write count ptr A */
int *DAT_00481ea8 = NULL; /* pathfinding read buffer B */
int *DAT_00481e94 = NULL; /* pathfinding write buffer B */
int *DAT_00481ea0 = NULL; /* pathfinding read count ptr B */
int *DAT_00481eb0 = NULL; /* pathfinding write count ptr B */
int DAT_00481e98 = 0; /* pathfinding alternation flag */
/* Float/double constants from binary (AI decision making) */
static double _DAT_00475640 = 0.9; /* health retreat threshold */
static double _DAT_00475680 = 0.6; /* health aggression threshold */
static float _DAT_004757a4 = 0.05f; /* weapon cooldown scale */
static float _DAT_004757a0 = 500.0f; /* base fire rate bonus (no health cap) */
static float _DAT_0047579c = 2500.0f; /* energy cost scale */
static float _DAT_00475798 = 60.0f; /* minimum fire threshold */
static float _DAT_00475790 = 0.1f; /* velocity norm scale */
static float _DAT_0047578c = 0.0009f; /* velocity micro scale */
static float _DAT_00475788 = 1.4e-05f; /* velocity pico scale */
static float _DAT_00475784 = 7.0e-05f; /* distance micro scale */
static float _DAT_00475780 = 10240.0f; /* conveyor speed A */
static float _DAT_0047577c = 30720.0f; /* conveyor speed B */
static float _DAT_00475778 = 35840.0f; /* conveyor speed C */
static double _DAT_00475770 = 0.125; /* LOS distance scale */
static float _DAT_00475794 = 0.016666668f; /* fire rate norm (1/60) */
static float _DAT_004757a8 = 0.5f; /* melee velocity scale */
/* Weapon range data tables (from binary at 0x47ee0c) */
static int DAT_0047ee0c[4] = { 0x20, 0x19, 0x14, 0x12 }; /* base range per weapon level */
static int DAT_0047ee1c[4] = { 0x10, 0x0c, 0x09, 0x05 }; /* range bonus per weapon level */
static int DAT_0047ee2c[2] = { 0x02, 0x00 }; /* range minimum */
static int DAT_0047ee34[4] = { 0x07, 0x0a, 0x12, 0x28 }; /* step count per weapon level */
static float DAT_0047ee48[4] = { 0.5f, 0.6f, 0.9f, 1.0f }; /* weapon accuracy per level */
/* ===== FUN_0044f630 — Wall Segment Ripple Displacement (0044F630) ===== */
/* Finds nearest wall segment to impact point, then applies a sine-wave
* displacement across nearby segments to create a ripple/wobble effect.
* Called on wall bounce (FUN_0044f840) and particle-wall collision. */
static const double _DAT_004757d0 = 0.00005; /* ripple intensity scale */
void FUN_0044f630(int x, int y, int velX, int velY, float scale,
int maxDist, int spread, char direction)
{
int nearest = 0;
int bestDist = maxDist;
int tileX = x >> 0x12;
int tileY = y >> 0x12;
/* Phase 1: Find nearest wall segment (skip segment 0) */
if (DAT_004892c8 <= 1) return;
int *seg = (int *)((int)DAT_00487820 + 0x1c); /* start at segment[1] */
for (int i = 1; i < DAT_004892c8; i++) {
int dy = tileY - seg[1];
int dx = tileX - seg[0];
int absDy = dy < 0 ? -dy : dy;
int absDx = dx < 0 ? -dx : dx;
int dist = absDy + absDx;
if (dist < bestDist) {
nearest = i;
bestDist = dist;
}
seg = (int *)((char *)seg + 0x1c);
}
if (nearest == 0) return;
/* Phase 2: Compute ripple intensity from impact velocity */
int vxDiv4 = velX / 4; /* rounding toward zero (matches CDQ+AND+ADD+SAR) */
int absVx = vxDiv4 < 0 ? -vxDiv4 : vxDiv4;
int absVy = velY < 0 ? -velY : velY;
int speedFactor = (absVx + absVy) >> 9;
float intensity = (float)((float)speedFactor * scale * (float)_DAT_004757d0 * (float)spread);
/* Phase 3: Compute sine table step (byte offset per iteration) */
int step = 0x800 / (spread * 4);
int sinStepBytes = step * 4;
/* Phase 4: Apply ripple across segment range [nearest-spread+1, nearest+spread-1] */
int relOff = 1 - spread;
if (relOff >= spread) return;
int sinOffset = 0;
int segIdx = nearest + relOff;
int segByteOff = segIdx * 0x1c;
while (relOff < spread) {
if (segIdx >= 0 && segIdx < DAT_004892c8) {
/* Check segment is close enough to the nearest on the main axis */
int nearX = *(int *)((int)DAT_00487820 + nearest * 0x1c);
int segX = *(int *)((int)DAT_00487820 + segByteOff);
int xDiff = segX - nearX;
int absXDiff = xDiff < 0 ? -xDiff : xDiff;
int absRel = relOff < 0 ? -relOff : relOff;
if (absXDiff <= absRel) {
int sinVal = *(int *)((char *)DAT_00487ab0 + sinOffset);
float disp = (float)sinVal * intensity;
if (DAT_004892cc == -1) {
/* Vertical wall: displace field2 (offset +8) */
int *target = (int *)((int)DAT_00487820 + segByteOff + 8);
if (direction != 0)
*target = (int)((float)*target - disp);
else
*target = (int)(disp + (float)*target);
} else {
/* Horizontal wall: displace field3 (offset +0xC) */
int *target = (int *)((int)DAT_00487820 + segByteOff + 0xc);
if (direction != 0)
*target = (int)((float)*target - disp);
else
*target = (int)(disp + (float)*target);
}
}
}
sinOffset += sinStepBytes;
relOff++;
segByteOff += 0x1c;
segIdx++;
}
}
/* ===== FUN_0040fd70 — Positional Sound with Entity Dedup (0040FD70) ===== */
/* Manages per-entity sound state: if same sound is already playing, reset timer.
* If different sound, stop old one first. Uses spatial audio like FUN_0040f9b0.
* param_1: entity index (as float, cast to int), param_2: sound ID,
* param_3: world x, param_4: world y */
void FUN_0040fd70(int entity_idx, int param_2, int param_3, int param_4, int vol_override, int param6)
{
int iVar6 = entity_idx * 0x598;
/* If same sound already assigned to this entity, just refresh timer */
if (param_2 == *(int *)(iVar6 + 0x4b0 + (int)DAT_00487810)) {
if (0 < *(int *)(iVar6 + 0x4a8 + (int)DAT_00487810)) {
*(int *)(iVar6 + 0x4a8 + (int)DAT_00487810) = 6;
}
}
else {
/* Different sound — stop old channel and reset timer */
FSOUND_StopSound(*(int *)(iVar6 + 0x4ac + (int)DAT_00487810));
*(int *)(iVar6 + 0x4a8 + (int)DAT_00487810) = 0;
}
/* If timer is already active, don't re-trigger */
if (*(int *)(iVar6 + 0x4a8 + (int)DAT_00487810) != 0) return;
/* Check sound enabled and sample exists */
if (DAT_0048371f == '\0' || g_SoundEnabled == 0) return;
if (*(int *)((int)g_SoundTable + param_2 * 8) == 0) return;
/* Set timer and record which sound */
*(int *)(iVar6 + 0x4a8 + (int)DAT_00487810) = 6;
*(int *)(iVar6 + 0x4b0 + (int)DAT_00487810) = param_2;
float minDist = 10000.0f;
int iVar8 = 0xff;
/* Find nearest listener */
if (0 < DAT_00487808) {
int *pIdx = (int *)&DAT_004877f8;
int count = DAT_00487808;
do {
int *piVar1 = (int *)((int)DAT_00487810 + (*pIdx) * 0x598);
int iVar5 = (piVar1[1] - param_4) >> 0x12;
int iVar3 = (piVar1[0] - param_3) >> 0x12;
float fVar2 = (float)(iVar5 * iVar5 + iVar3 * iVar3) * _DAT_004753fc;
if (fVar2 < _DAT_004753e8) fVar2 = _DAT_004753e8;
if (fVar2 < minDist) {
iVar8 = *pIdx;
minDist = fVar2;
}
pIdx++;
count--;
} while (count != 0);
if (iVar8 != 0xff) {
/* Volume: table volume scaled by inverse distance
* Boosted ×4 for modern Windows audio stack */
int vol_byte = (int)*(unsigned char *)((int)g_SoundTable + param_2 * 8 + 4);
int vol = (int)((float)vol_byte / minDist) * 8;
/* Pan from angle to nearest listener */
int angle = FUN_004257e0(
*(int *)((int)DAT_00487810 + iVar8 * 0x598),
*(int *)((int)DAT_00487810 + iVar8 * 0x598 + 4),
param_3, param_4);
int pan = (*(int *)((int)DAT_00487ab0 + angle * 4) >> 0xc) + 0x80;
if (minDist < (float)_DAT_004753e0_d) pan = 0x80;
/* Clamp volume */
if (vol >= 0x100) vol = 0xff;
if (vol < 5) return;
/* Play with spatial properties */
int chan = FSOUND_PlaySoundEx(-1,
(FSOUND_SAMPLE *)(*(int *)((int)g_SoundTable + param_2 * 8)), NULL, 1);
FSOUND_SetVolume(chan, vol);
FSOUND_SetPan(chan, pan);
FSOUND_SetPaused(chan, 0);
/* Store channel handle for later management */
*(int *)(iVar6 + 0x4ac + (int)DAT_00487810) = chan;
}
}
}
/* ===== FUN_00450dd0 — Sprite-vs-Tile Collision Check (00450DD0) ===== */
/* Checks if sprite mask 0x19B overlaps any impassable tiles.
* Returns 1 if collision detected, 0 if clear. */
int FUN_00450dd0(int x, int y)
{
unsigned int spr_w = *(unsigned char *)((int)DAT_00489e8c + 0x19b);
int frame_off = *(int *)((int)DAT_00489234 + 0x66c);
unsigned int spr_h = (unsigned int)*(unsigned char *)((int)DAT_00489e88 + 0x19b);
int sx = (x >> 0x12) - (int)(spr_w >> 1);
int sy = (y >> 0x12) - (int)(spr_h >> 1);
unsigned int idx = (sy << ((unsigned char)DAT_00487a18 & 0x1f)) + sx;
/* Bounds check: sprite must be well within map margins */
if (sx <= 6 || sy <= 6 ||
(int)(spr_w + sx) >= DAT_004879f0 - 7 ||
(int)(spr_h + sy) >= DAT_004879f4 - 7)
{
return 1; /* out of bounds = collision */
}
int row = 0;
if (spr_h != 0) {
int tsy = sy;
do {
int col = 0;
int tx = sx;
if (spr_w != 0) {
do {
if ((*(char *)((int)DAT_00489e94 + frame_off) != '\0') &&
(0 < tx) && (tx < DAT_004879f0) &&
(0 < tsy) && (tsy < DAT_004879f4) &&
(*(char *)((unsigned int)*(unsigned char *)((int)DAT_0048782c + idx) *
0x20 + 1 + (int)DAT_00487928) == '\0'))
{
return 1; /* impassable tile hit */
}
frame_off++;
idx++;
col++;
tx++;
} while (col < (int)spr_w);
}
idx += DAT_00487a00 - spr_w;
row++;
tsy++;
} while (row < (int)spr_h);
}
return 0; /* no collision */
}
/* ===== FUN_004483c0 — Find Nearest Walkable Tile (004483C0) ===== */
/* Adjusts coordinates to the nearest walkable shadow-grid cell.
* Used by A* pathfinding to snap start/end to valid positions. */
static void FUN_004483c0(int *param_1, int *param_2)
{
int iVar1 = *param_2;
if (*(char *)((int)DAT_00489ea4 + DAT_00487a04 * iVar1 + *param_1) != '\0')
return;
int iVar5 = iVar1 - 1;
int local_c = -1;
int iVar3 = iVar5 * DAT_00487a04;
do {
if ((0 < iVar5) && (iVar5 < DAT_00487a08)) {
int iVar4 = -1;
int iVar2 = *param_1 - 1;
do {
if (((0 < iVar2) && (iVar2 < DAT_00487a04)) &&
(*(char *)((int)DAT_00489ea4 + iVar3 + iVar2) != '\0')) {
*param_2 = iVar1 + local_c;
*param_1 = *param_1 + iVar4;
return;
}
iVar4++;
iVar2++;
} while (iVar4 < 2);
}
iVar3 += DAT_00487a04;
local_c++;
iVar5++;
if (1 < local_c)
return;
} while (true);
}
/* ===== FUN_004495e0 — Dual Ray Wall Check (004495E0) ===== */
/* Fires two rays simultaneously; returns 1 if ray A hits wall first,
* 2 if ray B hits wall first, 0 if neither hits within 5 steps. */
static int FUN_004495e0(int param_1, int param_2, int param_3, int param_4,
int param_5, int param_6)
{
int iVar1 = param_1;
int iVar2 = iVar1;
int iVar3 = param_2;
int count = 0;
while (1) {
iVar1 += param_3;
param_2 += param_4;
iVar2 += param_5;
iVar3 += param_6;
if ((0 < iVar1) && (0 < param_2) &&
(iVar1 < (int)DAT_004879f0 * 0x40000) &&
(param_2 < (int)DAT_004879f4 * 0x40000) &&
(*(char *)((unsigned int)*(unsigned char *)((iVar1 >> 0x12) +
(int)DAT_0048782c +
((param_2 >> 0x12) << ((unsigned char)DAT_00487a18 & 0x1f))) *
0x20 + 1 + (int)DAT_00487928) == '\0'))
return 1;
if ((0 < iVar2) && (0 < iVar3) &&
(iVar2 < (int)DAT_004879f0 * 0x40000) &&
(iVar3 < (int)DAT_004879f4 * 0x40000) &&
(*(char *)((unsigned int)*(unsigned char *)((iVar2 >> 0x12) +
(int)DAT_0048782c +
((iVar3 >> 0x12) << ((unsigned char)DAT_00487a18 & 0x1f))) *
0x20 + 1 + (int)DAT_00487928) == '\0'))
return 2;
count++;
if (4 < count)
return 0;
}
}
/* ===== FUN_004494e0 — Forward Trajectory Collision (004494E0) ===== */
/* Checks if the entity's forward trajectory (based on ship speed/angle)
* will hit an impassable tile within 7 steps. Returns 1 if collision. */
static int FUN_004494e0(int param_1, int param_2, int param_3, int param_4, int param_5)
{
int iVar3 = param_5;
int count = 0;
int iVar2 = (int)DAT_00487810 + iVar3 * 0x598;
unsigned int uVar4 = (unsigned int)*(unsigned char *)(iVar3 * 0x40 + 0x23 + (int)DAT_0048780c);
iVar3 = *(int *)(iVar2 + 0x18);
signed char sVar1 = (signed char)((0 < *(int *)(iVar2 + 0xd4)) + 0xb);
while (1) {
param_3 += ((int)(*(int *)((int)DAT_00487ab0 + iVar3 * 4) * (int)uVar4) >> sVar1) * 0x40;
param_4 += ((int)(*(int *)((int)DAT_00487ab0 + 0x800 + iVar3 * 4) * (int)uVar4) >> sVar1) * 0x40;
param_1 += param_3;
param_2 += param_4;
if ((0 < param_1) && (0 < param_2) &&
(param_1 < (int)DAT_004879f0 * 0x40000) &&
(param_2 < (int)DAT_004879f4 * 0x40000) &&
(*(char *)((unsigned int)*(unsigned char *)((param_1 >> 0x12) +
(int)DAT_0048782c +
((param_2 >> 0x12) << ((unsigned char)DAT_00487a18 & 0x1f))) *
0x20 + 1 + (int)DAT_00487928) == '\0'))
return 1;
count++;
if (6 < count)
return 0;
}
}
/* ===== FUN_004497c0 — Dodge/Strafe Decision (004497C0) ===== */
/* Decides whether the AI should strafe left/right or move forward/backward
* based on the angle difference between facing and velocity direction. */
static void FUN_004497c0(int param_1, char param_2)
{
unsigned long long uVar6 = (unsigned long long)(unsigned int)FUN_004257e0(
0, 0, *(int *)(param_1 + 0x10), *(int *)(param_1 + 0x14));
unsigned int uVar3 = (unsigned int)(*(int *)(param_1 + 0x18) - (int)uVar6) & 0x7ff;
int iVar4 = 0x800 - (int)uVar3;
unsigned int uVar2 = (uVar3 - 0x400) & 0x7ff;
int thresh1, thresh2;
if (param_2 == '\0') {
thresh1 = 0x155;
thresh2 = 0x155;
} else {
thresh1 = 0xe3;
thresh2 = 0xe3;
}
if ((uVar3 < (unsigned int)thresh1) || (iVar4 < thresh1)) {
unsigned int uVar_b = *(unsigned int *)(param_1 + 0xb8);
unsigned int uVar_s = uVar_b | 0x40;
*(unsigned int *)(param_1 + 0xb8) = uVar_s;
if ((uVar_b & 4) != 0)
*(unsigned int *)(param_1 + 0xb8) = uVar_s ^ 4;
return;
}
if ((uVar2 < (unsigned int)thresh2) || (iVar4 < thresh2)) {
unsigned int uVar_b = *(unsigned int *)(param_1 + 0xb8);
unsigned int uVar_s = uVar_b | 4;
*(unsigned int *)(param_1 + 0xb8) = uVar_s;
if ((uVar_b & 0x40) != 0)
*(unsigned int *)(param_1 + 0xb8) = uVar_s ^ 0x40;
}
}
/* ===== FUN_004496e0 — Line-of-Sight Step Check (004496E0) ===== */
/* Walks from (param_1,param_2) toward (param_3,param_4) in tile-sized steps.
* Returns 1 (as long long) if LOS is clear, 0 if blocked. */
static long long FUN_004496e0(int param_1, int param_2, int param_3, int param_4, char param_5)
{
int dx = param_3 - param_1;
int dy = param_4 - param_2;
/* Compute step count from distance: sqrt(dx_tile^2 + dy_tile^2) * 0.125 */
int dx_tile = dx >> 0x12;
int dy_tile = dy >> 0x12;
int dist_sq = dx_tile * dx_tile + dy_tile * dy_tile;
int uVar1 = (int)(sqrt((double)dist_sq) * _DAT_00475770); /* __ftol */
if (uVar1 != 0) {
if (param_5 != '\0') {
if (0x18 < uVar1) return 0LL;
} else {
if (0x10 < uVar1) return 0LL;
}
if (0 < uVar1) {
int step_dx = dx / uVar1;
int step_dy = dy / uVar1;
int steps = 0;
do {
param_2 += step_dy;
param_1 += step_dx;
unsigned int tileOff = (unsigned int)*(unsigned char *)((param_1 >> 0x12) +
(int)DAT_0048782c +
((param_2 >> 0x12) << ((unsigned char)DAT_00487a18 & 0x1f))) * 0x20;
if (*(char *)(tileOff + 1 + (int)DAT_00487928) == '\0')
return 0LL;
steps++;
} while (steps < uVar1);
}
}
return 1LL;
}
/* ===== FUN_0044de10 — Validate Spawn Position (0044DE10) ===== */
/* Checks a 16x16 tile area is fully passable. Returns 1 if valid. */
static unsigned int FUN_0044de10(int param_1, unsigned int param_2)
{
if (param_1 <= 0xd || param_1 >= (int)DAT_004879f0 - 0xe ||
(int)param_2 <= 0xd || (int)param_2 >= (int)DAT_004879f4 - 0xe)
return 0;
int iVar3 = 0;
unsigned int idx = ((param_2 - 8) << ((unsigned char)DAT_00487a18 & 0x1f)) - 8 + param_1;
do {
int iVar2 = 0;
do {
unsigned int uVar1 = idx++;
if (*(char *)((unsigned int)*(unsigned char *)((int)DAT_0048782c + uVar1) *
0x20 + 1 + (int)DAT_00487928) == '\0')
return 0;
iVar2++;
} while (iVar2 < 0x10);
iVar3++;
idx = (idx - 0x10) + DAT_00487a00;
if (0xf < iVar3)
return 1;
} while (1);
}
/* ===== FUN_0044ab20 — Find Nearest Enemy Player (0044AB20) ===== */
/* Scans all players for the nearest enemy within AI vision range.
* Returns (index << 8) | 1 if found, or count & 0xFFFFFF00 if not. */
static unsigned int FUN_0044ab20(int *param_1)
{
int iVar5 = (DAT_00481ec8 >> 0x12) * (DAT_00481ec8 >> 0x12);
unsigned int uVar6 = 0;
unsigned int local_4 = 0xffffffff;
unsigned int uVar2 = (unsigned int)DAT_00489240;
if (0 < DAT_00489240) {
char *pcVar4 = (char *)((int)DAT_00487810 + 0x24);
do {
if ((pcVar4[8] != (char)param_1[0xb]) && (*pcVar4 == '\0')) {
int iVar3 = (*(int *)(pcVar4 - 0x20) - param_1[1]) >> 0x12;
int iVar1 = (*(int *)(pcVar4 - 0x24) - *param_1) >> 0x12;
iVar1 = iVar1 * iVar1 + iVar3 * iVar3;
if (iVar1 < iVar5) {
iVar5 = iVar1;
local_4 = uVar6;
}
}
uVar6++;
pcVar4 += 0x598;
} while ((int)uVar6 < DAT_00489240);
uVar2 = local_4;
if (local_4 != 0xffffffff)
return (local_4 & 0xffffff00) | 1;
}
return uVar2 & 0xffffff00;
}
/* ===== FUN_0044ac80 — Check Wall Above/Below for Evasion (0044AC80) ===== */
/* Checks tiles directly above and below entity for solid walls.
* Sets movement flags for evasion. Returns 1 if wall found. */
static unsigned int FUN_0044ac80(int *param_1)
{
unsigned int uVar2 = (unsigned int)param_1[1] >> 0x12;
unsigned char bVar4 = (unsigned char)DAT_00487a18;
int iVar5 = *param_1 >> 0x12;
/* Check tile below (+1 row) */
if (*(char *)((unsigned int)*(unsigned char *)((int)DAT_0048782c +
((uVar2 + 1) << (bVar4 & 0x1f)) + iVar5) * 0x20 + 0x18 + (int)DAT_00487928) != '\0') {
int idx = (uVar2 << (bVar4 & 0x1f)) + iVar5;
char cVar1 = *(char *)((unsigned int)*(unsigned char *)((int)DAT_0048782c + idx) *
0x20 + 4 + (int)DAT_00487928);
if (cVar1 != '\0') {
param_1[0x2e] |= 4;
}
return 1;
}
/* Check tile above (-1 row) */
if (*(char *)((unsigned int)*(unsigned char *)(((uVar2 - 1) << (bVar4 & 0x1f)) +
iVar5 + (int)DAT_0048782c) * 0x20 + 0x18 + (int)DAT_00487928) != '\0') {
int idx = (uVar2 << (bVar4 & 0x1f)) + iVar5;
char cVar1 = *(char *)((unsigned int)*(unsigned char *)((int)DAT_0048782c + idx) *
0x20 + 4 + (int)DAT_00487928);
if (cVar1 == '\0') {
param_1[0x2e] |= 4;
}
return 1;
}
return 0;
}
/* ===== FUN_00449420 — Projectile Trajectory Prediction (00449420) ===== */
/* Predicts if a projectile from entity will hit a solid wall or
* leave the map. Returns 1 if it will hit a wall. */
static int FUN_00449420(int *param_1)
{
int iVar2 = *param_1;
int iVar3 = param_1[1];
int vx = param_1[4] << 3;
int vy = param_1[5] << 3;
int count = 0;
do {
iVar2 += vx;
iVar3 += vy;
vy += DAT_00483824 * 0x40;
if ((0 < iVar2) && (0 < iVar3) &&
(iVar2 < (int)DAT_004879f0 * 0x40000) &&
(iVar3 < (int)DAT_004879f4 * 0x40000)) {
unsigned int tileOff = (unsigned int)*(unsigned char *)((iVar2 >> 0x12) +
(int)DAT_0048782c +
((iVar3 >> 0x12) << ((unsigned char)DAT_00487a18 & 0x1f))) * 0x20;
if (*(char *)(tileOff + 0x18 + (int)DAT_00487928) != '\0')
return 1;
if (*(char *)(tileOff + (int)DAT_00487928 + 1) == '\0')
return 0;
}
count++;
if (0xe < count)
return 0;
} while (1);
}
/* ===== FUN_0044aa50 — Find Nearest Waypoint/Ammo Pickup (0044AA50) ===== */
/* Scans edge/waypoint records for nearest one matching entity's team.
* Sets target position if found. Returns (index << 8) | 1 on success. */
static unsigned int FUN_0044aa50(int *param_1)
{
int iVar1 = -1;
int iVar5 = 0;
int iVar4 = 999999999;
int local_4 = -1;
if (0 < DAT_00489254) {
char *pcVar3 = (char *)((int)DAT_00489e84 + 8);
do {
if ((*pcVar3 == (char)param_1[0xb]) || (*pcVar3 == (char)-1)) {
iVar1 = (*(int *)(pcVar3 - 4) - param_1[1]) >> 0x12;
int iVar2 = (*(int *)(pcVar3 - 8) - *param_1) >> 0x12;
iVar2 = iVar2 * iVar2 + iVar1 * iVar1;
iVar1 = local_4;
if (iVar2 < iVar4) {
iVar1 = iVar5;
iVar4 = iVar2;
local_4 = iVar5;
}
}
iVar5++;
pcVar3 += 0x10;
} while (iVar5 < DAT_00489254);
if (iVar1 != -1) {
iVar1 *= 0x10;
param_1[0x114] = *(int *)(iVar1 + (int)DAT_00489e84);
int iVar4_2 = *(int *)(iVar1 + 4 + (int)DAT_00489e84);
param_1[0x116] = 0;
param_1[0x115] = iVar4_2;
return (((unsigned int)iVar1) & 0xffffff00) | 1;
}
}
return (unsigned int)DAT_00489254 & 0xffffff00;
}
/* ===== FUN_0044abb0 — Find Nearest Enemy and Set Target (0044ABB0) ===== */
/* Scans players for nearest enemy, sets targeting data on entity. */
static void FUN_0044abb0(int *param_1)
{
int iVar5 = (DAT_00481ec8 >> 0x12) * (DAT_00481ec8 >> 0x12);
int iVar1 = -1;
int iVar4 = 0;
int local_4 = -1;
if (0 < DAT_00489240) {
char *pcVar3 = (char *)((int)DAT_00487810 + 0x24);
do {
if ((pcVar3[8] != (char)param_1[0xb]) && (*pcVar3 == '\0')) {
int iVar2 = (*(int *)(pcVar3 - 0x20) - param_1[1]) >> 0x12;
iVar1 = (*(int *)(pcVar3 - 0x24) - *param_1) >> 0x12;
iVar2 = iVar1 * iVar1 + iVar2 * iVar2;
iVar1 = local_4;
if (iVar2 < iVar5) {
iVar1 = iVar4;
iVar5 = iVar2;
local_4 = iVar4;
}
}
iVar4++;
pcVar3 += 0x598;
} while (iVar4 < DAT_00489240);
if (iVar1 != -1) {
param_1[0x10e] = *(int *)(iVar1 * 0x598 + (int)DAT_00487810);
iVar1 = *(int *)(iVar1 * 0x598 + 4 + (int)DAT_00487810);
param_1[0x38] = 1;
param_1[0x10f] = iVar1;
}
}
}
/* ===== FUN_00449c50 — Wall Avoidance with Ray Casting (00449C50) ===== */
/* Tests walls at 3 angle pairs around entity facing direction,
* then checks forward/backward clearance. Calls dodge if stuck. */
static void FUN_00449c50(int *param_1, int param_2, int param_3)
{
int iVar5 = param_1[1];
int iVar1 = *param_1;
unsigned int uVar2, uVar3;
int iVar4;
/* Test 1: +/-0x199 from facing */
uVar2 = (param_1[6] + 0x199U) & 0x7ff;
uVar3 = (param_1[6] - 0x199U) & 0x7ff;
iVar4 = FUN_004495e0(iVar1, iVar5,
*(int *)((int)DAT_00487ab0 + uVar2 * 4) * 3,
*(int *)((int)DAT_00487ab0 + 0x800 + uVar2 * 4) * 3,
*(int *)((int)DAT_00487ab0 + uVar3 * 4) * 3,
*(int *)((int)DAT_00487ab0 + 0x800 + uVar3 * 4) * 3);
if (iVar4 == 1) {
unsigned int b = param_1[0x2e];
unsigned int s = b | 2;
param_1[0x2e] = (int)s;
if ((b & 1) != 0)
param_1[0x2e] = (int)(s ^ 1);
} else if (iVar4 == 2) {
unsigned int b = param_1[0x2e];
unsigned int s = b | 1;
param_1[0x2e] = (int)s;
if ((b & 2) != 0)
param_1[0x2e] = (int)(s ^ 2);
}
/* Test 2: +/-0x100 from facing */
uVar3 = (param_1[6] - 0x100U) & 0x7ff;
uVar2 = (param_1[6] + 0x100U) & 0x7ff;
iVar4 = FUN_004495e0(iVar1, iVar5,
*(int *)((int)DAT_00487ab0 + uVar2 * 4),
*(int *)((int)DAT_00487ab0 + 0x800 + uVar2 * 4),
*(int *)((int)DAT_00487ab0 + uVar3 * 4),
*(int *)((int)DAT_00487ab0 + 0x800 + uVar3 * 4));
if (iVar4 == 1) {
unsigned int b = param_1[0x2e];
unsigned int s = b | 2;
param_1[0x2e] = (int)s;
if ((b & 1) != 0)
param_1[0x2e] = (int)(s ^ 1);
} else if (iVar4 == 2) {
unsigned int b = param_1[0x2e];
unsigned int s = b | 1;
param_1[0x2e] = (int)s;
if ((b & 2) != 0)
param_1[0x2e] = (int)(s ^ 2);
}
/* Test 3: +/-0x300 from facing */
uVar3 = (param_1[6] - 0x300U) & 0x7ff;
uVar2 = (param_1[6] + 0x300U) & 0x7ff;
iVar4 = FUN_004495e0(iVar1, iVar5,
*(int *)((int)DAT_00487ab0 + uVar2 * 4),
*(int *)((int)DAT_00487ab0 + 0x800 + uVar2 * 4),
*(int *)((int)DAT_00487ab0 + uVar3 * 4),
*(int *)((int)DAT_00487ab0 + 0x800 + uVar3 * 4));
if (iVar4 == 1) {
unsigned int b = param_1[0x2e];
unsigned int s = b | 2;
param_1[0x2e] = (int)s;
if ((b & 1) != 0)
param_1[0x2e] = (int)(s ^ 1);
} else if (iVar4 == 2) {
unsigned int b = param_1[0x2e];
unsigned int s = b | 1;
param_1[0x2e] = (int)s;
if ((b & 2) != 0)
param_1[0x2e] = (int)(s ^ 2);
}
/* Forward clearance check: walk backward (facing - 0x400) 5 steps */
uVar2 = (unsigned int)param_1[6] & 0x7ff;
uVar3 = (param_1[6] - 0x400U) & 0x7ff;
int local_14 = 0;
int iVar4b = iVar5;
int iVar6 = iVar1;
do {
iVar6 = iVar6 + *(int *)((int)DAT_00487ab0 + uVar3 * 4);
iVar4b = iVar4b + *(int *)((int)DAT_00487ab0 + 0x800 + uVar3 * 4);
if ((0 < iVar6) && (0 < iVar4b) &&
(iVar6 < (int)DAT_004879f0 * 0x40000) &&
(iVar4b < (int)DAT_004879f4 * 0x40000) &&
(*(char *)((unsigned int)*(unsigned char *)((iVar6 >> 0x12) +
(int)DAT_0048782c +
((iVar4b >> 0x12) << ((unsigned char)DAT_00487a18 & 0x1f))) *
0x20 + 1 + (int)DAT_00487928) == '\0'))
goto LAB_00449f58;
local_14++;
} while (local_14 < 5);
/* Forward clearance check: walk forward 5 steps */
local_14 = 0;
iVar4b = iVar1;
iVar6 = iVar5;
while (1) {
iVar4b = iVar4b + *(int *)((int)DAT_00487ab0 + uVar2 * 4);
iVar6 = iVar6 + *(int *)((int)DAT_00487ab0 + 0x800 + uVar2 * 4);
if ((0 < iVar4b) && (0 < iVar6) &&
(iVar4b < (int)DAT_004879f0 * 0x40000) &&
(iVar6 < (int)DAT_004879f4 * 0x40000) &&
(*(char *)((unsigned int)*(unsigned char *)((iVar4b >> 0x12) +
(int)DAT_0048782c +
((iVar6 >> 0x12) << ((unsigned char)DAT_00487a18 & 0x1f))) *
0x20 + 1 + (int)DAT_00487928) == '\0'))
break;
local_14++;
if (4 < local_14) {
LAB_00449f58:
if (20000 < param_2) {
if ((90000 < param_2) && ((char)param_1[0x39] == '\0')) {
FUN_004497c0((int)param_1, '\0');
}
if ((120000 < param_2) && ((char)param_1[0x39] == '\0')) {
int res = FUN_004494e0(iVar1, iVar5, param_1[4] << 3,
param_1[5] << 3, param_3);
if (res != 0) {
FUN_004497c0((int)param_1, '\0');
}
}
}
return;
}
}
/* Forward clear — set backward flag */
uVar2 = (unsigned int)param_1[0x2e];
uVar3 = uVar2 | 0x40;
param_1[0x2e] = (int)uVar3;
if ((uVar2 & 4) != 0) {
param_1[0x2e] = (int)(uVar3 ^ 4);
}
goto LAB_00449f58;
}
/* ===== FUN_004498a0 — Pathfinding Movement (004498A0) ===== */
/* Advances along the pathfinding waypoint list, checks terrain tile types
* for conveyors/speed tiles, and sets movement buttons accordingly.
* The __ftol() calls compute velocity from entity speed/angle and tile effects. */
static void FUN_004498a0(int *param_1, int param_2)
{
int *piVar4 = param_1;
int iVar2 = param_1[0x3d];
param_1[0x3d] = iVar2 + 1;
if (2 < iVar2 + 1) {
iVar2 = param_1[0x3b];
param_1[0x3d] = 0;
if (iVar2 == param_1[0x3c] - 1) {
param_1[0x38] = 1;
} else {
long long lVar8 = FUN_004496e0(*param_1, param_1[1],
param_1[iVar2 * 2 + 0x40] << 0x12,
param_1[iVar2 * 2 + 0x41] << 0x12,
(char)param_1[0x39]);
if ((int)lVar8 != 0) {
param_1[0x3a] = 0xfc;
param_1[0x3b] = param_1[0x3b] + 1;
}
}
}
/* Get current waypoint target position */
int wp_idx = piVar4[0x3b];
int wp_x = piVar4[wp_idx * 2 + 0x3e];
int wp_y = piVar4[wp_idx * 2 + 0x3f];
int iVar2b = *piVar4; /* entity x */
int iVar3 = piVar4[1]; /* entity y */
/* Compute tile-space delta to waypoint */
int dx_tile = wp_x - (iVar2b >> 0x12);
int dy_tile = wp_y - (iVar3 >> 0x12);
/* Compute velocity from entity speed and angle:
* vx = cos(angle) * speed, vy = sin(angle) * speed
* The disassembly shows: ent[4] (vx), ent[5] (vy) are current velocity,
* then it computes from distance to waypoint using sqrt and scaling. */
int vx = piVar4[4];
int vy = piVar4[5];
/* Normalize velocity to get speed scalar */
int vx_norm = ((vx + ((unsigned int)(vx >> 0x1f) >> 0x17)) >> 9);
int vy_norm = ((vy + ((unsigned int)(vy >> 0x1f) >> 0x17)) >> 9);
int speed_sq = vx_norm * vx_norm + vy_norm * vy_norm;
float speed_f = sqrtf((float)speed_sq);
/* Compute projected target position based on current velocity */
/* dx = wp_x_tile - ent_x_tile, dy = wp_y_tile - ent_y_tile */
/* The disasm computes: target_x = dx * (tiny_scale * speed) / dist - vx_term */
/* target_y = dy * (tiny_scale * speed) / dist - vy_term */
float dist_f = sqrtf((float)(dx_tile * dx_tile + dy_tile * dy_tile));
float vel_scale = speed_f * _DAT_0047578c;
/* BUG FIX: steering formula verified from disassembly FPU stack trace at 0x004499c0.
* Original: target = waypoint_delta - velocity * (dist * 0.1 * scale / vel_scale)
* The velocity term is a distance-proportional damping of the current velocity.
* vel_scale = speed * DAT_0047578c; when speed=0, __ftol clamps infinity. */
int target_x, target_y;
if (vel_scale > 0.0f) {
float vel_damp = dist_f * _DAT_00475790 * _DAT_00475788 / vel_scale;
target_x = (int)((float)dx_tile - (float)vx * vel_damp);
target_y = (int)((float)dy_tile - (float)vy * vel_damp);
} else {
target_x = dx_tile;
target_y = dy_tile;
}
/* BUG FIX: combined metric is target_y^2 + target_x (NOT target_x^2).
* Verified from disassembly at 0x004499f6: IMUL ECX,EAX then ADD ECX,EBP. */
int combined = target_y * target_y + target_x;
float combined_f = sqrtf((float)(combined > 0 ? combined : -combined));
/* BUG FIX: gravity correction subtracts gravity*combined_f*scale FROM target_y.
* Verified from FPU trace at 0x00449a09. */
target_y = (int)((float)target_y - (float)DAT_00483824 * combined_f * _DAT_00475784);
/* Conveyor scale factor: combined_f * DAT_00475784 (NOT vel_scale).
* This is the value remaining on the FPU stack after the gravity computation. */
float conv_scale = combined_f * _DAT_00475784;
/* Check terrain tile type for conveyors/speed modifiers */
unsigned char bVar1 = *(unsigned char *)(((iVar3 >> 0x12) << ((unsigned char)DAT_00487a18 & 0x1f)) +
(iVar2b >> 0x12) + (int)DAT_0048782c);
/* Conveyor tile types 0x40-0x47, 0x64-0x73, 0x16-0x19 modify velocity */
if (bVar1 == 0x40 || (99 < bVar1 && bVar1 < 0x68)) {
target_y = (int)(_DAT_00475780 * conv_scale + (float)target_y);
}
if (bVar1 == 0x41 || (0x67 < bVar1 && bVar1 < 0x6c)) {
target_y = (int)((float)target_y - _DAT_00475780 * conv_scale);
}
if (bVar1 == 0x42 || (0x6b < bVar1 && bVar1 < 0x70)) {
target_x = (int)(_DAT_00475780 * conv_scale + (float)target_x);
}
if (bVar1 == 0x43 || (0x6f < bVar1 && bVar1 < 0x74)) {
target_x = (int)((float)target_x - _DAT_00475780 * conv_scale);
}
if (bVar1 == 0x44) {
target_y = (int)(_DAT_0047577c * conv_scale + (float)target_y);
} else if (bVar1 == 0x45) {
target_y = (int)((float)target_y - _DAT_0047577c * conv_scale);
} else if (bVar1 == 0x46) {
target_x = (int)(_DAT_0047577c * conv_scale + (float)target_x);
} else if (bVar1 == 0x47) {
target_x = (int)((float)target_x - _DAT_0047577c * conv_scale);
} else if (bVar1 == 0x16) {
target_y = (int)(_DAT_00475778 * conv_scale + (float)target_y);
} else if (bVar1 == 0x17) {
target_y = (int)((float)target_y - _DAT_00475778 * conv_scale);
} else if (bVar1 == 0x18) {
target_x = (int)(_DAT_00475778 * conv_scale + (float)target_x);
} else if (bVar1 == 0x19) {
target_x = (int)((float)target_x - _DAT_00475778 * conv_scale);
}
/* Compute angle to adjusted target and decide movement direction */
unsigned long long uVar9 = (unsigned long long)(unsigned int)FUN_004257e0(0, 0, target_x, target_y);
unsigned int uVar7 = ((unsigned int)piVar4[6] - (unsigned int)uVar9) & 0x7ff;
unsigned int uVar6;
if ((param_2 < 60000) || (uVar7 < 0x2aa) || ((int)(0x800 - uVar7) < 0x2aa)) {
uVar6 = (unsigned int)piVar4[0x2e] | 4; /* forward */
} else {
if ((0x198 < ((uVar7 - 0x400) & 0x7ff)) && (0x198 < (int)(0x800 - uVar7)))
goto LAB_00449c28;
uVar6 = (unsigned int)piVar4[0x2e] | 0x40; /* backward */
}
piVar4[0x2e] = (int)uVar6;
LAB_00449c28:
/* Dead zone: skip turning when nearly aimed at target (±0x18 ≈ 5°).
* Prevents rapid left/right oscillation when heading is close to correct. */
if (uVar7 < 0x18 || uVar7 > 0x7E8)
return; /* close enough — don't turn */
if (0x3ff < uVar7) {
piVar4[0x2e] = piVar4[0x2e] | 1; /* turn left */
return;
}
piVar4[0x2e] = piVar4[0x2e] | 2; /* turn right */
}
/* ===== FUN_00449fd0 — Weapon Fire Decision (00449FD0) ===== */
/* Checks if firing the current weapon would hit an enemy using ballistic
* prediction with gravity. Sets fire button if projectile will intersect. */
static void FUN_00449fd0(int *param_1)
{
int iVar19 = (int)DAT_00487abc;
unsigned int uVar13 = (unsigned int)*(unsigned char *)((char)param_1[0xd] + 0x3c + (int)param_1);
unsigned int uVar16 = (unsigned int)*(unsigned char *)((int)param_1 + 0x35);
int iVar10 = iVar19 + uVar13 * 0x218;
char cVar2 = *(char *)(iVar10 + 0x7c);
if (cVar2 == '\0') return;
if (cVar2 == '\x02') {
param_1[0x2e] = param_1[0x2e] | 0x10;
return;
}
if (cVar2 == '\x03') {
if (param_1[0x116] != 2) return;
if (*param_1 <= param_1[0x114] - 0x1900000) return;
if (param_1[0x114] + 0x1900000 <= *param_1) return;
if (param_1[1] <= param_1[0x115] - 0x1900000) return;
if (param_1[0x115] + 0x1900000 <= param_1[1]) return;
param_1[0x2e] = param_1[0x2e] | 0x10;
return;
}
int iVar3 = *param_1;
int iVar7 = iVar3 + DAT_00481ec4;
int iVar14 = iVar3 - DAT_00481ec4;
int iVar4 = param_1[1];
int iVar8 = iVar4 + DAT_00481ec8;
int iVar15 = iVar4 - DAT_00481ec8;
/* Weapon parameters from level/type tables */
unsigned int weap_level = (unsigned int)*(unsigned char *)((int)param_1 + 0xdd);
int local_5c = DAT_0047ee1c[weap_level];
int iVar20 = (int)weap_level - 1;
int local_64 = DAT_0047ee0c[iVar20];
int iVar5 = DAT_0047ee34[iVar20];