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