forked from gunslingermod/gunslinger_wpnpatch
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathWeaponAmmoCounter.pas
814 lines (690 loc) · 24.1 KB
/
WeaponAmmoCounter.pas
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
unit WeaponAmmoCounter;
{$IFDEF FPC}{$MODE DELPHI}{$ENDIF}
{$define DISABLE_AUTOAMMOCHANGE} //îòêëþ÷àåò àâòîìàòè÷åñêóþ ñìåíó òèïà ïàòðîíîâ ïî íàæàòèþ êëàâèøè ðåëîàäà ïðè îòñóòñâèè ïàòðîíîâ òåêóùåãî òèïà; ïðè àíäåôå ïîëîìàþòñÿ äâóñòâîëû, êîãäà â èíâåíòàðå ïîñëåäíèé ïàòðîí!
interface
procedure CWeaponMagazined__OnAnimationEnd_DoReload(wpn:pointer); stdcall;
function CWeaponShotgun__OnAnimationEnd_OnAddCartridge(wpn:pointer):boolean; stdcall;
function Init:boolean;
implementation
uses BaseGameData, WeaponAdditionalBuffer, HudItemUtils, xr_Cartridge, ActorUtils, strutils, ActorDOF, gunsl_config, sysutils, dynamic_caster, xr_strings;
procedure SwapFirstLastAmmo(wpn:pointer);stdcall;
var
cs, ce:pCCartridge;
tmp:CCartridge;
cnt, gl_status:cardinal;
begin
gl_status:=GetGLStatus(wpn);
if ((gl_status=1) or ((gl_status=2) and IsGLAttached(wpn))) and IsGLEnabled(wpn) then exit;
cnt:=GetAmmoInMagCount(wpn);
if cnt>1 then begin
cnt:=cnt-1;
cs:=GetCartridgeFromMagVector(wpn,0);
ce:=GetCartridgeFromMagVector(wpn,cnt);
CopyCartridge(cs^, tmp);
CopyCartridge(ce^, cs^);
CopyCartridge(tmp, ce^);
end;
end;
procedure SwapLastPrevAmmo(wpn:pointer);stdcall;
var
cs, ce:pCCartridge;
tmp:CCartridge;
cnt, gl_status:cardinal;
begin
gl_status:=GetGLStatus(wpn);
if ((gl_status=1) or ((gl_status=2) and IsGLAttached(wpn))) and IsGLEnabled(wpn) then exit;
cnt:=GetAmmoInMagCount(wpn);
if cnt>1 then begin
cnt:=cnt-1;
cs:=GetCartridgeFromMagVector(wpn,cnt-1);
ce:=GetCartridgeFromMagVector(wpn,cnt);
CopyCartridge(cs^, tmp);
CopyCartridge(ce^, cs^);
CopyCartridge(tmp, ce^);
end;
end;
//---------------------------------------------------Ñâîå ÷èñëî ïàòðîíîâ â ðåëîàäå-------------------------
procedure CWeaponMagazined__OnAnimationEnd_DoReload(wpn:pointer); stdcall;
var
buf: WpnBuf;
def_magsize, mod_magsize, curammocnt:integer;
gl_status:cardinal;
begin
buf:=GetBuffer(wpn);
//åñëè áóôåðà íåò èëè ìû óæå ïåðåçàðÿäèëècü èëè ó íàñ ðåæèì ïîäñòâîëà - íè÷åãî îñîáåííîãî íå äåëàåì
if (buf=nil) then begin virtual_CWeaponMagazined__ReloadMagazine(wpn); exit; end;
if buf.IsReloaded() then begin buf.SetReloaded(false); exit; end;
gl_status:=GetGLStatus(wpn);
if (((gl_status=1) or ((gl_status=2) and IsGLAttached(wpn))) and IsGLEnabled(wpn)) then begin virtual_CWeaponMagazined__ReloadMagazine(wpn); exit; end;
//ïîñìîòðèì, êàêîâ ðàçìåð ìàãàçèíà ó îðóæèÿ è ñêîëüêî ïàòðîíîâ â íåì ñåé÷àñ
def_magsize:=GetMagCapacityInCurrentWeaponMode(wpn);
curammocnt:=GetCurrentAmmoCount(wpn);
//òåïåðü ïîñìîòðèì íà ñîñòîÿíèå îðóæèÿ è ïîäóìàåì, ñêîëüêî ïàòðîíîâ â íåãî çàïèõíóòü
if IsWeaponJammed(wpn) then begin
SetAmmoTypeChangingStatus(wpn, $FF);
mod_magsize:=curammocnt;
end else if IsBM16(wpn) then begin
mod_magsize:=buf.ammo_cnt_to_reload;
end else if not IsGrenadeMode(wpn) and buf.IsAmmoInChamber() and ((curammocnt=0) or ((GetAmmoTypeChangingStatus(wpn)<>$FF) and not buf.SaveAmmoInChamber() )) then begin
mod_magsize:=def_magsize-1;
end else begin
mod_magsize:=def_magsize;
end;
//èçìåíèì åìêîñòü ìàãàçèíà, îòðåëîàäèìñÿ äî íåå è âîññòàíîâèì ñòàðîå çíà÷åíèå
SetMagCapacityInCurrentWeaponMode(wpn, mod_magsize);
virtual_CWeaponMagazined__ReloadMagazine(wpn);
SetMagCapacityInCurrentWeaponMode(wpn, def_magsize);
end;
procedure CWeaponMagazined__OnAnimationEnd_DoReload_Patch(); stdcall;
asm
pushad
sub esi, $2e0
push esi
call CWeaponMagazined__OnAnimationEnd_DoReload
popad
end;
//---------------------------------------------------Íåñìåíà òèïà ïàòðîíà â ïàòðîííèêå â ðåëîàäå-------------------------
procedure PerformUnloadAmmo(wpn:pointer); stdcall;
var
buf:WpnBuf;
need_unload:boolean;
i, cnt:integer;
begin
buf:=GetBuffer(wpn);
//Âûçûâàåòñÿ ïðè ÊÀÆÄÎÉ ïåðåçàðÿäêå ïðè ÍÅÏÓÑÒÎÌ ìàãàçèíå - íå òîëüêî ïðè ñìåíå òèïà ïàòðîíîâ (ýòî ïðîïàò÷åíî äðóãîé âðåçêîé)
if buf <> nil then begin
buf.is_firstlast_ammo_swapped:=false;
if not IsGrenadeMode(wpn) and buf.IsAmmoInChamber() and buf.SaveAmmoInChamber() then begin
//Ïðè èñïîëüçîâàíèè ñõåìû ñ ïàòðîííèêîì â ïàòðîíå íå ðàçðÿæàåì ïàòðîí â ïàòðîííèêå
//Ìåíÿåì ìåñòàìè ïåðâûé ïàòðîí èç âåêòîðà ìàãàçèíà ñ ïîñëåäíèì
//Ïîñëå ýòîãî íà ìåñòå ïåðâîãî ïàòðîíà îêàçûâàåòñÿ ïàòðîí èç ïàòðîííèêà
SwapFirstLastAmmo(wpn);
buf.is_firstlast_ammo_swapped:=true;
// Õàê - ñìåùàåì óêàçàòåëü íà ïåðâûé ýëåìåíò èç âåêòîðà ïàòðîíîâ, ÷òîáû åãî íå ðàçðÿäèëî
ChangeAmmoVectorStart(wpn, sizeof(CCartridge));
end;
end;
//Åñëè òåêóùèé òèï ïàòðîíîâ íå ñîîòâåòñòâóåò òîìó, êîòîðûé áóäåì çàðÿæàòü - ðàçðÿäèì îðóæèå
need_unload:=false;
if IsGrenadeMode(wpn) then begin
cnt:=GetAmmoInGLCount(wpn);
if cnt > 0 then begin
for i:=0 to cnt - 1 do begin
if GetCartridgeType(GetGrenadeCartridgeFromGLVector(wpn, i)) <> GetAmmoTypeIndex(wpn) then begin
need_unload:=true;
break;
end;
end;
end;
end else begin
cnt:=GetAmmoInMagCount(wpn);
if cnt > 0 then begin
for i:=0 to cnt - 1 do begin
if GetCartridgeType(GetCartridgeFromMagVector(wpn, i)) <> GetAmmoTypeIndex(wpn) then begin
need_unload:=true;
break;
end;
end;
end;
end;
if need_unload then begin
virtual_CWeaponMagazined__UnloadMagazine(wpn, true);
end;
if (buf<>nil) and buf.is_firstlast_ammo_swapped then begin
//Îòêàòûâàåì ñäåëàííûå õàêîì èçìåíåíèÿ â âåêòîðå - íåðàçðÿæåííûé ïàòðîí èç ïàòðîííèêà ìàãè÷åñêèì îáðàçîì ïîÿâëÿåòñÿ îáðàòíî
ChangeAmmoVectorStart(wpn, (-1)*sizeof(CCartridge));
end;
end;
procedure CWeaponMagazined__ReloadMagazine_OnUnloadMag_Patch(); stdcall;
asm
pushad
push esi
call PerformUnloadAmmo
popad
@finish:
end;
procedure CWeaponMagazined__ReloadMagazine_OnFinish(wpn:pointer); stdcall;
var
buf:WpnBuf;
begin
buf:=GetBuffer(wpn);
if (buf<>nil) and (buf.is_firstlast_ammo_swapped) then begin
buf.is_firstlast_ammo_swapped:=false;
SwapFirstLastAmmo(wpn);
end;
end;
procedure CWeaponMagazined__ReloadMagazine_OnFinish_Patch(); stdcall;
asm
pushad
push esi
call CWeaponMagazined__ReloadMagazine_OnFinish
popad
pop esi
pop ebp
add esp, $48
end;
{$ifdef DISABLE_AUTOAMMOCHANGE}
procedure CWeaponmagazined__TryReload_Patch();stdcall;
asm
//ïðîâåðÿåì, áûëà ëè îò þçåðà êîìàíäà íà ñìåíó ðåæèìà
cmp byte ptr [esi+$6C7], $FF //if m_set_next_ammoType_on_reload<>-1 then jmp
jne @need_change
//Åñëè â ìàãàçèíå ïóñòî - èìååò ñìûñë àâòîìàòîì ñìåíèòü òèï, äàáû íå áûëî çàòóïîâ þçåðîâ
push eax //ñîõðàíÿåì âàæíîå
push esi
call GetCurrentAmmoCount
test eax, eax
pop eax //âîññòàíîâèì ñîõðàíåííîå
je @need_change
mov eax, 0 //ãîâîðèì, ÷òî ó îðóæèÿ 0 äîñòóïíûõ òèïîâ ïàòðîíîâ ;)
@need_change:
//äåëàåì âûðåçàííîå
sar eax, 02
test al, al
ret
end;
procedure CWeaponShotgun__HaveCartridgeInInventory_DisableAutoAmmoChange_Patch(); stdcall;
asm
movzx ebp,byte ptr [esp+$14] //original
mov edi, eax //original
cmp edi, ebp //orig check: (ac<cnt); ac = edi, cnt = ebp
jae @finish
cmp byte ptr [esi+$6c7], $FF // åñëè èãðîê íàæàë êíîïêó ñìåíû - ðàçðåøàåì ñìåíó
jne @allowed_change
cmp edi, 0 // åñëè â ðþêçàêå åùå åñòü ïàòðîíû òåêóùåãî òèïà (ac>0), çàïðåùàåì àâòîñìåíó
jne @not_allowed_change
push eax //ñîõðàíÿåì âàæíîå
push esi
call GetCurrentAmmoCount
test eax, eax
pop eax //âîññòàíîâèì ñîõðàíåííîå
jne @not_allowed_change
@allowed_change: // Ìîæåì ìåíÿòü òèï ïàòðîíîâ - íàäî çàãíàòü íàñ â öèêë ïåðåáîðà íàëè÷èÿ ðàçëè÷íûõ òèïîâ (ò.å. êàê â îðèãèíàëå)
xor ecx, ecx
cmp ecx, 1
jmp @finish
@not_allowed_change: // íå ìîæåì ìåíÿòü òèï ïàòðîíîâ - íàäî âåðíóòü ðåçóëüòàò óñëîâèÿ (ac>=cnt)
//Íî åñëè ìû ïîéäåì ìèìî öèêëà, òî âñåãäà ïîëó÷èì âîçâðàùåíèå true èç-çà îïòèìèçàöèè êîìïèëÿòîðà!
//Âûâîä - ñðàâíèâàåì ñàìè è âîçâðàùàåìñÿ èç âûçûâàþùåé ôóíêöèè
xor eax, eax
cmp edi, ebp //ac = edi, cnt = ebp
jb @retx2
inc eax
@retx2:
pop ecx //ret addr
pop edi
pop ebp
pop esi
ret 4 // ret FROM CWeaponShotgun::HaveCartridgeInInventory
@finish:
end;
{$endif}
//---------------------------------Ïàòðîíû â ïàòðîííèêå äëÿ äðîáîâèêîâ----------------------------
function CWeaponShotgun__OnAnimationEnd_OnAddCartridge(wpn:pointer):boolean; stdcall;
//âîçâðàùàåò, ñòîèò ëè ïðîäîëæàòü íàáèâàòü ïàòðîíû â TriStateReload, èëè õâàòèò óæå :)
var
buf:WpnBuf;
begin
buf:=GetBuffer(wpn);
if buf<>nil then begin
if not buf.IsReloaded then begin
virtual_CWeaponShotgun__AddCartridge(wpn, 1);
if buf.IsAmmoInChamber() and buf.SaveAmmoInChamber() then begin
SwapLastPrevAmmo(wpn);
end;
end;
end else begin
virtual_CWeaponShotgun__AddCartridge(wpn, 1); //äàíü îðèãèíàëüíîìó êîäó ;)
end;
result:=CWeaponShotgun__HaveCartridgeInInventory(wpn, 1);
end;
procedure CWeaponShotgun__OnAnimationEnd_OnAddCartridge_Patch(); stdcall;
asm
pushad
sub esi, $2e0
push esi
call CWeaponShotgun__OnAnimationEnd_OnAddCartridge
cmp al, 01
popad
end;
//-----------------------------------------anm_close â ñëó÷àå ðó÷íîãî ïðåðûâàíèÿ ðåëîàäà----------------------------
procedure CWeaponShotgun__Action_OnStopReload(wpn:pointer); stdcall;
begin
if (GetSubState(wpn)=EWeaponSubStates__eSubStateReloadEnd) or (IsWeaponJammed(wpn)) then begin //???ïåðâîå íèêîãäà íå âûïîëíèòñÿ - ñì èñõîäíèê äâèãà???
exit;
end;
if not IsActionProcessing(wpn) then begin
SetSubState(wpn, EWeaponSubStates__eSubStateReloadEnd);
virtual_CHudItem_SwitchState(wpn,EWeaponStates__eReload);
end else begin
SetActorKeyRepeatFlag(kfFIRE, true);
end;
end;
procedure CWeaponShotgun__Action_OnStopReload_Patch(); stdcall;
asm
pushad
push esi
call CWeaponShotgun__Action_OnStopReload
popad
end;
//----------------------------------------------äîáàâëåíèå ïàòðîíà â open-------------------------------------------
procedure CWeaponMagazined__OnAnimationEnd_anm_open(wpn:pointer); stdcall;
var
buf:WpnBuf;
begin
if IsWeaponJammed(wpn) then begin
SetWeaponMisfireStatus(wpn, false);
SetSubState(wpn, EWeaponSubStates__eSubStateReloadBegin);
virtual_CHudItem_SwitchState(wpn, EHudStates__eIdle);
exit;
end;
SetSubState(wpn, EWeaponSubStates__eSubStateReloadInProcess); //âûðåçàííîå
buf:=GetBuffer(wpn);
if (buf<>nil) and buf.AddCartridgeAfterOpen() then begin
CWeaponShotgun__OnAnimationEnd_OnAddCartridge(wpn);
end;
virtual_CHudItem_SwitchState(wpn, EWeaponStates__eReload);
end;
procedure CWeaponMagazined__OnAnimationEnd_anm_open_Patch(); stdcall;
asm
pushad
sub esi, $2e0
push esi
call CWeaponMagazined__OnAnimationEnd_anm_open
popad
end;
//-------------------------------------------------------Óñëîâèå íà ðàñêëèí áåç ïàòðîíîâ â èíâåíòàðå-----------------------------------------
function CWeaponShotgun_Needreload(wpn:pointer):boolean; stdcall;
begin
result:= (IsWeaponJammed(wpn) or CWeaponShotgun__HaveCartridgeInInventory(wpn, 1));
end;
procedure CWeaponShotgun__TriStateReload_Needreload_Patch(); stdcall;
asm
pushad
push esi
call CWeaponShotgun_Needreload
test al, al
popad
end;
procedure CWeaponShotgun__OnStateSwitch_Needreload_Patch(); stdcall;
asm
pushad
push edi
call CWeaponShotgun_Needreload
test al, al
popad
end;
procedure CWeaponMagazined__TryReload_hasammo_Patch(); stdcall;
asm
cmp [esi+$690], 00 //original
jne @finish
//cmp byte ptr [esi+$7f8], 1 //àêòèâåí ëè ïîäñòâîë ñåé÷àñ
pushad
push esi
call IsGrenadeMode
cmp al, 1
popad
@finish:
end;
//------------------------------------------------------------------------------------------------------------------
type
ammo_section_params = packed record
name:string;
box_size:single;
box_weight:single;
inv_name_short:PAnsiChar;
end;
var
_ammo_sections_params_cache:array of ammo_section_params;
function GetAmmoSectionParams(sect:string):ammo_section_params;
var
i:integer;
found:boolean;
begin
found:=false;
for i:=0 to length(_ammo_sections_params_cache)-1 do begin
if (length(_ammo_sections_params_cache[i].name) = length(sect)) then begin
if _ammo_sections_params_cache[i].name = sect then begin
result:=_ammo_sections_params_cache[i];
found:=true;
break;
end;
end;
end;
if not found then begin
result.box_size:=game_ini_r_single_def(PAnsiChar(sect), 'box_size', 1);
result.box_weight:=game_ini_r_single_def(PAnsiChar(sect), 'inv_weight', 0);
result.name:=sect;
result.inv_name_short:=game_ini_read_string(PAnsiChar(sect), 'inv_name_short');
setlength(_ammo_sections_params_cache, length(_ammo_sections_params_cache)+1);
_ammo_sections_params_cache[length(_ammo_sections_params_cache)-1]:=result;
end;
end;
procedure CWeapon__Weight_CalcAmmoWeight(wpn:pointer; total_weight:psingle); stdcall;
var
weight:single;
cnt, i:cardinal;
c:pCCartridge;
ammo_params:ammo_section_params;
sect:PAnsiChar;
begin
if dynamic_cast(wpn, 0, RTTI_CWeapon, RTTI_CWeaponMagazined, false) = nil then exit;
weight:=0;
cnt:=GetAmmoInMagCount(wpn);
if cnt>0 then begin
for i:=0 to cnt-1 do begin
c:=GetCartridgeFromMagVector(wpn, i);
if c<>nil then begin
sect:= GetCartridgeSection(c);
if sect<>nil then begin
ammo_params:=GetAmmoSectionParams(sect);
weight:=weight+ (ammo_params.box_weight/ammo_params.box_size);
end;
end;
end;
end;
cnt:=GetAmmoInGLCount(wpn);
if cnt>0 then begin
for i:=0 to cnt-1 do begin
c:=GetGrenadeCartridgeFromGLVector(wpn, i);
if c<>nil then begin
sect:= GetCartridgeSection(c);
if sect<>nil then begin
ammo_params:=GetAmmoSectionParams(sect);
weight:=weight+ (ammo_params.box_weight/ammo_params.box_size);
end;
end;
end;
end;
total_weight^:=total_weight^+weight;
end;
procedure CWeapon__Weight_CalcAmmoWeight_Patch(); stdcall;
asm
lea eax, [esp+8]
pushad
push eax
push esi
call CWeapon__Weight_CalcAmmoWeight
xor eax, eax
cmp eax, 0 //÷òîáû ñòàíäàðòíûé íåäîêîä ïîäñ÷åòà äàæå íå äóìàë âûïîëíÿòüñÿ!
popad;
end;
function GetTotalGrenadesCountInInventory(wpn:pointer):cardinal;stdcall;
var
g_m:boolean;
cnt, i:cardinal;
gl_status:cardinal;
begin
gl_status:=GetGLStatus(wpn);
if (gl_status=0) or ((gl_status=2) and not IsGLAttached(wpn)) then begin
result:=0;
exit;
end;
g_m:=IsGLEnabled(wpn);
cnt:=GetGLAmmoTypesCount(wpn);
result:=0;
for i:=0 to cnt-1 do begin
if g_m then
result:=result+cardinal(CWeapon__GetAmmoCount(wpn, byte(i)))
else
result:=result+cardinal(CWeaponMagazinedWGrenade__GetAmmoCount2(wpn, byte(i)));
end;
end;
procedure CWeaponMagazinedWGrenade__GetBriefInfo_GrenadesCount_Patch(); stdcall;
asm
push ecx
lea ecx, [esp]
pushad
push ecx
push ebp
call GetTotalGrenadesCountInInventory
pop ecx
mov [ecx], eax
popad
pop eax
end;
function CWeaponMagazined_FillBriefInfo(wpn:pointer; bi:pII_BriefInfo):boolean; stdcall;
//no GL
var
ammo_sect:PChar;
s:string;
cnt, ammos, i, current:cardinal;
queue:integer;
begin
ammo_sect:= GetMainCartridgeSectionByType(wpn, GetAmmoTypeIndex(wpn, false));
assign_string(@bi.name, GetAmmoSectionParams(ammo_sect).inv_name_short);
assign_string(@bi.icon, ammo_sect);
s:=inttostr(GetAmmoInMagCount(wpn));
assign_string(@bi.cur_ammo, PChar(s));
cnt:=GetMainAmmoTypesCount(wpn);
if cnt>0 then begin
current:=GetAmmoTypeIndex(wpn, false);
s:=inttostr(CWeapon__GetAmmoCount(wpn, current));
assign_string(@bi.fmj_ammo, PChar(s));
if cnt>1 then begin
ammos:=0;
for i:=0 to cnt-1 do begin
if i<>current then begin
ammos:=ammos+cardinal(CWeapon__GetAmmoCount(wpn, i));
end;
end;
s:=inttostr(ammos);
assign_string(@bi.ap_ammo, PChar(s));
end else begin
assign_string(@bi.ap_ammo, ' ');
end;
end else begin
assign_string(@bi.fmj_ammo, ' ');
assign_string(@bi.ap_ammo, ' ');
end;
if HasDifferentFireModes(wpn) then begin
queue:=CurrentQueueSize(wpn);
if queue<0 then begin
s:='A';
end else begin
s:=inttostr(queue)
end;
assign_string(@bi.fire_mode, PChar(s));
end else begin
assign_string(@bi.fire_mode, ' ');
end;
assign_string(@bi.grenade, ' ');
result:=true;
end;
function CWeaponMagazinedWGrenade_FillBriefInfo(wpn:pointer; bi:pII_BriefInfo):boolean; stdcall;
var
ammotypes, i:cardinal;
ammo_cnt, queue:integer;
g_m:boolean;
gl_status:cardinal;
ammo_sect:PChar;
current:byte;
s:string;
begin
g_m:=IsGrenadeMode(wpn);
if not g_m then begin
result:=CWeaponMagazined_FillBriefInfo(wpn, bi);
end else begin
current:=GetAmmoTypeIndex(wpn, false);
ammo_sect:= GetGLCartridgeSectionByType(wpn, current);
assign_string(@bi.name, GetAmmoSectionParams(ammo_sect).inv_name_short);
assign_string(@bi.icon, ammo_sect);
s:=inttostr(GetAmmoInGLCount(wpn));
assign_string(@bi.cur_ammo, PChar(s));
ammotypes:=GetGLAmmoTypesCount(wpn);
if ammotypes>0 then begin
s:=inttostr(CWeapon__GetAmmoCount(wpn, current));
assign_string(@bi.fmj_ammo, PChar(s));
if ammotypes>1 then begin
ammo_cnt:=0;
for i:=0 to ammotypes-1 do begin
if i<>current then begin
ammo_cnt:=ammo_cnt+cardinal(CWeapon__GetAmmoCount(wpn, i));
end;
end;
s:=inttostr(ammo_cnt);
assign_string(@bi.ap_ammo, PChar(s));
end else begin
assign_string(@bi.ap_ammo, ' ');
end;
end else begin
assign_string(@bi.fmj_ammo, ' ');
assign_string(@bi.ap_ammo, ' ');
end;
if HasDifferentFireModes(wpn) then begin
queue:=CurrentQueueSize(wpn);
if queue<0 then begin
s:='A';
end else begin
s:=inttostr(queue)
end;
assign_string(@bi.fire_mode, PChar(s));
end else begin
assign_string(@bi.fire_mode, ' ');
end;
result:=true;
end;
//ïåðåîïðåäåëÿåì ñòðîêó ÷èñëà ãðåí
gl_status:=GetGLStatus(wpn);
if (gl_status=1) or ((gl_status=2) and IsGLAttached(wpn)) then begin
ammotypes:=GetGLAmmoTypesCount(wpn);
ammo_cnt:=0;
for i:=0 to ammotypes-1 do begin
if not g_m then
ammo_cnt:=ammo_cnt+CWeaponMagazinedWGrenade__GetAmmoCount2(wpn, i)
else
ammo_cnt:=ammo_cnt+CWeapon__GetAmmoCount(wpn, i);
end;
if ammo_cnt = 0 then begin
assign_string(@bi.grenade, 'X');
end else begin
assign_string(@bi.grenade, PChar(inttostr(ammo_cnt)));
end;
end else begin
assign_string(@bi.grenade, ' ');
end;
end;
procedure CWeaponMagazined__GetBriefInfo_Replace_Patch(); stdcall;
asm
mov eax, [esp+4]
pushad
push eax
push ecx
call CWeaponMagazined_FillBriefInfo;
popad
mov eax, 1
ret 4
end;
procedure CWeaponMagazinedWGrenade__GetBriefInfo_Replace_Patch(); stdcall;
asm
mov eax, [esp+4]
pushad
push eax
push ecx
call CWeaponMagazinedWGrenade_FillBriefInfo;
popad
mov eax, 1
ret 4
end;
procedure CWeaponMagazinedWGrenade__PerformSwitchGL_ammoinverse_Patch(); stdcall;
asm
//ñâîïàåì ïàòðîíû
mov edi, [esi+$6C8]
mov ebx, [esi+$7EC]
mov [esi+$6C8], ebx
mov [esi+$7EC], edi
mov edi, [esi+$6CC]
mov ebx, [esi+$7F0]
mov [esi+$6CC], ebx
mov [esi+$7F0], edi
mov edi, [esi+$6D0]
mov ebx, [esi+$7F4]
mov [esi+$6D0], ebx
mov [esi+$7F4], edi
//äåëàåì îñòàòîê ôóíêöèè
mov eax, [esi+$6cc]
sub eax, [esi+$6c8]
xor edx, edx
mov ebx, $3c;
div ebx
mov [esi+$690], eax
mov [esi+$69C], 0
//âàëèì
pop edi
pop esi
pop ebp
pop ebx
add esp, $4C
ret
end;
function Init:boolean;
var
debug_bytes:array of byte;
addr:cardinal;
begin
result:=false;
setlength(debug_bytes, 6);
////////////////////////////////////////////////////
//[bug]îòêëþ÷àåì áàã ñ ìîìåíòàëüíîé ñìåíîé òèïà ïàòðîíîâ ïðè ïåðåçàðÿäêå, êîãäà ó íàñ íå õâàòàåò ïàòðîíîâ òåêóùåãî òèïà äî ïîëíîãî ìàãàçèíà
//[bug]Îíî æå ïðîÿâëÿåòñÿ, åñëè ó îðóæèÿ, ó êîòîðîãî íåïîëíûé ìàãàçèí îäíîãî òèïà ïàòðîíîâ, è òàêîãî òèïà â èíâåíòàðå áîëüøå íåò, ïîïðîáîâàòü ñìåíèòü òèï è, íå äîæèäàÿñü îêîí÷àíèÿ àíèìû, âûáðîñèòü
//ïîñëå ïîäúåìà îðóæèå íå áóäåò ðåàãèðîâàòü íà êëàâèøó ñìåíû òèïà
// ïðè÷èíà â òîì, ÷òî â CWeaponMagazined::TryReload ìû ïðèñâàèâàåì çíà÷åíèå ÷ëåíó m_ammoType âìåñòî m_set_next_ammoType_on_reload
debug_bytes[0]:=$C7;
if not WriteBufAtAdr(xrGame_addr+$2D0185, @debug_bytes[0],1) then exit;
if not WriteBufAtAdr(xrGame_addr+$2DE84B, @debug_bytes[0],1) then exit; //CWeaponShotgun::HaveCarteidgeInInventory, ïîòîì âñå ðàâíî ïåðåçàïèñûâàåì, íî ïóñòü áóäåò
//ðåøàåò, ñêîëüêî ïàòðîíîâ íàäî çàðÿäèòü â ðåëîàäå è äåëàåò ñàì ðåëîàä
addr:=xrGame_addr+$2CCD94;
if not WriteJump(addr, cardinal(@CWeaponMagazined__OnAnimationEnd_DoReload_Patch), 20, true) then exit;
//îïöèîíàëüíîå äîáàâëåíèå ïàòðîíà ïîñëå anm_open
addr:=xrGame_addr+$2DE41C;
if not WriteJump(addr, cardinal(@CWeaponMagazined__OnAnimationEnd_anm_open_Patch), 15, true) then exit;
//Ïðè ñìåíå òèïà ïàòðîíîâ ìàãàçèí ðàçðÿæàåòñÿ - çàñòàâëÿåì îñòàâèòü ïîñëåäíèé ïàòðîí íåðàçðÿæåííûì
nop_code(xrGame_addr+$2D10D8, 2); //óáèðàåì óñëîâèå íà íåðàâåíñòâî ñåêöèé ïîñëåäíåãî ïàòðîíà è çàðÿæàåìîãî
addr:=xrGame_addr+$2D1106;
if not WriteJump(addr, cardinal(@CWeaponMagazined__ReloadMagazine_OnUnloadMag_Patch), 6, true) then exit;
//ñâîïèì ïåðâûé è ïîñëåäíèé ïàòðîí, åñëè ó íàñ áûëà ñìåíà òèïà
addr:=xrGame_addr+$2D125F;
if not WriteJump(addr, cardinal(@CWeaponMagazined__ReloadMagazine_OnFinish_Patch), 6, false) then exit;
//îòêëþ÷àåì äîáàâëåíèå "ëèøíåãî" ïàòðîíà ïðè ïðåðûâàíèè ðåëîàäà äðîáîâèêà +çàñòàâëÿåì èãðàòüñÿ anm_close (â CWeaponShotgun::Action)
addr:=xrGame_addr+$2DE374;
if not WriteJump(addr, cardinal(@CWeaponShotgun__Action_OnStopReload_Patch), 30, true) then exit;
//ïàòðîí â ïàòðîííèêå+àíèìàöèÿ ðàñêëèíèâàíèÿ+îòâå÷àåò çà äîáàâëåíèå ïàòðîíà â ìàãàçèí
addr:=xrGame_addr+$2DE3ED;
if not WriteJump(addr, cardinal(@CWeaponShotgun__OnAnimationEnd_OnAddCartridge_Patch), 22, true) then exit;
//èçìåíèì óñëîâèå, êîòîðîå íå äàåò ðàñêëèíèâàòü CWeaponMagazined, åñëè ïàòðîíîâ ê íåìó íåò íè â èíâåíòàðå, íè â ìàãàçèíå
//îíî ñóùåñòâåííî òîëüêî ïðè ïåðåçàðÿäêå â ðåæèìå ïîäñòâîëà
addr:=xrGame_addr+$2D00AD;
if not WriteJump(addr, cardinal(@CWeaponMagazined__TryReload_hasammo_Patch), 7, true) then exit;
//äàäèì âîçìîæíîñòü ðàñêëèíèâàòü äðîáîâèê, êîãäà â èíâåíòàðå íåò ïàòðîíîâ
addr:=xrGame_addr+$2DE94A;
if not WriteJump(addr, cardinal(@CWeaponShotgun__TriStateReload_Needreload_Patch), 11, true) then exit;
addr:=xrGame_addr+$2DE9D1;
if not WriteJump(addr, cardinal(@CWeaponShotgun__OnStateSwitch_Needreload_Patch), 11, true) then exit;
addr:=xrGame_addr+$2DEA19;
if not WriteJump(addr, cardinal(@CWeaponShotgun__OnStateSwitch_Needreload_Patch), 11, true) then exit;
//addr:=xrGame_addr+$2DEA00;
//if not WriteJump(addr, cardinal(@CWeaponShotgun__OnStateSwitch_Needreload_Patch), 11, true) then exit;
{$ifdef DISABLE_AUTOAMMOCHANGE}
addr:=xrGame_addr+$2D00FF;
if not WriteJump(addr, cardinal(@CWeaponMagazined__TryReload_Patch), 5, true) then exit;
addr:=xrGame_addr+$2DE7E2;
if not WriteJump(addr, cardinal(@CWeaponShotgun__HaveCartridgeInInventory_DisableAutoAmmoChange_Patch), 9, true) then exit;
{$endif}
//[bug] áàã ñ íåïðàâèëüíûì ðàñ÷åòîì âåñà îðóæèÿ â CWeapon::Weight: íå ó÷èòûâàåòñÿ âîçìîæíîñòü íàëè÷èÿ â ìàãàçèíå áîåïðèïàñîâ ðàçíûõ òèïîâ, à òàêæå çàðÿäîâ â ïîäñòâîëüíèêå
addr:=xrGame_addr+$2BE9B7;
if not WriteJump(addr, cardinal(@CWeapon__Weight_CalcAmmoWeight_Patch), 7, true) then exit;
//[bug] áàã ñ îïðåäåëåíèåì ÷èñëà ãðàíàò äëÿ ïîäñòâîëà - îïðåäåëÿåòñÿ òîëüêî ÷èñëî äëÿ 1ãî òèïà, îñòàëüíûå èãíîðÿòñÿ
addr:=xrGame_addr+$2D2562;
if not WriteJump(addr, cardinal(@CWeaponMagazinedWGrenade__GetBriefInfo_GrenadesCount_Patch), 17, true) then exit;
//ïåðåäåëêà ñõåìû BriefInfo
addr:=xrGame_addr+$2CE360;
if not WriteJump(addr, cardinal(@CWeaponMagazined__GetBriefInfo_Replace_Patch), 5, false) then exit;
addr:=xrGame_addr+$2D2110;
if not WriteJump(addr, cardinal(@CWeaponMagazinedWGrenade__GetBriefInfo_Replace_Patch), 5, false) then exit;
//[bug] áàã ñ èíâåðñèåé ïîðÿäêà ïàòðîíîâ â ìàãàçèíå ïðè ïåðåêëþ÷åíèè íà ïîäñòâîë è îáðàòíî - thanks to Shoker
addr:=xrGame_addr+$2D3810;
if not WriteJump(addr, cardinal(@CWeaponMagazinedWGrenade__PerformSwitchGL_ammoinverse_Patch), 6, false) then exit;
setlength(debug_bytes, 0);
result:=true;
end;
end.