mirror of
https://github.com/OpenDriver2/REDRIVER2.git
synced 2024-11-22 10:22:48 +01:00
475 lines
9.6 KiB
C
475 lines
9.6 KiB
C
#include "driver2.h"
|
|
#include "felony.h"
|
|
#include "cop_ai.h"
|
|
#include "civ_ai.h"
|
|
|
|
#include "players.h"
|
|
#include "cars.h"
|
|
#include "mission.h"
|
|
#include "convert.h"
|
|
#include "gamesnd.h"
|
|
#include "dr2roads.h"
|
|
#include "overlay.h"
|
|
#include "cutrecorder.h"
|
|
|
|
short initialOccurrenceDelay[12] = { 24, 0, 0, 0, 0, 0, 0, 0, 24, 0, 24, 0 };
|
|
short initialReccurrenceDelay[12] = { 128, 0, 128, 64, 64, 32, 32, 0, 128, 256 };
|
|
|
|
int CopsCanSeePlayer = 0;
|
|
short pedestrianFelony = 0;
|
|
|
|
FELONY_VALUE initialFelonyValue[12] =
|
|
{
|
|
{ 659, 0 },
|
|
{ 659, 75 },
|
|
{ 659, 0 },
|
|
{ 659, 0 },
|
|
{ 659, 659 },
|
|
{ 1318, 659 },
|
|
{ 659, 659 },
|
|
{ 659, 25 },
|
|
{ 659, 0 },
|
|
{ 659, 0 },
|
|
{ 659, 0 },
|
|
{ 4096, 0 }
|
|
};
|
|
|
|
FELONY_DATA felonyData;
|
|
|
|
int FelonyIncreaseTime = 0;
|
|
int FelonyDecreaseTime = 0;
|
|
|
|
int FelonyIncreaseTimer = 0;
|
|
int FelonyDecreaseTimer = 0;
|
|
|
|
|
|
// [D] [T]
|
|
void InitFelonyDelayArray(FELONY_DELAY *pFelonyDelay, short *pMaximum, int count)
|
|
{
|
|
FELONY_DELAY *pCurrent;
|
|
|
|
pCurrent = pFelonyDelay + count;
|
|
|
|
while (pFelonyDelay < pCurrent)
|
|
{
|
|
pFelonyDelay->current = 0;
|
|
pFelonyDelay->maximum = *pMaximum++;
|
|
|
|
pFelonyDelay++;
|
|
}
|
|
}
|
|
|
|
// [D] [T]
|
|
void InitFelonyData(FELONY_DATA *pFelonyData)
|
|
{
|
|
InitFelonyDelayArray(pFelonyData->occurrenceDelay, initialOccurrenceDelay, numberOf(initialOccurrenceDelay));
|
|
InitFelonyDelayArray(pFelonyData->reoccurrenceDelay, initialReccurrenceDelay, numberOf(initialOccurrenceDelay));
|
|
|
|
memcpy((u_char*)&pFelonyData->value, (u_char*)&initialFelonyValue, sizeof(initialFelonyValue));
|
|
}
|
|
|
|
// [D] [T]
|
|
int GetCarHeading(int direction)
|
|
{
|
|
return (direction + 0x200U & 0xfff) >> 10;
|
|
}
|
|
|
|
// [D] [T]
|
|
char GetCarDirectionOfTravel(CAR_DATA *cp)
|
|
{
|
|
int direction;
|
|
|
|
direction = GetCarHeading(cp->hd.direction);;
|
|
|
|
if (cp->hd.wheel_speed < 0)
|
|
direction = direction + 2 & 3;
|
|
|
|
return direction;
|
|
}
|
|
|
|
// [D] [T]
|
|
void NoteFelony(FELONY_DATA *pFelonyData, char type, short scale)
|
|
{
|
|
int felonyTooLowForRoadblocks;
|
|
char rnd; // $s1
|
|
int dir; // $a3
|
|
short *felony;
|
|
int phrase;
|
|
int additionalFelonyPoints;
|
|
|
|
if (player[0].playerCarId < 0)
|
|
felony = &pedestrianFelony;
|
|
else
|
|
felony = &car_data[player[0].playerCarId].felonyRating;
|
|
|
|
felonyTooLowForRoadblocks = *felony;
|
|
|
|
if (pFelonyData->occurrenceDelay[type].current < pFelonyData->occurrenceDelay[type].maximum)
|
|
return;
|
|
|
|
#ifdef FELONY_DEBUG
|
|
switch (type)
|
|
{
|
|
case 1:
|
|
SetPlayerMessage(0, "Scaring pedestrians", 0, 1);
|
|
break;
|
|
case 2:
|
|
SetPlayerMessage(0, "Speeding", 0, 1);
|
|
break;
|
|
case 3:
|
|
SetPlayerMessage(0, "Red light crossing", 0, 1);
|
|
break;
|
|
case 4:
|
|
SetPlayerMessage(0, "Collision with another vehicle", 0, 1);
|
|
break;
|
|
case 5:
|
|
SetPlayerMessage(0, "Collision with cop", 0, 1);
|
|
break;
|
|
case 6:
|
|
SetPlayerMessage(0, "Collision with building", 0, 1);
|
|
break;
|
|
case 7:
|
|
SetPlayerMessage(0, "Damaging propery", 0, 1);
|
|
break;
|
|
case 8:
|
|
SetPlayerMessage(0, "Wrong way", 0, 1);
|
|
break;
|
|
case 9:
|
|
SetPlayerMessage(0, "Driving without lights", 0, 1);
|
|
break;
|
|
case 10:
|
|
SetPlayerMessage(0, "Reckless driving", 0, 1);
|
|
break;
|
|
case 11:
|
|
SetPlayerMessage(0, "Stealing cop car", 0, 1);
|
|
break;
|
|
}
|
|
#endif
|
|
|
|
if (CopsCanSeePlayer == 0 && (type != 11))
|
|
return;
|
|
|
|
if (pFelonyData->reoccurrenceDelay[type].current != 0)
|
|
return;
|
|
|
|
pFelonyData->reoccurrenceDelay[type].current = pFelonyData->reoccurrenceDelay[type].maximum;
|
|
|
|
if (*felony <= FELONY_PURSUIT_MIN_VALUE)
|
|
additionalFelonyPoints = pFelonyData->value[type].placid;
|
|
else
|
|
additionalFelonyPoints = pFelonyData->value[type].angry * pFelonyData->pursuitFelonyScale >> 0xc;
|
|
|
|
*felony += (additionalFelonyPoints * scale >> 12);
|
|
|
|
if (*felony > FELONY_MAX_VALUE)
|
|
*felony = FELONY_MAX_VALUE;
|
|
|
|
// KILL PEDESTRIAN FELONY HERE
|
|
if (player[0].playerType == 2)
|
|
*felony = 0;
|
|
|
|
if (first_offence == 0 && numActiveCops)
|
|
{
|
|
// say something..
|
|
rnd = Random2(1);
|
|
dir = GetCarDirectionOfTravel(&car_data[player[0].playerCarId]);
|
|
|
|
switch (type)
|
|
{
|
|
case 1:
|
|
case 5:
|
|
case 6:
|
|
case 7:
|
|
case 11:
|
|
break;
|
|
case 3:
|
|
if ((rnd & 3) != 0)
|
|
break;
|
|
|
|
CopSay(5, 0);
|
|
break;
|
|
case 4:
|
|
if ((rnd % 3) & 0xff != 0)
|
|
break;
|
|
|
|
CopSay((rnd & 1) + 7, 0);
|
|
|
|
break;
|
|
default:
|
|
if ((rnd % 17) & 0xFF == 0)
|
|
{
|
|
if (MaxPlayerDamage[0] * 3 / 4 < car_data[player[0].playerCarId].totalDamage)
|
|
phrase = rnd % 4;
|
|
else
|
|
phrase = rnd % 3;
|
|
|
|
if (last_cop_phrase != phrase && 0 < TimeSinceLastSpeech)
|
|
{
|
|
if (phrase < 3)
|
|
CopSay(phrase + 15, dir);
|
|
else
|
|
CopSay(6, 0);
|
|
|
|
last_cop_phrase = phrase;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (felonyTooLowForRoadblocks <= FELONY_ROADBLOCK_MIN_VALUE)
|
|
{
|
|
if (*felony > FELONY_ROADBLOCK_MIN_VALUE)
|
|
{
|
|
roadblockCount = roadblockDelayDiff[gCopDifficultyLevel] + (Random2(0) & 0xff);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// [D] [T]
|
|
void AdjustFelony(FELONY_DATA *pFelonyData)
|
|
{
|
|
FELONY_DELAY *pFelonyDelay;
|
|
short *felony;
|
|
|
|
if (player[0].playerCarId < 0)
|
|
felony = &pedestrianFelony;
|
|
else
|
|
felony = &car_data[player[0].playerCarId].felonyRating;
|
|
|
|
if (*felony != 0 && *felony <= FELONY_PURSUIT_MIN_VALUE)
|
|
{
|
|
if (FelonyDecreaseTimer++ == FelonyDecreaseTime)
|
|
{
|
|
(*felony)--;
|
|
|
|
FelonyDecreaseTimer = 0;
|
|
}
|
|
}
|
|
else if (CopsCanSeePlayer)
|
|
{
|
|
if (*felony > FELONY_PURSUIT_MIN_VALUE && FelonyIncreaseTimer++ == FelonyIncreaseTime)
|
|
{
|
|
(*felony)++;
|
|
|
|
if (*felony > FELONY_MAX_VALUE)
|
|
*felony = FELONY_MAX_VALUE;
|
|
|
|
FelonyIncreaseTimer = 0;
|
|
}
|
|
}
|
|
|
|
pFelonyDelay = pFelonyData->reoccurrenceDelay;
|
|
|
|
while (pFelonyDelay <= &pFelonyData->reoccurrenceDelay[11])
|
|
{
|
|
if (pFelonyDelay->current != 0)
|
|
pFelonyDelay->current--;
|
|
|
|
pFelonyDelay++;
|
|
}
|
|
}
|
|
|
|
short playerLastRoad = 0;
|
|
|
|
// [D] [T]
|
|
void CheckPlayerMiscFelonies(void)
|
|
{
|
|
int i;
|
|
bool goingWrongWay;
|
|
int surfInd;
|
|
int maxSpeed;
|
|
int limit;
|
|
int exitId;
|
|
int _exitId;
|
|
VECTOR *carPos;
|
|
DRIVER2_ROAD_INFO roadInfo;
|
|
DRIVER2_JUNCTION *jn;
|
|
CAR_DATA* cp;
|
|
|
|
// Do not register felony if player does not have a car
|
|
if (player[0].playerType == 2 ||
|
|
player[0].playerCarId < 0 ||
|
|
FelonyBar.active == 0)
|
|
return;
|
|
|
|
cp = &car_data[player[0].playerCarId];
|
|
carPos = (VECTOR *)cp->hd.where.t;
|
|
|
|
surfInd = GetSurfaceIndex(carPos);
|
|
|
|
// check junctions
|
|
if (IS_JUNCTION_SURFACE(surfInd))
|
|
{
|
|
jn = GET_JUNCTION(surfInd);
|
|
|
|
if( (IS_CURVED_SURFACE(playerLastRoad) || IS_STRAIGHT_SURFACE(playerLastRoad)) && (jn->flags & 0x1))
|
|
{
|
|
exitId = 0;
|
|
i = 0;
|
|
while (i < 4)
|
|
{
|
|
if (jn->ExitIdx[i] == playerLastRoad)
|
|
{
|
|
exitId = i;
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
// Run a red light!
|
|
if (junctionLightsPhase[exitId & 1] == 1)
|
|
NoteFelony(&felonyData, 3, 4096);
|
|
}
|
|
}
|
|
|
|
playerLastRoad = surfInd;
|
|
goingWrongWay = false;
|
|
|
|
if(GetSurfaceRoadInfo(&roadInfo, surfInd))
|
|
{
|
|
int lane;
|
|
int crd;
|
|
|
|
lane = GetLaneByPositionOnRoad(&roadInfo, carPos);
|
|
|
|
if(roadInfo.straight)
|
|
crd = (roadInfo.straight->angle - cp->hd.direction) + 1024U >> 0xb & 1;
|
|
else
|
|
crd = NotTravellingAlongCurve(carPos->vx, carPos->vz, cp->hd.direction, roadInfo.curve);
|
|
|
|
// check if on correct lane
|
|
if (ROAD_IS_AI_LANE(&roadInfo, lane))
|
|
{
|
|
if (ROAD_LANE_DIR(&roadInfo, lane) == 0)
|
|
{
|
|
if (crd == 1)
|
|
goingWrongWay = true;
|
|
}
|
|
else
|
|
{
|
|
if (crd == 0)
|
|
goingWrongWay = true;
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
printInfo("ROAD %d lane: %d / %d, (%d). AI drive: %d, flg: %d%d%d, dir: %d, spd: %d (wrong way: %d)\n",
|
|
roadInfo.surfId,
|
|
lane + 1,
|
|
ROAD_WIDTH_IN_LANES(&roadInfo), // lane count. * 2 for both sides as roads are symmetric
|
|
IS_NARROW_ROAD(&roadInfo),
|
|
ROAD_IS_AI_LANE(&roadInfo, lane), // lane AI driveable flag
|
|
(roadInfo.NumLanes & 0x20) > 0, // flag 0 - first lane?
|
|
(roadInfo.NumLanes & 0x40) > 0, // flag 1 - leftmost park
|
|
(roadInfo.NumLanes & 0x80) > 0, // flag 2 - rightmost park
|
|
ROAD_LANE_DIRECTION_BIT(&roadInfo, lane), // direction bit
|
|
ROAD_SPEED_LIMIT(&roadInfo), // speed limit id
|
|
goingWrongWay);
|
|
#endif
|
|
|
|
// get road speed limit
|
|
maxSpeed = speedLimits[ROAD_SPEED_LIMIT(&roadInfo)];
|
|
}
|
|
else
|
|
{
|
|
maxSpeed = speedLimits[2];
|
|
}
|
|
|
|
// wrong way
|
|
if (goingWrongWay)
|
|
felonyData.occurrenceDelay[8].current++;
|
|
else
|
|
felonyData.occurrenceDelay[8].current = 0;
|
|
|
|
NoteFelony(&felonyData, 8, 4096);
|
|
|
|
// if lights are off (broken)
|
|
if (gTimeOfDay == 3 && cp->ap.damage[0] > 1000 && cp->ap.damage[1] > 1000)
|
|
NoteFelony(&felonyData, 9, 4096);
|
|
|
|
// reckless driving.
|
|
// for that checking if rear wheels are sliding
|
|
if (cp->wheelspin == 0)
|
|
{
|
|
if (ABS(cp->hd.rear_vel) > 11100)
|
|
felonyData.occurrenceDelay[10].current++;
|
|
else
|
|
felonyData.occurrenceDelay[10].current = 0;
|
|
}
|
|
else
|
|
{
|
|
felonyData.occurrenceDelay[10].current++;
|
|
}
|
|
|
|
NoteFelony(&felonyData, 10, 4096);
|
|
|
|
// check the speed limit
|
|
if (speedLimits[2] == maxSpeed)
|
|
limit = (maxSpeed * 19) >> 4;
|
|
else
|
|
limit = (maxSpeed * 3) >> 1;
|
|
|
|
if (FIXEDH(cp->hd.wheel_speed) > limit)
|
|
NoteFelony(&felonyData, 2, 4096);
|
|
}
|
|
|
|
// [D] [T]
|
|
void InitFelonySystem(void)
|
|
{
|
|
FelonyIncreaseTime = 31;
|
|
FelonyDecreaseTime = 31;
|
|
FelonyIncreaseTimer = 0;
|
|
FelonyDecreaseTimer = 0;
|
|
|
|
InitFelonyData(&felonyData);
|
|
}
|
|
|
|
// enable when debugging whacky StoreCarPosition
|
|
// #define LEADAI_EASY
|
|
|
|
// [D] [T]
|
|
void CarHitByPlayer(CAR_DATA *victim, int howHard)
|
|
{
|
|
char type;
|
|
|
|
_CutRec_CheckInvalidatePing(victim->id, howHard);
|
|
|
|
#ifdef LEADAI_EASY
|
|
if (victim->controlType == CONTROL_TYPE_LEAD_AI)
|
|
victim->totalDamage = 0xffff;
|
|
#endif
|
|
|
|
if (howHard > 0 && victim->controlType != CONTROL_TYPE_PURSUER_AI)
|
|
{
|
|
if ((victim->controlFlags & 1) == 0)
|
|
{
|
|
if (howHard < 32)
|
|
{
|
|
NoteFelony(&felonyData, 4, (howHard << 0x17) >> 0x10);
|
|
return;
|
|
}
|
|
|
|
type = 4;
|
|
}
|
|
else
|
|
{
|
|
if (howHard < 16)
|
|
{
|
|
NoteFelony(&felonyData, 5, (howHard << 0x18) >> 0x10);
|
|
return;
|
|
}
|
|
|
|
type = 5;
|
|
}
|
|
|
|
NoteFelony(&felonyData, type, 4096);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|