7
7
#pragma newdecls required
8
8
9
9
#include <sdkhooks>
10
- #include <sdktools >
10
+ #include <tf2_stocks >
11
11
12
12
#include <stocksoup/memory>
13
13
14
- #define PLUGIN_VERSION " 0.11 .0"
14
+ #define PLUGIN_VERSION " 0.12 .0"
15
15
public Plugin myinfo = {
16
16
name = " TF2 Utils" ,
17
17
author = " nosoop" ,
@@ -42,6 +42,16 @@ Handle g_SDKCallPointInRespawnRoom;
42
42
43
43
Address offs_CTFPlayer_hMyWearables ;
44
44
45
+ Address offs_CTFPlayerShared_flBurnDuration ;
46
+ Address offs_CTFPlayerShared_ConditionData ;
47
+
48
+ Address offs_TFCondInfo_flDuration ;
49
+ Address offs_TFCondInfo_hProvider ;
50
+
51
+ int sizeof_TFCondInfo ;
52
+
53
+ int g_nConditions ;
54
+
45
55
public APLRes AskPluginLoad2 (Handle self , bool late , char [] error , int maxlen ) {
46
56
RegPluginLibrary (" nosoop_tf2utils" );
47
57
@@ -50,6 +60,14 @@ public APLRes AskPluginLoad2(Handle self, bool late, char[] error, int maxlen) {
50
60
CreateNative (" TF2Util_GetPlayerMaxHealth" , Native_GetMaxHealth );
51
61
CreateNative (" TF2Util_GetPlayerMaxAmmo" , Native_GetMaxAmmo );
52
62
63
+ CreateNative (" TF2Util_GetPlayerConditionCount" , Native_GetPlayerConditionCount );
64
+ CreateNative (" TF2Util_GetPlayerConditionDuration" , Native_GetPlayerConditionDuration );
65
+ CreateNative (" TF2Util_SetPlayerConditionDuration" , Native_SetPlayerConditionDuration );
66
+ CreateNative (" TF2Util_GetPlayerConditionProvider" , Native_GetPlayerConditionProvider );
67
+ CreateNative (" TF2Util_SetPlayerConditionProvider" , Native_SetPlayerConditionProvider );
68
+ CreateNative (" TF2Util_GetPlayerBurnDuration" , Native_GetPlayerBurnDuration );
69
+ CreateNative (" TF2Util_SetPlayerBurnDuration" , Native_SetPlayerBurnDuration );
70
+
53
71
CreateNative (" TF2Util_IsEntityWearable" , Native_IsEntityWearable );
54
72
CreateNative (" TF2Util_GetPlayerWearable" , Native_GetPlayerWearable );
55
73
CreateNative (" TF2Util_GetPlayerWearableCount" , Native_GetPlayerWearableCount );
@@ -161,6 +179,38 @@ public void OnPluginStart() {
161
179
" CTFPlayer::m_hMyWearables" );
162
180
}
163
181
182
+ // TODO: use FindSendPropInfo("CTFPlayer", "m_ConditionData")
183
+ if (offs_CTFPlayerShared_ConditionData <= Address_Null ) {
184
+ offs_CTFPlayerShared_ConditionData = GameConfGetAddressOffset (hGameConf ,
185
+ " CTFPlayerShared::m_ConditionData" );
186
+ }
187
+
188
+ offs_CTFPlayerShared_flBurnDuration = GameConfGetAddressOffset (hGameConf ,
189
+ " CTFPlayerShared::m_flBurnDuration" );
190
+
191
+ sizeof_TFCondInfo = GameConfGetOffset (hGameConf , " sizeof(TFCondInfo_t)" );
192
+
193
+ offs_TFCondInfo_flDuration = GameConfGetAddressOffset (hGameConf ,
194
+ " TFCondInfo_t::m_flDuration" );
195
+
196
+ offs_TFCondInfo_hProvider = GameConfGetAddressOffset (hGameConf ,
197
+ " TFCondInfo_t::m_hProvider" );
198
+
199
+ Address pNumConds = GameConfGetAddress (hGameConf , " &TF_COND_LAST" );
200
+ if (! pNumConds ) {
201
+ LogError (" Could not determine location to read TF_COND_LAST from. "
202
+ ... " Condition bounds checking will produce false positives and condition "
203
+ ... " count native will report incorrect values." );
204
+ g_nConditions = 0xFF ;
205
+ } else if (! (g_nConditions = LoadFromAddress (pNumConds , NumberType_Int32 ))
206
+ || g_nConditions != g_nConditions & 0xFF ) {
207
+ // we expect the value to be within [1, 255]; if it isn't, then our address is invalid
208
+ LogError (" TF_COND_LAST is not within expected bounds (found %08x ). "
209
+ ... " Condition bounds checking will produce false positives and condition "
210
+ ... " count native will report incorrect values." , g_nConditions );
211
+ g_nConditions = 0xFF ;
212
+ }
213
+
164
214
delete hGameConf ;
165
215
}
166
216
@@ -374,6 +424,99 @@ int Native_GetPlayerLoadoutEntity(Handle plugin, int numParams) {
374
424
return SDKCall (g_SDKCallPlayerGetEntityForLoadoutSlot , client , loadoutSlot , check_wearable );
375
425
}
376
426
427
+ // int();
428
+ int Native_GetPlayerConditionCount (Handle plugin , int numParams ) {
429
+ return g_nConditions ;
430
+ }
431
+
432
+ // float(int client, TFCond cond);
433
+ any Native_GetPlayerConditionDuration (Handle plugin , int numParams ) {
434
+ int client = GetNativeCell (1 );
435
+ TFCond cond = GetNativeCell (2 );
436
+
437
+ if (! IsConditionValid (cond )) {
438
+ return ThrowNativeError (SP_ERROR_NATIVE , " Condition index %d is invalid" , cond );
439
+ } else if (! TF2_IsPlayerInCondition (client , cond )) {
440
+ return 0.0 ;
441
+ }
442
+
443
+ Address pData = GetConditionData (client , cond );
444
+ return LoadFromAddress (pData + offs_TFCondInfo_flDuration , NumberType_Int32 );
445
+ }
446
+
447
+ // void(int client, TFCond cond, float duration);
448
+ any Native_SetPlayerConditionDuration (Handle plugin , int numParams ) {
449
+ int client = GetNativeCell (1 );
450
+ TFCond cond = GetNativeCell (2 );
451
+ float duration = GetNativeCell (3 );
452
+
453
+ if (! IsConditionValid (cond )) {
454
+ ThrowNativeError (SP_ERROR_NATIVE , " Condition index %d is invalid" , cond );
455
+ } else if (! TF2_IsPlayerInCondition (client , cond )) {
456
+ ThrowNativeError (SP_ERROR_NATIVE , " Player is not in condition %d " , cond );
457
+ }
458
+
459
+ Address pData = GetConditionData (client , cond );
460
+ StoreToAddress (pData + offs_TFCondInfo_flDuration , view_as <any >(duration ),
461
+ NumberType_Int32 );
462
+ }
463
+
464
+ // int(int client, TFCond cond);
465
+ any Native_GetPlayerConditionProvider (Handle plugin , int numParams ) {
466
+ int client = GetNativeCell (1 );
467
+ TFCond cond = GetNativeCell (2 );
468
+
469
+ if (! IsConditionValid (cond )) {
470
+ return ThrowNativeError (SP_ERROR_NATIVE , " Condition index %d is invalid" , cond );
471
+ } else if (! TF2_IsPlayerInCondition (client , cond )) {
472
+ return INVALID_ENT_REFERENCE ;
473
+ }
474
+
475
+ Address pData = GetConditionData (client , cond );
476
+ return LoadEntityHandleFromAddress (pData + offs_TFCondInfo_hProvider );
477
+ }
478
+
479
+ // void(int client, TFCond cond, int provider);
480
+ any Native_SetPlayerConditionProvider (Handle plugin , int numParams ) {
481
+ int client = GetNativeCell (1 );
482
+ TFCond cond = GetNativeCell (2 );
483
+ int provider = GetNativeCell (3 );
484
+
485
+ if (! IsConditionValid (cond )) {
486
+ ThrowNativeError (SP_ERROR_NATIVE , " Condition index %d is invalid" , cond );
487
+ } else if (! TF2_IsPlayerInCondition (client , cond )) {
488
+ ThrowNativeError (SP_ERROR_NATIVE , " Player is not in condition %d " , cond );
489
+ } else if (! IsValidEntity (provider )) {
490
+ ThrowNativeError (SP_ERROR_NATIVE , " Entity %d is invalid" , provider );
491
+ }
492
+
493
+ Address pData = GetConditionData (client , cond );
494
+ StoreEntityHandleToAddress (pData + offs_TFCondInfo_hProvider , provider );
495
+ }
496
+
497
+ // float(int client);
498
+ any Native_GetPlayerBurnDuration (Handle plugin , int numParams ) {
499
+ int client = GetNativeCell (1 );
500
+ if (! TF2_IsPlayerInCondition (client , TFCond_OnFire )) {
501
+ return 0.0 ;
502
+ }
503
+ int pOffsSharedBurnDuration = FindSendPropInfo (" CTFPlayer" , " m_Shared" )
504
+ + view_as <int >(offs_CTFPlayerShared_flBurnDuration );
505
+ return GetEntDataFloat (client , pOffsSharedBurnDuration );
506
+ }
507
+
508
+ // void(int client, float duration);
509
+ any Native_SetPlayerBurnDuration (Handle plugin , int numParams ) {
510
+ int client = GetNativeCell (1 );
511
+ float duration = GetNativeCell (2 );
512
+ if (! TF2_IsPlayerInCondition (client , TFCond_OnFire )) {
513
+ return ;
514
+ }
515
+ int pOffsSharedBurnDuration = FindSendPropInfo (" CTFPlayer" , " m_Shared" )
516
+ + view_as <int >(offs_CTFPlayerShared_flBurnDuration );
517
+ SetEntDataFloat (client , pOffsSharedBurnDuration , duration );
518
+ }
519
+
377
520
bool IsEntityWeapon (int entity ) {
378
521
if (! IsValidEntity (entity )) {
379
522
ThrowNativeError (SP_ERROR_NATIVE , " Entity %d (%d ) is invalid" , entity ,
@@ -390,6 +533,17 @@ bool IsEntityWearable(int entity) {
390
533
return SDKCall (g_SDKCallIsEntityWearable , entity );
391
534
}
392
535
536
+ static Address GetConditionData (int client , TFCond cond ) {
537
+ Address pCondMemory = DereferencePointer (GetEntityAddress (client )
538
+ + view_as <Address >(FindSendPropInfo (" CTFPlayer" , " m_Shared" ))
539
+ + offs_CTFPlayerShared_ConditionData );
540
+ return pCondMemory + view_as <Address >(view_as <int >(cond ) * sizeof_TFCondInfo );
541
+ }
542
+
543
+ static bool IsConditionValid (TFCond cond ) {
544
+ return 0 <= view_as <any >(cond ) < g_nConditions ;
545
+ }
546
+
393
547
static Address GameConfGetAddressOffset (Handle gamedata , const char [] key ) {
394
548
Address offs = view_as <Address >(GameConfGetOffset (gamedata , key ));
395
549
if (offs == view_as <Address >(- 1 )) {
0 commit comments