1 #include "Font_Control.h"
2 #include "Soldier_Control.h"
3 #include "Soldier_Profile.h"
4 #include "Drugs_And_Alcohol.h"
5 #include "Items.h"
6 #include "Morale.h"
7 #include "Points.h"
8 #include "Message.h"
9 #include "Random.h"
10 #include "Text.h"
11 #include "Interface.h"
12 #include "Timer_Control.h"
13
14
15 UINT8 ubDrugTravelRate[] = {4, 2};
16 UINT8 ubDrugWearoffRate[] = {2, 2};
17 UINT8 ubDrugEffect[] = {15, 8};
18 UINT8 ubDrugSideEffect[] = {20, 10};
19 UINT8 ubDrugSideEffectRate[] = {2, 1};
20
21 INT32 giDrunkModifier[] =
22 {
23 100, // Sober
24 75, // Feeling good,
25 65, // Borderline
26 50, // Drunk
27 100, // HungOver
28 };
29
30 #define HANGOVER_AP_REDUCE 5
31 #define HANGOVER_BP_REDUCE 200
32
33
GetDrugType(UINT16 usItem)34 static UINT8 GetDrugType(UINT16 usItem)
35 {
36 if ( usItem == ADRENALINE_BOOSTER )
37 {
38 return( DRUG_TYPE_ADRENALINE );
39 }
40
41 if ( usItem == REGEN_BOOSTER )
42 {
43 return( DRUG_TYPE_REGENERATION );
44 }
45
46 if ( usItem == ALCOHOL || usItem == WINE || usItem == BEER )
47 {
48 return( DRUG_TYPE_ALCOHOL );
49 }
50
51
52 return( NO_DRUG );
53 }
54
55
ApplyDrugs(SOLDIERTYPE * pSoldier,OBJECTTYPE * pObject)56 BOOLEAN ApplyDrugs( SOLDIERTYPE *pSoldier, OBJECTTYPE *pObject )
57 {
58 UINT8 ubDrugType;
59 UINT8 ubKitPoints;
60 UINT16 usItem;
61
62 usItem = pObject->usItem;
63
64 // If not a syringe, return
65
66 ubDrugType = GetDrugType( usItem );
67
68 // Determine what type of drug....
69 if ( ubDrugType == NO_DRUG )
70 {
71 return( FALSE );
72 }
73
74 // do switch for Larry!!
75 if ( pSoldier->ubProfile == LARRY_NORMAL )
76 {
77 pSoldier = SwapLarrysProfiles( pSoldier );
78 }
79 else if ( pSoldier->ubProfile == LARRY_DRUNK )
80 {
81 gMercProfiles[ LARRY_DRUNK ].bNPCData = 0;
82 }
83
84 if ( ubDrugType < NUM_COMPLEX_DRUGS )
85 {
86
87 // Add effects
88 if ( ( pSoldier->bFutureDrugEffect[ ubDrugType ] + ubDrugEffect[ ubDrugType ] ) < 127 )
89 {
90 pSoldier->bFutureDrugEffect[ ubDrugType ] += ubDrugEffect[ ubDrugType ];
91 }
92 pSoldier->bDrugEffectRate[ ubDrugType ] = ubDrugTravelRate[ ubDrugType ];
93
94 // Increment times used during lifetime...
95 // CAP!
96 if ( ubDrugType == DRUG_TYPE_ADRENALINE )
97 {
98 if ( gMercProfiles[ pSoldier->ubProfile ].ubNumTimesDrugUseInLifetime != 255 )
99 {
100 gMercProfiles[ pSoldier->ubProfile ].ubNumTimesDrugUseInLifetime++;
101 }
102 }
103
104 // Increment side effects..
105 if ( ( pSoldier->bDrugSideEffect[ ubDrugType ] + ubDrugSideEffect[ ubDrugType ] ) < 127 )
106 {
107 pSoldier->bDrugSideEffect[ ubDrugType ] += ( ubDrugSideEffect[ ubDrugType ] );
108 }
109 // Stop side effects until were done....
110 pSoldier->bDrugSideEffectRate[ ubDrugType ] = 0;
111
112
113 if ( ubDrugType == DRUG_TYPE_ALCOHOL )
114 {
115 // ATE: use kit points...
116 if ( usItem == ALCOHOL )
117 {
118 ubKitPoints = 10;
119 }
120 else if ( usItem == WINE )
121 {
122 ubKitPoints = 20;
123 }
124 else
125 {
126 ubKitPoints = 100;
127 }
128
129 UseKitPoints(*pObject, ubKitPoints, *pSoldier);
130 }
131 else
132 {
133 // Remove the object....
134 if (--pObject->ubNumberOfObjects == 0) DeleteObj(pObject);
135
136 // ATE: Make guy collapse from heart attack if too much stuff taken....
137 if ( pSoldier->bDrugSideEffectRate[ ubDrugType ] > ( ubDrugSideEffect[ ubDrugType ] * 3 ) )
138 {
139 // Keel over...
140 DeductPoints( pSoldier, 0, 10000 );
141
142 // Permanently lower certain stats...
143 pSoldier->bWisdom -= 5;
144 pSoldier->bDexterity -= 5;
145 pSoldier->bStrength -= 5;
146
147 if (pSoldier->bWisdom < 1)
148 pSoldier->bWisdom = 1;
149 if (pSoldier->bDexterity < 1)
150 pSoldier->bDexterity = 1;
151 if (pSoldier->bStrength < 1)
152 pSoldier->bStrength = 1;
153
154 // export stat changes to profile
155 gMercProfiles[ pSoldier->ubProfile ].bWisdom = pSoldier->bWisdom;
156 gMercProfiles[ pSoldier->ubProfile ].bDexterity = pSoldier->bDexterity;
157 gMercProfiles[ pSoldier->ubProfile ].bStrength = pSoldier->bStrength;
158
159 // make those stats RED for a while...
160 pSoldier->uiChangeWisdomTime = GetJA2Clock();
161 pSoldier->usValueGoneUp &= ~( WIS_INCREASE );
162 pSoldier->uiChangeDexterityTime = GetJA2Clock();
163 pSoldier->usValueGoneUp &= ~( DEX_INCREASE );
164 pSoldier->uiChangeStrengthTime = GetJA2Clock();
165 pSoldier->usValueGoneUp &= ~( STRENGTH_INCREASE );
166 }
167 }
168 }
169 else
170 {
171 if ( ubDrugType == DRUG_TYPE_REGENERATION )
172 {
173 UINT8 const n = --pObject->ubNumberOfObjects;
174 INT8 const status = pObject->bStatus[n];
175 if (n == 0) DeleteObj(pObject);
176
177 // each use of a regen booster over 1, each day, reduces the effect
178 INT8 bRegenPointsGained = REGEN_POINTS_PER_BOOSTER * status / 100;
179 // are there fractional %s left over?
180 if (status % (100 / REGEN_POINTS_PER_BOOSTER) != 0)
181 {
182 // chance of an extra point
183 if (PreRandom(100 / REGEN_POINTS_PER_BOOSTER) < (UINT32)(status % (100 / REGEN_POINTS_PER_BOOSTER)))
184 {
185 bRegenPointsGained++;
186 }
187 }
188
189 bRegenPointsGained -= pSoldier->bRegenBoostersUsedToday;
190 if (bRegenPointsGained > 0)
191 {
192 // can't go above the points you get for a full boost
193 pSoldier->bRegenerationCounter = __min( pSoldier->bRegenerationCounter + bRegenPointsGained, REGEN_POINTS_PER_BOOSTER );
194 }
195 pSoldier->bRegenBoostersUsedToday++;
196 }
197 }
198
199 if ( ubDrugType == DRUG_TYPE_ALCOHOL )
200 {
201 ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, st_format_printf(pMessageStrings[ MSG_DRANK_SOME ], pSoldier->name, ShortItemNames[ usItem ]) );
202 }
203 else
204 {
205 ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_INTERFACE, st_format_printf(pMessageStrings[ MSG_MERC_TOOK_DRUG ], pSoldier->name) );
206 }
207
208 // Dirty panel
209 DirtyMercPanelInterface(pSoldier, DIRTYLEVEL2);
210
211 return( TRUE );
212 }
213
HandleEndTurnDrugAdjustments(SOLDIERTYPE * pSoldier)214 void HandleEndTurnDrugAdjustments( SOLDIERTYPE *pSoldier )
215 {
216 INT32 cnt, cnt2;
217 INT32 iNumLoops;
218 //INT8 bBandaged;
219
220 for ( cnt = 0; cnt < NUM_COMPLEX_DRUGS; cnt++ )
221 {
222 // If side effect rate is non-zero....
223 if ( pSoldier->bDrugSideEffectRate[ cnt ] > 0 )
224 {
225 // Subtract some...
226 pSoldier->bDrugSideEffect[ cnt ] -= pSoldier->bDrugSideEffectRate[ cnt ];
227
228 // If we're done, we're done!
229 if ( pSoldier->bDrugSideEffect[ cnt ] <= 0 )
230 {
231 pSoldier->bDrugSideEffect[ cnt ] = 0;
232 DirtyMercPanelInterface(pSoldier, DIRTYLEVEL1);
233 }
234 }
235
236 // IF drug rate is -ve, it's being worn off...
237 if ( pSoldier->bDrugEffectRate[ cnt ] < 0 )
238 {
239 pSoldier->bDrugEffect[ cnt ] -= ( -1 * pSoldier->bDrugEffectRate[ cnt ] );
240
241 // Have we run out?
242 if ( pSoldier->bDrugEffect[ cnt ] <= 0 )
243 {
244 pSoldier->bDrugEffect[ cnt ] = 0;
245
246 // Dirty panel
247 DirtyMercPanelInterface(pSoldier, DIRTYLEVEL2);
248
249 // Start the bad news!
250 pSoldier->bDrugSideEffectRate[ cnt ] = ubDrugSideEffectRate[ cnt ];
251
252 // The drug rate is 0 now too
253 pSoldier->bDrugEffectRate[ cnt ] = 0;
254
255 // Once for each 'level' of crash....
256 iNumLoops = ( pSoldier->bDrugSideEffect[ cnt ] / ubDrugSideEffect[ cnt ] ) + 1;
257
258 for ( cnt2 = 0; cnt2 < iNumLoops; cnt2++ )
259 {
260 // OK, give a much BIGGER morale downer
261 if ( cnt == DRUG_TYPE_ALCOHOL )
262 {
263 HandleMoraleEvent( pSoldier, MORALE_ALCOHOL_CRASH, pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ );
264 }
265 else
266 {
267 HandleMoraleEvent( pSoldier, MORALE_DRUGS_CRASH, pSoldier->sSectorX, pSoldier->sSectorY, pSoldier->bSectorZ );
268 }
269 }
270 }
271 }
272
273 // Add increase in effect....
274 if ( pSoldier->bDrugEffectRate[ cnt ] > 0 )
275 {
276 // Sip some in....
277 pSoldier->bFutureDrugEffect[ cnt ] -= pSoldier->bDrugEffectRate[ cnt ];
278 pSoldier->bDrugEffect[ cnt ] += pSoldier->bDrugEffectRate[ cnt ];
279
280 // Refresh morale w/ new drug value...
281 RefreshSoldierMorale( pSoldier );
282
283 // Check if we need to stop 'adding'
284 if ( pSoldier->bFutureDrugEffect[ cnt ] <= 0 )
285 {
286 pSoldier->bFutureDrugEffect[ cnt ] = 0;
287 // Change rate to -ve..
288 pSoldier->bDrugEffectRate[ cnt ] = -ubDrugWearoffRate[ cnt ];
289 }
290 }
291 }
292
293 if ( pSoldier->bRegenerationCounter > 0)
294 {
295 //bBandaged = BANDAGED( pSoldier );
296
297 // increase life
298 pSoldier->bLife = __min( pSoldier->bLife + LIFE_GAIN_PER_REGEN_POINT, pSoldier->bLifeMax );
299
300 if ( pSoldier->bLife == pSoldier->bLifeMax )
301 {
302 pSoldier->bBleeding = 0;
303 }
304 else if ( pSoldier->bBleeding + pSoldier->bLife > pSoldier->bLifeMax )
305 {
306 // got to reduce amount of bleeding
307 pSoldier->bBleeding = (pSoldier->bLifeMax - pSoldier->bLife);
308 }
309
310 // decrement counter
311 pSoldier->bRegenerationCounter--;
312 }
313 }
314
GetDrugEffect(SOLDIERTYPE * pSoldier,UINT8 ubDrugType)315 INT8 GetDrugEffect( SOLDIERTYPE *pSoldier, UINT8 ubDrugType )
316 {
317 return( pSoldier->bDrugEffect[ ubDrugType ] );
318 }
319
320
HandleAPEffectDueToDrugs(const SOLDIERTYPE * const pSoldier,UINT8 * const pubPoints)321 void HandleAPEffectDueToDrugs(const SOLDIERTYPE* const pSoldier, UINT8* const pubPoints)
322 {
323 INT8 bDrunkLevel;
324 INT16 sPoints = (*pubPoints);
325
326 // Are we in a side effect or good effect?
327 if ( pSoldier->bDrugEffect[ DRUG_TYPE_ADRENALINE ] )
328 {
329 // Adjust!
330 sPoints += pSoldier->bDrugEffect[ DRUG_TYPE_ADRENALINE ];
331 }
332 else if ( pSoldier->bDrugSideEffect[ DRUG_TYPE_ADRENALINE ] )
333 {
334 // Adjust!
335 sPoints -= pSoldier->bDrugSideEffect[ DRUG_TYPE_ADRENALINE ];
336
337 if ( sPoints < AP_MINIMUM )
338 {
339 sPoints = AP_MINIMUM;
340 }
341 }
342
343 bDrunkLevel = GetDrunkLevel( pSoldier );
344
345 if ( bDrunkLevel == HUNGOVER )
346 {
347 // Reduce....
348 sPoints -= HANGOVER_AP_REDUCE;
349
350 if ( sPoints < AP_MINIMUM )
351 {
352 sPoints = AP_MINIMUM;
353 }
354 }
355
356 (*pubPoints) = (UINT8)sPoints;
357 }
358
359
HandleBPEffectDueToDrugs(SOLDIERTYPE * pSoldier,INT16 * psPointReduction)360 void HandleBPEffectDueToDrugs( SOLDIERTYPE *pSoldier, INT16 *psPointReduction )
361 {
362 INT8 bDrunkLevel;
363
364 // Are we in a side effect or good effect?
365 if ( pSoldier->bDrugEffect[ DRUG_TYPE_ADRENALINE ] )
366 {
367 // Adjust!
368 (*psPointReduction) -= ( pSoldier->bDrugEffect[ DRUG_TYPE_ADRENALINE ] * BP_RATIO_RED_PTS_TO_NORMAL );
369 }
370 else if ( pSoldier->bDrugSideEffect[ DRUG_TYPE_ADRENALINE ] )
371 {
372 // Adjust!
373 (*psPointReduction) += ( pSoldier->bDrugSideEffect[ DRUG_TYPE_ADRENALINE ] * BP_RATIO_RED_PTS_TO_NORMAL );
374 }
375
376 bDrunkLevel = GetDrunkLevel( pSoldier );
377
378 if ( bDrunkLevel == HUNGOVER )
379 {
380 // Reduce....
381 (*psPointReduction) += HANGOVER_BP_REDUCE;
382 }
383 }
384
385
GetDrunkLevel(const SOLDIERTYPE * pSoldier)386 INT8 GetDrunkLevel(const SOLDIERTYPE* pSoldier)
387 {
388 INT8 bNumDrinks;
389
390 // If we have a -ve effect ...
391 if ( pSoldier->bDrugEffect[ DRUG_TYPE_ALCOHOL ] == 0 && pSoldier->bDrugSideEffect[ DRUG_TYPE_ALCOHOL ] == 0 )
392 {
393 return( SOBER );
394 }
395
396 if ( pSoldier->bDrugEffect[ DRUG_TYPE_ALCOHOL ] == 0 && pSoldier->bDrugSideEffect[ DRUG_TYPE_ALCOHOL ] != 0 )
397 {
398 return( HUNGOVER );
399 }
400
401 // Calculate how many drinks we have had....
402 bNumDrinks = ( pSoldier->bDrugEffect[ DRUG_TYPE_ALCOHOL ] / ubDrugEffect[ DRUG_TYPE_ALCOHOL ] );
403
404 if ( bNumDrinks <= 3 )
405 {
406 return( FEELING_GOOD );
407 }
408 else if ( bNumDrinks <= 4 )
409 {
410 return( BORDERLINE );
411 }
412 else
413 {
414 return( DRUNK );
415 }
416 }
417
418
EffectStatForBeingDrunk(const SOLDIERTYPE * pSoldier,INT32 iStat)419 INT32 EffectStatForBeingDrunk(const SOLDIERTYPE* pSoldier, INT32 iStat)
420 {
421 return( ( iStat * giDrunkModifier[ GetDrunkLevel( pSoldier ) ] / 100 ) );
422 }
423
424
MercUnderTheInfluence(const SOLDIERTYPE * pSoldier)425 BOOLEAN MercUnderTheInfluence(const SOLDIERTYPE* pSoldier)
426 {
427 // Are we in a side effect or good effect?
428 return pSoldier->bDrugEffect[DRUG_TYPE_ADRENALINE] ||
429 pSoldier->bDrugSideEffect[DRUG_TYPE_ADRENALINE] ||
430 GetDrunkLevel(pSoldier) != SOBER;
431 }
432