Re3/src/control/Darkel.cpp

372 lines
12 KiB
C++
Raw Normal View History

#include "common.h"
#include "patcher.h"
2019-07-04 16:31:21 -04:00
#include "main.h"
#include "Darkel.h"
2019-10-05 09:44:03 -04:00
#include "PlayerPed.h"
2019-07-04 16:31:21 -04:00
#include "Timer.h"
#include "DMAudio.h"
#include "Population.h"
#include "Weapon.h"
#include "World.h"
#include "Stats.h"
#include "Font.h"
#include "Text.h"
2019-07-04 16:31:21 -04:00
int32 &CDarkel::TimeLimit = *(int32*)0x885BAC;
int32 &CDarkel::PreviousTime = *(int32*)0x885B00;
int32 &CDarkel::TimeOfFrenzyStart = *(int32*)0x9430D8;
int32 &CDarkel::WeaponType = *(int32*)0x9430F0;
int32 &CDarkel::AmmoInterruptedWeapon = *(int32*)0x8E29C8;
int32 &CDarkel::KillsNeeded = *(int32*)0x8F1AB8;
int8 &CDarkel::InterruptedWeapon = *(int8*)0x95CD60;
2019-10-05 09:44:03 -04:00
/*
* bStandardSoundAndMessages is a completely beta thing,
* makes game handle sounds & messages instead of SCM (just like in GTA2)
* but it's never been used in the game. Has unused sliding text when frenzy completed etc.
*/
2019-07-04 16:31:21 -04:00
int8 &CDarkel::bStandardSoundAndMessages = *(int8*)0x95CDB6;
int8 &CDarkel::bNeedHeadShot = *(int8*)0x95CDCA;
int8 &CDarkel::bProperKillFrenzy = *(int8*)0x95CD98;
eKillFrenzyStatus &CDarkel::Status = *(eKillFrenzyStatus*)0x95CCB4;
2019-10-05 09:44:03 -04:00
uint16 (&CDarkel::RegisteredKills)[NUMDEFAULTMODELS] = *(uint16(*)[NUMDEFAULTMODELS]) * (uintptr*)0x6EDBE0;
2019-07-04 16:31:21 -04:00
int32 &CDarkel::ModelToKill = *(int32*)0x8F2C78;
int32 &CDarkel::ModelToKill2 = *(int32*)0x885B40;
int32 &CDarkel::ModelToKill3 = *(int32*)0x885B3C;
int32 &CDarkel::ModelToKill4 = *(int32*)0x885B34;
wchar *CDarkel::pStartMessage = (wchar*)0x8F2C08;
2019-10-05 09:44:03 -04:00
uint8
CDarkel::CalcFade(uint32 time, uint32 start, uint32 end)
{
2019-07-07 03:13:04 -04:00
if (time >= start && time <= end) {
if (time >= start + 500) {
if (time <= end - 500)
2019-07-07 14:59:49 -04:00
return 255;
2019-07-04 16:31:21 -04:00
else
2019-07-07 03:13:04 -04:00
return 255 * (end - time) / 500;
2019-10-05 09:44:03 -04:00
} else
2019-07-07 03:13:04 -04:00
return 255 * (time - start) / 500;
2019-10-05 09:44:03 -04:00
} else
2019-07-04 16:31:21 -04:00
return 0;
}
2019-10-05 09:44:03 -04:00
// Screen positions taken from VC
void
CDarkel::DrawMessages()
2019-07-04 16:31:21 -04:00
{
switch (Status) {
2019-10-05 09:44:03 -04:00
case KILLFRENZY_ONGOING:
{
CFont::SetJustifyOff();
CFont::SetBackgroundOff();
CFont::SetCentreSize(SCREEN_SCALE_FROM_RIGHT(30.0f));
CFont::SetCentreOn();
CFont::SetPropOn();
uint32 timePassedSinceStart = CTimer::GetTimeInMilliseconds() - CDarkel::TimeOfFrenzyStart;
if (CDarkel::bStandardSoundAndMessages) {
if (timePassedSinceStart >= 3000 && timePassedSinceStart < 11000) {
CFont::SetScale(SCREEN_SCALE_X(1.3f), SCREEN_SCALE_Y(1.3f));
CFont::SetJustifyOff();
CFont::SetColor(CRGBA(255, 255, 128, CalcFade(timePassedSinceStart, 3000, 11000)));
CFont::SetFontStyle(FONT_BANK);
if (pStartMessage) {
CFont::PrintString(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, pStartMessage);
}
}
} else {
if (timePassedSinceStart < 8000) {
CFont::SetScale(SCREEN_SCALE_X(1.3f), SCREEN_SCALE_Y(1.3f));
CFont::SetJustifyOff();
CFont::SetColor(CRGBA(255, 255, 128, CalcFade(timePassedSinceStart, 0, 8000)));
CFont::SetFontStyle(FONT_BANK);
if (pStartMessage) {
CFont::PrintString(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, pStartMessage);
}
}
}
CFont::SetScale(SCREEN_SCALE_X(0.75f), SCREEN_SCALE_Y(1.5f));
CFont::SetCentreOff();
CFont::SetRightJustifyOn();
CFont::SetFontStyle(FONT_HEADING);
if (CDarkel::TimeLimit >= 0) {
uint32 timeLeft = CDarkel::TimeLimit - (CTimer::GetTimeInMilliseconds() - CDarkel::TimeOfFrenzyStart);
sprintf(gString, "%d:%02d", timeLeft / 60000, timeLeft % 60000 / 1000);
AsciiToUnicode(gString, gUString);
if (timeLeft > 4000 || CTimer::GetFrameCounter() & 1) {
CFont::SetColor(CRGBA(0, 0, 0, 255));
CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(35.0f), SCREEN_SCALE_Y(109.0f), gUString);
CFont::SetColor(CRGBA(150, 100, 255, 255));
CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(34.0f), SCREEN_SCALE_Y(108.0f), gUString);
}
}
sprintf(gString, "%d", (CDarkel::KillsNeeded >= 0 ? CDarkel::KillsNeeded : 0));
2019-07-04 16:31:21 -04:00
AsciiToUnicode(gString, gUString);
CFont::SetColor(CRGBA(0, 0, 0, 255));
2019-10-05 09:44:03 -04:00
CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(35.0f), SCREEN_SCALE_Y(144.0f), gUString);
CFont::SetColor(CRGBA(255, 128, 128, 255));
CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(34.0f), SCREEN_SCALE_Y(143.0f), gUString);
break;
2019-07-04 16:31:21 -04:00
}
2019-10-05 09:44:03 -04:00
case KILLFRENZY_PASSED:
{
if (CDarkel::bStandardSoundAndMessages) {
uint32 timePassedSinceStart = CTimer::GetTimeInMilliseconds() - CDarkel::TimeOfFrenzyStart;
if (CTimer::GetTimeInMilliseconds() - CDarkel::TimeOfFrenzyStart < 5000) {
CFont::SetBackgroundOff();
CFont::SetCentreSize(SCREEN_SCALE_FROM_RIGHT(20.0f));
CFont::SetCentreOn();
CFont::SetScale(SCREEN_SCALE_X(1.5f), SCREEN_SCALE_Y(1.5f));
CFont::SetJustifyOff();
CFont::SetColor(CRGBA(128, 255, 128, CalcFade(timePassedSinceStart, 0, 5000)));
CFont::SetFontStyle(FONT_BANK);
int y = SCREEN_HEIGHT / 2 + SCREEN_SCALE_Y(25.0f - timePassedSinceStart * 0.01f);
CFont::PrintString(SCREEN_WIDTH / 2, y, TheText.Get("KF_3"));
}
}
break;
}
default:
break;
2019-07-04 16:31:21 -04:00
}
}
2019-10-05 09:44:03 -04:00
void
CDarkel::Init()
2019-07-04 16:31:21 -04:00
{
2019-07-07 03:13:04 -04:00
Status = KILLFRENZY_NONE;
2019-07-04 16:31:21 -04:00
}
2019-10-05 09:44:03 -04:00
uint16
CDarkel::QueryModelsKilledByPlayer(int32 modelId)
2019-07-04 16:31:21 -04:00
{
return RegisteredKills[modelId];
}
2019-06-14 19:34:19 -04:00
2019-10-05 09:44:03 -04:00
bool
CDarkel::FrenzyOnGoing()
{
2019-07-04 16:31:21 -04:00
return Status == KILLFRENZY_ONGOING;
}
2019-10-05 09:44:03 -04:00
uint16
CDarkel::ReadStatus()
2019-07-04 16:31:21 -04:00
{
return Status;
}
2019-07-07 03:13:04 -04:00
#if 1
2019-07-09 12:50:35 -04:00
WRAPPER void CDarkel::RegisterCarBlownUpByPlayer(CVehicle *vehicle) { EAXJMP(0x421070); }
2019-07-07 03:13:04 -04:00
#else
2019-07-09 12:50:35 -04:00
int32 CDarkel::RegisterCarBlownUpByPlayer(CVehicle *vehicle)
2019-07-04 16:31:21 -04:00
{
return 0;
}
2019-07-07 03:13:04 -04:00
#endif
2019-07-04 16:31:21 -04:00
2019-07-07 03:13:04 -04:00
#if 1
2019-07-09 12:50:35 -04:00
WRAPPER void CDarkel::RegisterKillByPlayer(CPed *victim, eWeaponType weapontype, bool headshot) { EAXJMP(0x420F60); }
2019-07-07 03:13:04 -04:00
#else
2019-07-09 12:50:35 -04:00
void CDarkel::RegisterKillByPlayer(CPed *victim, eWeaponType weapontype, bool headshot)
2019-07-04 16:31:21 -04:00
{
}
2019-07-07 03:13:04 -04:00
#endif
2019-07-04 16:31:21 -04:00
2019-10-05 09:44:03 -04:00
void
CDarkel::RegisterKillNotByPlayer(CPed* victim, eWeaponType weapontype)
2019-07-04 16:31:21 -04:00
{
2019-10-05 09:44:03 -04:00
++CStats::PeopleKilledByOthers;
2019-07-04 16:31:21 -04:00
}
2019-10-05 09:44:03 -04:00
void
CDarkel::ResetModelsKilledByPlayer()
2019-07-04 16:31:21 -04:00
{
2019-10-05 09:44:03 -04:00
for (int i = 0; i < NUMDEFAULTMODELS; i++)
2019-07-07 03:13:04 -04:00
RegisteredKills[i] = 0;
2019-07-04 16:31:21 -04:00
}
2019-07-07 03:13:04 -04:00
#if 0
WRAPPER void CDarkel::ResetOnPlayerDeath() { EAXJMP(0x420E70); }
#else
2019-10-05 09:44:03 -04:00
void
CDarkel::ResetOnPlayerDeath()
2019-07-04 16:31:21 -04:00
{
2019-07-07 03:13:04 -04:00
if (Status != KILLFRENZY_ONGOING)
return;
2019-07-04 16:31:21 -04:00
2019-07-07 03:13:04 -04:00
CPopulation::m_AllRandomPedsThisType = -1;
Status = KILLFRENZY_FAILED;
TimeOfFrenzyStart = CTimer::GetTimeInMilliseconds();
2019-07-04 16:31:21 -04:00
2019-10-05 09:44:03 -04:00
eWeaponType fixedWeapon;
2019-07-07 03:13:04 -04:00
if (WeaponType == WEAPONTYPE_UZI_DRIVEBY)
2019-10-05 09:44:03 -04:00
fixedWeapon = WEAPONTYPE_UZI;
else
fixedWeapon = (eWeaponType)WeaponType;
2019-07-07 03:13:04 -04:00
2019-10-05 09:44:03 -04:00
CPlayerPed *player = FindPlayerPed();
if (fixedWeapon < WEAPONTYPE_TOTALWEAPONS) {
player->m_nSelectedWepSlot = InterruptedWeapon;
player->GetWeapon(player->GetWeaponSlot(fixedWeapon)).m_nAmmoTotal = CDarkel::AmmoInterruptedWeapon;
2019-07-07 03:13:04 -04:00
}
if (FindPlayerVehicle()) {
2019-10-05 09:44:03 -04:00
player->RemoveWeaponModel(CWeaponInfo::GetWeaponInfo(player->GetWeapon()->m_eWeaponType)->m_nModelId);
player->m_currentWeapon = player->m_nSelectedWepSlot;
player->MakeChangesForNewWeapon(player->m_currentWeapon);
2019-07-04 16:31:21 -04:00
}
}
2019-07-07 03:13:04 -04:00
#endif
2019-07-04 16:31:21 -04:00
#if 0
2019-10-05 09:44:03 -04:00
WRAPPER void CDarkel::StartFrenzy(eWeaponType weaponType, int32 time, uint16 kill, int32 modelId0, wchar *text, int32 modelId2, int32 modelId3, int32 modelId4, bool standardSound, bool needHeadShot) { EAXJMP(0x4210E0); }
2019-07-04 16:31:21 -04:00
#else
2019-10-05 09:44:03 -04:00
void
CDarkel::StartFrenzy(eWeaponType weaponType, int32 time, uint16 kill, int32 modelId0, wchar *text, int32 modelId2, int32 modelId3, int32 modelId4, bool standardSound, bool needHeadShot)
2019-07-04 16:31:21 -04:00
{
2019-10-05 09:44:03 -04:00
eWeaponType fixedWeapon;
2019-07-04 16:31:21 -04:00
if (weaponType == WEAPONTYPE_UZI_DRIVEBY)
2019-10-05 09:44:03 -04:00
fixedWeapon = WEAPONTYPE_UZI;
else
fixedWeapon = weaponType;
2019-07-04 16:31:21 -04:00
WeaponType = weaponType;
Status = KILLFRENZY_ONGOING;
KillsNeeded = kill;
ModelToKill = modelId0;
ModelToKill2 = modelId2;
ModelToKill3 = modelId3;
ModelToKill4 = modelId4;
pStartMessage = text;
if (text == TheText.Get("PAGE_00")) {
CDarkel::bProperKillFrenzy = 1;
CDarkel::pStartMessage = 0;
2019-10-05 09:44:03 -04:00
} else
2019-07-04 16:31:21 -04:00
bProperKillFrenzy = 0;
bStandardSoundAndMessages = standardSound;
bNeedHeadShot = needHeadShot;
TimeOfFrenzyStart = CTimer::GetTimeInMilliseconds();
TimeLimit = time;
PreviousTime = time / 1000;
2019-10-05 09:44:03 -04:00
CPlayerPed *player = FindPlayerPed();
if (fixedWeapon < WEAPONTYPE_TOTALWEAPONS) {
InterruptedWeapon = player->m_currentWeapon;
player->GiveWeapon(fixedWeapon, 0);
AmmoInterruptedWeapon = player->GetWeapon(player->GetWeaponSlot(fixedWeapon)).m_nAmmoTotal;
player->GiveWeapon(fixedWeapon, 30000);
player->m_nSelectedWepSlot = player->GetWeaponSlot(fixedWeapon);
player->MakeChangesForNewWeapon(player->m_nSelectedWepSlot);
2019-07-04 16:31:21 -04:00
if (FindPlayerVehicle()) {
2019-10-05 09:44:03 -04:00
player->m_currentWeapon = player->m_nSelectedWepSlot;
player->GetWeapon()->m_nAmmoInClip = min(player->GetWeapon()->m_nAmmoTotal, CWeaponInfo::GetWeaponInfo(player->GetWeapon()->m_eWeaponType)->m_nAmountofAmmunition);
player->ClearWeaponTarget();
2019-07-04 16:31:21 -04:00
}
}
if (CDarkel::bStandardSoundAndMessages)
DMAudio.PlayFrontEndSound(SOUND_RAMPAGE_START, 0);
}
#endif
2019-10-05 09:44:03 -04:00
void
CDarkel::Update()
2019-07-04 16:31:21 -04:00
{
2019-07-07 03:13:04 -04:00
if (Status != KILLFRENZY_ONGOING)
return;
2019-07-04 16:31:21 -04:00
2019-07-07 03:13:04 -04:00
int32 FrameTime = TimeLimit - (CTimer::GetTimeInMilliseconds() - TimeOfFrenzyStart);
if ((TimeLimit - (CTimer::GetTimeInMilliseconds() - TimeOfFrenzyStart)) > 0 || TimeLimit < 0) {
2019-10-05 09:44:03 -04:00
2019-07-07 03:13:04 -04:00
DMAudio.PlayFrontEndSound(SOUND_RAMPAGE_ONGOING, FrameTime);
2019-07-04 16:31:21 -04:00
2019-07-07 03:13:04 -04:00
int32 PrevTime = FrameTime / 1000;
2019-07-04 16:31:21 -04:00
2019-07-07 03:13:04 -04:00
if (PrevTime != PreviousTime) {
if (PreviousTime < 12)
DMAudio.PlayFrontEndSound(SOUND_CLOCK_TICK, PrevTime);
PreviousTime = PrevTime;
}
2019-07-04 16:31:21 -04:00
2019-10-05 09:44:03 -04:00
} else {
2019-07-07 03:13:04 -04:00
CPopulation::m_AllRandomPedsThisType = -1;
Status = KILLFRENZY_FAILED;
TimeOfFrenzyStart = CTimer::GetTimeInMilliseconds();
2019-10-05 09:44:03 -04:00
eWeaponType fixedWeapon;
2019-07-07 03:13:04 -04:00
if (WeaponType == WEAPONTYPE_UZI_DRIVEBY)
2019-10-05 09:44:03 -04:00
fixedWeapon = WEAPONTYPE_UZI;
else
fixedWeapon = (eWeaponType)WeaponType;
2019-07-07 03:13:04 -04:00
2019-10-05 09:44:03 -04:00
CPlayerPed *player = FindPlayerPed();
if (fixedWeapon < WEAPONTYPE_TOTALWEAPONS) {
player->m_nSelectedWepSlot = InterruptedWeapon;
player->GetWeapon(player->GetWeaponSlot(fixedWeapon)).m_nAmmoTotal = CDarkel::AmmoInterruptedWeapon;
2019-07-04 16:31:21 -04:00
}
2019-07-07 03:13:04 -04:00
if (FindPlayerVehicle()) {
2019-10-05 09:44:03 -04:00
player->RemoveWeaponModel(CWeaponInfo::GetWeaponInfo(player->GetWeapon()->m_eWeaponType)->m_nModelId);
player->m_currentWeapon = player->m_nSelectedWepSlot;
player->MakeChangesForNewWeapon(player->m_currentWeapon);
2019-07-04 16:31:21 -04:00
}
2019-07-07 03:13:04 -04:00
if (bStandardSoundAndMessages)
DMAudio.PlayFrontEndSound(SOUND_RAMPAGE_FAILED, 0);
}
2019-07-04 16:31:21 -04:00
2019-07-07 03:13:04 -04:00
if (KillsNeeded <= 0) {
CPopulation::m_AllRandomPedsThisType = -1;
Status = KILLFRENZY_PASSED;
2019-07-04 16:31:21 -04:00
2019-07-07 03:13:04 -04:00
if (bProperKillFrenzy)
CStats::AnotherKillFrenzyPassed();
2019-07-04 16:31:21 -04:00
2019-07-07 03:13:04 -04:00
TimeOfFrenzyStart = CTimer::GetTimeInMilliseconds();
2019-07-04 16:31:21 -04:00
2019-07-12 12:01:22 -04:00
FindPlayerPed()->m_pWanted->SetWantedLevel(0);
2019-07-04 16:31:21 -04:00
2019-10-05 09:44:03 -04:00
eWeaponType fixedWeapon;
2019-07-07 03:13:04 -04:00
if (WeaponType == WEAPONTYPE_UZI_DRIVEBY)
2019-10-05 09:44:03 -04:00
fixedWeapon = WEAPONTYPE_UZI;
else
fixedWeapon = (eWeaponType)WeaponType;
2019-07-04 16:31:21 -04:00
2019-10-05 09:44:03 -04:00
CPlayerPed* player = FindPlayerPed();
if (fixedWeapon < WEAPONTYPE_TOTALWEAPONS) {
player->m_nSelectedWepSlot = InterruptedWeapon;
player->GetWeapon(player->GetWeaponSlot(fixedWeapon)).m_nAmmoTotal = CDarkel::AmmoInterruptedWeapon;
2019-07-07 03:13:04 -04:00
}
2019-07-04 16:31:21 -04:00
2019-07-07 03:13:04 -04:00
if (FindPlayerVehicle()) {
2019-10-05 09:44:03 -04:00
player->RemoveWeaponModel(CWeaponInfo::GetWeaponInfo(player->GetWeapon()->m_eWeaponType)->m_nModelId);
player->m_currentWeapon = player->m_nSelectedWepSlot;
player->MakeChangesForNewWeapon(player->m_currentWeapon);
2019-07-04 16:31:21 -04:00
}
2019-07-07 03:13:04 -04:00
if (bStandardSoundAndMessages)
DMAudio.PlayFrontEndSound(SOUND_RAMPAGE_PASSED, 0);
2019-07-04 16:31:21 -04:00
}
}
STARTPATCHES
2019-10-05 09:44:03 -04:00
InjectHook(0x421380, CDarkel::CalcFade, PATCH_JUMP);
2019-07-04 16:31:21 -04:00
InjectHook(0x420650, CDarkel::Init, PATCH_JUMP);
2019-10-05 09:44:03 -04:00
InjectHook(0x420660, CDarkel::Update, PATCH_JUMP);
InjectHook(0x420E60, CDarkel::FrenzyOnGoing, PATCH_JUMP);
2019-07-04 16:31:21 -04:00
InjectHook(0x420E50, CDarkel::ReadStatus, PATCH_JUMP);
InjectHook(0x420E70, CDarkel::ResetOnPlayerDeath, PATCH_JUMP);
InjectHook(0x4210E0, CDarkel::StartFrenzy, PATCH_JUMP);
2019-10-05 09:44:03 -04:00
InjectHook(0x421370, CDarkel::QueryModelsKilledByPlayer, PATCH_JUMP);
InjectHook(0x421060, CDarkel::RegisterKillNotByPlayer, PATCH_JUMP);
InjectHook(0x421310, CDarkel::ResetModelsKilledByPlayer, PATCH_JUMP);
InjectHook(0x420920, CDarkel::DrawMessages, PATCH_JUMP);
//InjectHook(0x421070, CDarkel::RegisterCarBlownUpByPlayer, PATCH_JUMP);
//InjectHook(0x420F60, CDarkel::RegisterKillByPlayer, PATCH_JUMP);
2019-07-04 16:31:21 -04:00
ENDPATCHES