1 #include "Font_Control.h"
2 #include "Soldier_Control.h"
3 #include "Overhead.h"
4 #include "Boxing.h"
5 #include "Render_Fun.h"
6 #include "Random.h"
7 #include "Timer_Control.h"
8 #include "WorldMan.h"
9 #include "Soldier_Profile.h"
10 #include "NPC.h"
11 #include "OppList.h"
12 #include "AI.h"
13 #include "Handle_UI.h"
14 #include "Points.h"
15 #include "Interface.h"
16 #include "Interface_Dialogue.h"
17 #include "TeamTurns.h"
18 #include "Music_Control.h"
19 #include "ContentMusic.h"
20 #include "History.h"
21 #include "Game_Clock.h"
22 #include "StrategicMap.h"
23 #include "Animation_Data.h"
24 #include "Items.h"
25
26 INT16 gsBoxerGridNo[ NUM_BOXERS ] = { 11393, 11233, 11073 };
27 SOLDIERTYPE* gBoxer[NUM_BOXERS];
28 BOOLEAN gfBoxerFought[ NUM_BOXERS ] = { FALSE, FALSE, FALSE };
29 BOOLEAN gfLastBoxingMatchWonByPlayer = FALSE;
30 UINT8 gubBoxingMatchesWon = 0;
31 UINT8 gubBoxersRests = 0;
32 BOOLEAN gfBoxersResting = FALSE;
33
34
ExitBoxing(void)35 void ExitBoxing(void)
36 {
37 // find boxers and turn them neutral again
38
39 // first time through loop, look for AI guy, then for PC guy.... for stupid
40 // oppcnt/alert status reasons
41 for (UINT8 ubPass = 0; ubPass < 2; ++ubPass)
42 {
43 // because boxer could die, loop through all soldier ptrs
44 FOR_EACH_SOLDIER(s)
45 {
46 if (!(s->uiStatusFlags & SOLDIER_BOXER)) continue;
47 if (GetRoom(s->sGridNo) != BOXING_RING) continue;
48
49 if (s->uiStatusFlags & SOLDIER_PC)
50 {
51 if (ubPass == 0) continue; // pass 0, only handle AI
52 // put guy under AI control temporarily
53 s->uiStatusFlags |= SOLDIER_PCUNDERAICONTROL;
54 }
55 else
56 {
57 if (ubPass == 1) continue; // pass 1, only handle PCs
58 // reset AI boxer to neutral
59 SetSoldierNeutral(s);
60 RecalculateOppCntsDueToBecomingNeutral(s);
61 }
62 CancelAIAction(s);
63 s->bAlertStatus = STATUS_GREEN;
64 s->bUnderFire = 0;
65
66 // if necessary, revive boxer so he can leave ring
67 if (s->bLife > 0 && (s->bLife < OKLIFE || s->bBreath < OKBREATH))
68 {
69 s->bLife = __max(OKLIFE * 2, s->bLife);
70 if (s->bBreath < 100)
71 {
72 // deduct -ve BPs to grant some BPs back (properly)
73 DeductPoints(s, 0, -100 * (100 - s->bBreath));
74 }
75 BeginSoldierGetup(s);
76 }
77 }
78 }
79
80 DeleteTalkingMenu();
81 EndAllAITurns();
82
83 if (CheckForEndOfCombatMode(FALSE))
84 {
85 EndTopMessage();
86 SetMusicMode(MUSIC_TACTICAL_NOTHING);
87 // Lock UI until we get out of the ring
88 guiPendingOverrideEvent = LU_BEGINUILOCK;
89 }
90 }
91
92
93 // in both these cases we're going to want the AI to take over and move the boxers
94 // out of the ring!
EndBoxingMatch(SOLDIERTYPE * pLoser)95 void EndBoxingMatch( SOLDIERTYPE * pLoser )
96 {
97 if (pLoser->bTeam == OUR_TEAM )
98 {
99 SetBoxingState( LOST_ROUND );
100 }
101 else
102 {
103 SetBoxingState( WON_ROUND );
104 gfLastBoxingMatchWonByPlayer = TRUE;
105 gubBoxingMatchesWon++;
106 }
107 TriggerNPCRecord( DARREN, 22 );
108 }
109
BoxingPlayerDisqualified(SOLDIERTYPE * pOffender,INT8 bReason)110 void BoxingPlayerDisqualified( SOLDIERTYPE * pOffender, INT8 bReason )
111 {
112 if (bReason == BOXER_OUT_OF_RING || bReason == NON_BOXER_IN_RING)
113 {
114 EVENT_StopMerc(pOffender);
115 }
116 SetBoxingState( DISQUALIFIED );
117 TriggerNPCRecord( DARREN, 21 );
118 //ExitBoxing();
119 }
120
TriggerEndOfBoxingRecord(SOLDIERTYPE * pSoldier)121 void TriggerEndOfBoxingRecord( SOLDIERTYPE * pSoldier )
122 {
123 // unlock UI
124 guiPendingOverrideEvent = LU_ENDUILOCK;
125
126 if ( pSoldier )
127 {
128 switch( gTacticalStatus.bBoxingState )
129 {
130 case WON_ROUND:
131 AddHistoryToPlayersLog( HISTORY_WON_BOXING, pSoldier->ubProfile, GetWorldTotalMin(), gWorldSectorX, gWorldSectorY );
132 TriggerNPCRecord( DARREN, 23 );
133 break;
134 case LOST_ROUND:
135 // log as lost
136 AddHistoryToPlayersLog( HISTORY_LOST_BOXING, pSoldier->ubProfile, GetWorldTotalMin(), gWorldSectorX, gWorldSectorY );
137 TriggerNPCRecord( DARREN, 24 );
138 break;
139 case DISQUALIFIED:
140 AddHistoryToPlayersLog( HISTORY_DISQUALIFIED_BOXING, pSoldier->ubProfile, GetWorldTotalMin(), gWorldSectorX, gWorldSectorY );
141 break;
142 }
143 }
144
145 SetBoxingState( NOT_BOXING );
146 }
147
CountPeopleInBoxingRing(void)148 UINT8 CountPeopleInBoxingRing( void )
149 {
150 UINT8 ubTotalInRing = 0;
151
152 FOR_EACH_MERC(i)
153 {
154 if (GetRoom((*i)->sGridNo) == BOXING_RING)
155 {
156 ++ubTotalInRing;
157 }
158 }
159
160 return( ubTotalInRing );
161 }
162
163
164 static void PickABoxer();
165
166
CountPeopleInBoxingRingAndDoActions(void)167 static void CountPeopleInBoxingRingAndDoActions(void)
168 {
169 UINT8 ubTotalInRing = 0;
170 UINT8 ubPlayersInRing = 0;
171 SOLDIERTYPE *pInRing[2] = { NULL, NULL };
172 SOLDIERTYPE *pNonBoxingPlayer = NULL;
173
174 FOR_EACH_MERC(i)
175 {
176 SOLDIERTYPE* const s = *i;
177 if (GetRoom(s->sGridNo) != BOXING_RING) continue;
178
179 if (ubTotalInRing < 2) pInRing[ubTotalInRing] = s;
180 ++ubTotalInRing;
181
182 if (s->uiStatusFlags & SOLDIER_PC)
183 {
184 ++ubPlayersInRing;
185 if (!pNonBoxingPlayer && !(s->uiStatusFlags & SOLDIER_BOXER))
186 {
187 pNonBoxingPlayer = s;
188 }
189 }
190 }
191
192 if ( ubPlayersInRing > 1 )
193 {
194 // boxing match just became invalid!
195 if ( gTacticalStatus.bBoxingState <= PRE_BOXING )
196 {
197 BoxingPlayerDisqualified( pNonBoxingPlayer, NON_BOXER_IN_RING );
198 // set to not in boxing or it won't be handled otherwise
199 SetBoxingState( NOT_BOXING );
200 }
201 else
202 {
203 BoxingPlayerDisqualified( pNonBoxingPlayer, NON_BOXER_IN_RING );
204 }
205
206 return;
207 }
208
209
210 if ( gTacticalStatus.bBoxingState == BOXING_WAITING_FOR_PLAYER )
211 {
212 if ( ubTotalInRing == 1 && ubPlayersInRing == 1 )
213 {
214 // time to go to pre-boxing
215 SetBoxingState( PRE_BOXING );
216 PickABoxer();
217 }
218 }
219 else
220 // if pre-boxing, check for two people (from different teams!) in the ring
221 if ( gTacticalStatus.bBoxingState == PRE_BOXING )
222 {
223 if ( ubTotalInRing == 2 && ubPlayersInRing == 1 )
224 {
225 // ladieees and gennleman, we have a fight!
226 for (UINT32 uiLoop = 0; uiLoop < 2; ++uiLoop)
227 {
228 if ( ! ( pInRing[ uiLoop ]->uiStatusFlags & SOLDIER_BOXER ) )
229 {
230 // set as boxer!
231 pInRing[ uiLoop ]->uiStatusFlags |= SOLDIER_BOXER;
232 }
233 }
234 // start match!
235 SetBoxingState( BOXING );
236 gfLastBoxingMatchWonByPlayer = FALSE;
237
238 // give the first turn to a randomly chosen boxer
239 EnterCombatMode( pInRing[ Random( 2 ) ]->bTeam );
240 }
241 }
242 /*
243 else
244 {
245 // check to see if the player has more than one person in the ring
246 if ( ubPlayersInRing > 1 )
247 {
248 // boxing match just became invalid!
249 BoxingPlayerDisqualified( pNonBoxingPlayer, NON_BOXER_IN_RING );
250 return;
251 }
252 }*/
253 }
254
255
CheckOnBoxers()256 bool CheckOnBoxers()
257 {
258 // repick boxer IDs every time
259 if (!gBoxer[0])
260 {
261 // get boxer soldier IDs!
262 for (UINT32 i = 0; i != NUM_BOXERS; ++i)
263 {
264 SOLDIERTYPE* const s = WhoIsThere2(gsBoxerGridNo[i], 0);
265 if (!s || FindObjClass(s, IC_WEAPON) != NO_SLOT) continue;
266 // No weapon so this guy is a boxer
267 gBoxer[i] = s;
268 }
269 }
270
271 return gBoxer[0] || gBoxer[1] || gBoxer[2];
272 }
273
274
BoxerExists()275 bool BoxerExists()
276 {
277 FOR_EACH(GridNo const, i, gsBoxerGridNo)
278 {
279 if (WhoIsThere2(*i, 0)) return true;
280 }
281 return false;
282 }
283
284
PickABoxer()285 static void PickABoxer()
286 {
287 for (UINT32 i = 0; i != NUM_BOXERS; ++i)
288 {
289 SOLDIERTYPE* const boxer = gBoxer[i];
290 if (!boxer) continue;
291
292 if (gfBoxerFought[i])
293 {
294 // pathetic attempt to prevent multiple AI boxers
295 boxer->uiStatusFlags &= ~SOLDIER_BOXER;
296 }
297 else if (boxer->bActive && boxer->bInSector && boxer->bLife >= OKLIFE)
298 {
299 // Pick this boxer
300 boxer->uiStatusFlags |= SOLDIER_BOXER;
301 SetSoldierNonNeutral(boxer);
302 RecalculateOppCntsDueToNoLongerNeutral(boxer);
303 CancelAIAction(boxer);
304 RESETTIMECOUNTER(boxer->AICounter, 0);
305 gfBoxerFought[i] = TRUE;
306 // Improve stats based on the # of rests these guys have had
307 boxer->bStrength = __min(100, boxer->bStrength + gubBoxersRests * 5);
308 boxer->bDexterity = __min(100, boxer->bDexterity + gubBoxersRests * 5);
309 boxer->bAgility = __min(100, boxer->bAgility + gubBoxersRests * 5);
310 boxer->bLifeMax = __min(100, boxer->bLifeMax + gubBoxersRests * 5);
311 // Give the 3rd boxer martial arts
312 if (i == NUM_BOXERS - 1 && boxer->ubBodyType == REGMALE)
313 {
314 boxer->ubSkillTrait1 = MARTIALARTS;
315 }
316 break;
317 }
318 }
319 }
320
321
BoxerAvailable()322 bool BoxerAvailable()
323 {
324 // No way around this, BoxerAvailable will have to go find boxer IDs if they aren't set.
325 if (!CheckOnBoxers()) return false;
326
327 for (UINT8 i = 0; i != NUM_BOXERS; ++i)
328 {
329 if (gBoxer[i] && !gfBoxerFought[i]) return true;
330 }
331 return false;
332 }
333
334
335 // NOTE THIS IS NOW BROKEN BECAUSE NPC.C ASSUMES THAT BOXERSAVAILABLE < 3 IS A
336 // SEQUEL FIGHT. Maybe we could check Kingpin's location instead!
BoxersAvailable(void)337 static UINT8 BoxersAvailable(void)
338 {
339 UINT8 ubLoop;
340 UINT8 ubCount = 0;
341
342 for( ubLoop = 0; ubLoop < NUM_BOXERS; ubLoop++ )
343 {
344 if (gBoxer[ubLoop] != NULL && !gfBoxerFought[ubLoop]) ubCount++;
345 }
346
347 return( ubCount );
348 }
349
AnotherFightPossible(void)350 BOOLEAN AnotherFightPossible( void )
351 {
352 // Check that and a boxer is still available and
353 // a player has at least OKLIFE + 5 life
354
355 // and at least one fight HAS occurred
356 UINT8 ubAvailable;
357
358 ubAvailable = BoxersAvailable();
359
360 if ( ubAvailable == NUM_BOXERS || ubAvailable == 0 )
361 {
362 return( FALSE );
363 }
364
365 CFOR_EACH_IN_TEAM(s, OUR_TEAM)
366 {
367 if (s->bInSector && s->bLife > OKLIFE + 5 && !s->bCollapsed)
368 {
369 return TRUE;
370 }
371 }
372
373 return( FALSE );
374 }
375
376
BoxingMovementCheck(SOLDIERTYPE * pSoldier)377 void BoxingMovementCheck( SOLDIERTYPE * pSoldier )
378 {
379 if (GetRoom(pSoldier->sGridNo) == BOXING_RING)
380 {
381 // someone moving in/into the ring
382 CountPeopleInBoxingRingAndDoActions();
383 }
384 else if ( ( gTacticalStatus.bBoxingState == BOXING ) && ( pSoldier->uiStatusFlags & SOLDIER_BOXER ) )
385 {
386 // boxer stepped out of the ring!
387 BoxingPlayerDisqualified( pSoldier, BOXER_OUT_OF_RING );
388 // add the history record here.
389 AddHistoryToPlayersLog( HISTORY_DISQUALIFIED_BOXING, pSoldier->ubProfile, GetWorldTotalMin(), gWorldSectorX, gWorldSectorY );
390 // make not a boxer any more
391 pSoldier->uiStatusFlags &= ~(SOLDIER_BOXER);
392 pSoldier->uiStatusFlags &= (~SOLDIER_PCUNDERAICONTROL);
393 }
394 }
395
SetBoxingState(INT8 bNewState)396 void SetBoxingState( INT8 bNewState )
397 {
398 if ( gTacticalStatus.bBoxingState == NOT_BOXING )
399 {
400 if ( bNewState != NOT_BOXING )
401 {
402 // pause time
403 PauseGame();
404 }
405
406 }
407 else
408 {
409 if ( bNewState == NOT_BOXING )
410 {
411 // unpause time
412 UnPauseGame();
413
414 if ( BoxersAvailable() == NUM_BOXERS )
415 {
416 // set one boxer to be set as boxed so that the game will allow another
417 // fight to occur
418 gfBoxerFought[ 0 ] = TRUE;
419 }
420
421 }
422 }
423 gTacticalStatus.bBoxingState = bNewState;
424 }
425
426
ClearAllBoxerFlags(void)427 void ClearAllBoxerFlags(void)
428 {
429 FOR_EACH_MERC(i) (*i)->uiStatusFlags &= ~SOLDIER_BOXER;
430 }
431