44#include <sourcemod>
55#include <sourcescramble>
66
7- #define GAMEDATA_FILE " code_patcher"
8- #define KEY_SGSPREAD " sgspread"
9- #define BULLET_MAX_SIZE 4
10- #define DEBUG 0
7+ #define BULLET_MAX_SIZE 3
8+ #define GAMEDATA_FILE " code_patcher"
9+ #define KEY_SGSPREAD " sgspread"
1110
1211// Original code & Notes: https://github.com/Jahze/l4d2_plugins/tree/master/spread_patch
1312// Static Shotgun Spread leverages code_patcher (code_patcher.txt gamedata)
@@ -22,153 +21,177 @@ enum
2221 eWindows = 0 ,
2322 eLinux ,
2423 /* eMac, joke:) */
24+
2525 ePlatform_Size
26- }
26+ };
2727
2828int
29- g_ePlatform ;
29+ g_ePlatform = eLinux ;
3030
3131static const int
32- g_BulletOffsets [ePlatform_Size ][BULLET_MAX_SIZE ] = {
33- { 0xf , 0x21 , 0x30 , 0x3f }, // Windows
34- { 0x11 , 0x22 , 0x2f , 0x43 } // Linux
32+ g_iBulletOffsets [ePlatform_Size ][BULLET_MAX_SIZE ] = {
33+ { 0xf , 0x21 , 0x30 }, // Windows
34+ { 0x11 , 0x22 , 0x2f } // Linux
3535 },
36- g_FactorOffset [ePlatform_Size ] = {
36+ g_iDegreeOffsets [ePlatform_Size ] = {
37+ 0x3f , // Windows
38+ 0x43 // Linux
39+ },
40+ g_iFactorOffset [ePlatform_Size ] = {
3741 0x36 , // Windows
3842 0x34 // Linux
3943 },
40- g_CenterPelletOffset [ePlatform_Size ] = {
44+ g_iCenterPelletOffset [ePlatform_Size ] = {
4145 - 0x36 , // Windows
4246 - 0x1c // Linux
4347 };
4448
49+ Address
50+ g_pBullets [BULLET_MAX_SIZE ] = {Address_Null , ...},
51+ g_pDegree = Address_Null ,
52+ g_pFactor = Address_Null ,
53+ g_pCenterPellet = Address_Null ;
54+
4555MemoryPatch
46- g_hPatch_sgspread ;
56+ g_hPatchSgSpread = null ;
4757
4858ConVar
49- hRing1BulletsCvar ,
50- hRing1FactorCvar ,
51- hCenterPelletCvar ;
59+ g_hCvarRing1Bullets = null ,
60+ g_hCvarRing1Factor = null ,
61+ g_hCvarCenterPellet = null ;
5262
53- public Plugin myinfo =
63+ public Plugin myinfo =
5464{
5565 name = " L4D2 Static Shotgun Spread" ,
5666 author = " Jahze, Visor, A1m`, Rena" ,
57- version = " 1.6.1 " ,
67+ version = " 1.6.5 " ,
5868 description = " Changes the values in the sgspread patch" ,
5969 url = " https://github.com/SirPlease/L4D2-Competitive-Rework"
6070};
6171
6272public void OnPluginStart ()
6373{
64- Handle conf = LoadGameConfigFile (GAMEDATA_FILE );
65- if (conf == null ) {
74+ InitGameData ();
75+
76+ g_hCvarRing1Bullets = CreateConVar (" sgspread_ring1_bullets" , " 3" , " Number of bullets for the first ring, the remaining bullets will be in the second ring." );
77+ g_hCvarRing1Factor = CreateConVar (" sgspread_ring1_factor" , " 2" , " Determines how far or closer the bullets will be from the center for the first ring." );
78+ g_hCvarCenterPellet = CreateConVar (" sgspread_center_pellet" , " 1" , " Center pellet: 0 - off, 1 - on." , _ , true , 0.0 , true , 1.0 );
79+
80+ InitPlugin ();
81+ }
82+
83+ void InitGameData ()
84+ {
85+ Handle hConf = LoadGameConfigFile (GAMEDATA_FILE );
86+ if (hConf == null ) {
6687 SetFailState (" Missing gamedata \" " ... GAMEDATA_FILE ... " \" " );
6788 }
68-
69- g_hPatch_sgspread = MemoryPatch .CreateFromConf (conf , KEY_SGSPREAD );
70- if (g_hPatch_sgspread == null || ! g_hPatch_sgspread .Validate ()) {
89+
90+ g_ePlatform = GameConfGetOffset (hConf , " OS" );
91+ if (g_ePlatform == - 1 ) {
92+ SetFailState (" Failed to retrieve offset \" OS\" " );
93+ }
94+
95+ g_hPatchSgSpread = MemoryPatch .CreateFromConf (hConf , KEY_SGSPREAD );
96+ if (g_hPatchSgSpread == null || ! g_hPatchSgSpread .Validate ()) {
7197 SetFailState (" Failed to validate MemoryPatch \" " ... KEY_SGSPREAD ... " \" " );
7298 }
73-
74- if (! g_hPatch_sgspread .Enable ()) {
75- SetFailState (" Failed to enable MemoryPatch \" " ... KEY_SGSPREAD ... " \" " );
99+
100+ Address pFinalAddr = g_hPatchSgSpread .Address + view_as <Address >(g_iCenterPelletOffset [g_ePlatform ]);
101+ int iCurrentValue = LoadFromAddress (pFinalAddr , NumberType_Int8 );
102+ if (iCurrentValue != 1 ) {
103+ SetFailState (" Center pellet offset is uncorrect! CheckByte: %x " , iCurrentValue );
76104 }
77-
78- g_ePlatform = GameConfGetOffset (conf , " OS" );
79- if (g_ePlatform == - 1 ) {
80- SetFailState (" Failed to retrieve offset \" OS\" " );
105+
106+ if (! g_hPatchSgSpread .Enable ()) {
107+ SetFailState (" Failed to enable MemoryPatch \" " ... KEY_SGSPREAD ... " \" " );
81108 }
82-
83- delete conf ;
84-
85- hRing1BulletsCvar = CreateConVar (" sgspread_ring1_bullets" , " 3" , " Number of bullets for the first ring, the remaining bullets will be in the second ring." );
86- hRing1FactorCvar = CreateConVar (" sgspread_ring1_factor" , " 2" , " Determines how far or closer the bullets will be from the center for the first ring." );
87- hCenterPelletCvar = CreateConVar (" sgspread_center_pellet" , " 1" , " Center pellet: 0 - off, 1 - on." , _ , true , 0.0 , true , 1.0 );
88-
89- hRing1BulletsCvar .AddChangeHook (OnRing1BulletsChange );
90- hRing1FactorCvar .AddChangeHook (OnRing1FactorChange );
91- hCenterPelletCvar .AddChangeHook (OnCenterPelletChange );
92-
93- HotPatchBullets (hRing1BulletsCvar .IntValue );
94- HotPatchFactor (hRing1FactorCvar .IntValue );
95- HotPatchCenterPellet (hCenterPelletCvar .BoolValue );
109+
110+ delete hConf ;
96111}
97112
98- static void HotPatchCenterPellet ( bool newValue )
113+ void InitPlugin ( )
99114{
100- Address pAddr = g_hPatch_sgspread .Address ;
101-
102- int currentValue = LoadFromAddress (pAddr + view_as <Address >(g_CenterPelletOffset [g_ePlatform ]), NumberType_Int8 );
103-
104- int bullets = hRing1BulletsCvar .IntValue ;
105-
106- #if DEBUG
107- static bool IsFirstPatch = false ;
108- if (! IsFirstPatch ) {
109- PrintToServer (" Center pellet offset is %s ! CheckByte: %x " , (currentValue == 0x01 ) ? " correct " : " uncorrect" , currentValue );
110- PrintToChatAll (" Center pellet offset is %s ! CheckByte: %x " , (currentValue == 0x01 ) ? " correct " : " uncorrect" , currentValue );
111- IsFirstPatch = true ;
115+ for (int i = 0 ; i < BULLET_MAX_SIZE ; i ++ ) {
116+ g_pBullets [i ] = g_hPatchSgSpread .Address + view_as <Address >(g_iBulletOffsets [g_ePlatform ][i ]);
112117 }
113- #endif
114-
115- if (!! currentValue == newValue ) {
116- return ;
117- }
118-
119- StoreToAddress (pAddr + view_as <Address >(g_CenterPelletOffset [g_ePlatform ]), view_as <int >(newValue ), NumberType_Int8 );
120-
121- StoreToAddress (pAddr + view_as <Address >(g_BulletOffsets [g_ePlatform ][0 ]), bullets + (1 - view_as <int >(! newValue )), NumberType_Int8 );
122- StoreToAddress (pAddr + view_as <Address >(g_BulletOffsets [g_ePlatform ][1 ]), bullets + (1 - view_as <int >(! newValue )), NumberType_Int8 );
123- StoreToAddress (pAddr + view_as <Address >(g_BulletOffsets [g_ePlatform ][2 ]), bullets + (2 - view_as <int >(! newValue )), NumberType_Int8 );
118+
119+ g_pDegree = g_hPatchSgSpread .Address + view_as <Address >(g_iDegreeOffsets [g_ePlatform ]);
120+ g_pFactor = g_hPatchSgSpread .Address + view_as <Address >(g_iFactorOffset [g_ePlatform ]);
121+ g_pCenterPellet = g_hPatchSgSpread .Address + view_as <Address >(g_iCenterPelletOffset [g_ePlatform ]);
122+
123+ HotPatchBullets (g_hCvarRing1Bullets .IntValue );
124+ HotPatchFactor (g_hCvarRing1Factor .IntValue );
125+ HotPatchCenterPellet (g_hCvarCenterPellet .BoolValue );
126+
127+ g_hCvarRing1Bullets .AddChangeHook (OnRing1BulletsChange );
128+ g_hCvarRing1Factor .AddChangeHook (OnRing1FactorChange );
129+ g_hCvarCenterPellet .AddChangeHook (OnCenterPelletChange );
124130}
125131
126- static void HotPatchBullets ( int nBullets )
132+ public void OnPluginEnd ( )
127133{
128- bool centerpellet = ! hCenterPelletCvar .BoolValue ;
129- float degree = 0.0 ;
130-
131- if (g_ePlatform == eWindows ) {
132- degree = 360.0 / float (nBullets );
133- } else {
134- degree = 360.0 / (2.0 * float (nBullets ));
134+ if (g_pCenterPellet != Address_Null ) {
135+ int iCurrentValue = LoadFromAddress (g_pCenterPellet , NumberType_Int8 );
136+
137+ if (iCurrentValue != 1 ) {
138+ StoreToAddress (g_pCenterPellet , 1 , NumberType_Int8 );
139+ }
135140 }
136-
137- Address pAddr = g_hPatch_sgspread .Address ;
138-
139- StoreToAddress (pAddr + view_as <Address >(g_BulletOffsets [g_ePlatform ][0 ]), nBullets + (1 - view_as <int >(centerpellet )), NumberType_Int8 );
140- StoreToAddress (pAddr + view_as <Address >(g_BulletOffsets [g_ePlatform ][1 ]), nBullets + (1 - view_as <int >(centerpellet )), NumberType_Int8 );
141- StoreToAddress (pAddr + view_as <Address >(g_BulletOffsets [g_ePlatform ][2 ]), nBullets + (2 - view_as <int >(centerpellet )), NumberType_Int8 );
142-
143- StoreToAddress (pAddr + view_as <Address >(g_BulletOffsets [g_ePlatform ][3 ]), view_as <int >(degree ), NumberType_Int32 );
144141}
145142
146- static void HotPatchFactor ( int factor )
143+ void OnRing1BulletsChange ( ConVar hConVar , const char [] sOldValue , const char [] sNewValue )
147144{
148- Address pAddr = g_hPatch_sgspread .Address ;
145+ HotPatchBullets (hConVar .IntValue );
146+ }
149147
150- if (g_ePlatform == eWindows ) {
151- StoreToAddress (pAddr + view_as <Address >(g_FactorOffset [eWindows ]), view_as <int >(float (factor )), NumberType_Int32 ); //On windows need the float type !!!
152- return ;
148+ void OnRing1FactorChange (ConVar hConVar , const char [] sOldValue , const char [] sNewValue )
149+ {
150+ HotPatchFactor (hConVar .IntValue );
151+ }
152+
153+ void OnCenterPelletChange (ConVar hConVar , const char [] sOldValue , const char [] sNewValue )
154+ {
155+ HotPatchCenterPellet (hConVar .BoolValue );
156+ }
157+
158+ void HotPatchBullets (int iBullets )
159+ {
160+ PatchBullets (iBullets , g_hCvarCenterPellet .BoolValue );
161+
162+ float fBullets = float (iBullets );
163+ if (g_ePlatform == eLinux ) {
164+ fBullets *= 2.0 ;
153165 }
154-
155- StoreToAddress (pAddr + view_as <Address >( g_FactorOffset [ eLinux ]), factor , NumberType_Int32 );
166+
167+ StoreToAddress (g_pDegree , view_as <int >( 360.0 / fBullets ) , NumberType_Int32 );
156168}
157169
158- void OnRing1BulletsChange ( ConVar hCvar , const char [] oldVal , const char [] newVal )
170+ void HotPatchFactor ( int iFactor )
159171{
160- int nBullets = StringToInt (newVal );
161- HotPatchBullets (nBullets );
172+ // Asm patch on windows need the float type !
173+ int iSetFactor = (g_ePlatform == eWindows ) ? view_as <int >(float (iFactor )) : iFactor ;
174+ StoreToAddress (g_pFactor , iSetFactor , NumberType_Int32 );
162175}
163176
164- void OnRing1FactorChange ( ConVar hCvar , const char [] oldVal , const char [] newVal )
177+ void HotPatchCenterPellet ( bool bNewValue )
165178{
166- int factor = StringToInt (newVal );
167- HotPatchFactor (factor );
179+ bool iCurrentValue = LoadFromAddress (g_pCenterPellet , NumberType_Int8 );
180+ if (iCurrentValue == bNewValue ) {
181+ return ;
182+ }
183+
184+ StoreToAddress (g_pCenterPellet , view_as <int >(bNewValue ), NumberType_Int8 );
185+
186+ PatchBullets (g_hCvarRing1Bullets .IntValue , bNewValue );
168187}
169188
170- void OnCenterPelletChange ( ConVar hCvar , const char [] oldVal , const char [] newVal )
189+ void PatchBullets ( int iBullets , bool bCenterPellet )
171190{
172- bool value = !! StringToInt (newVal );
173- HotPatchCenterPellet (value );
191+ int iOffset1 = iBullets + (bCenterPellet ? 1 : 0 );
192+ int iOffset2 = iBullets + (bCenterPellet ? 2 : 1 );
193+
194+ StoreToAddress (g_pBullets [0 ], iOffset1 , NumberType_Int8 );
195+ StoreToAddress (g_pBullets [1 ], iOffset1 , NumberType_Int8 );
196+ StoreToAddress (g_pBullets [2 ], iOffset2 , NumberType_Int8 );
174197}
0 commit comments