diff --git a/src/control/Population.cpp b/src/control/Population.cpp index 1ae5962d..72de300d 100644 --- a/src/control/Population.cpp +++ b/src/control/Population.cpp @@ -7,6 +7,7 @@ PedGroup *CPopulation::ms_pPedGroups = (PedGroup*)0x6E9248; bool &CPopulation::ms_bGivePedsWeapons = *(bool*)0x95CCF6; int32 &CPopulation::m_AllRandomPedsThisType = *(int32*)0x5FA570; float &CPopulation::PedDensityMultiplier = *(float*)0x5FA56C; +uint32 &CPopulation::ms_nTotalMissionPeds = *(uint32*)0x8F5F70; WRAPPER void CPopulation::UpdatePedCount(uint32, bool) { EAXJMP(0x4F5A60); } WRAPPER void CPopulation::DealWithZoneChange(eLevelName oldLevel, eLevelName newLevel, bool) { EAXJMP(0x4F6200); } diff --git a/src/control/Population.h b/src/control/Population.h index 6bd2e3ae..e24ace3a 100644 --- a/src/control/Population.h +++ b/src/control/Population.h @@ -15,6 +15,7 @@ public: static bool &ms_bGivePedsWeapons; static int32 &m_AllRandomPedsThisType; static float &PedDensityMultiplier; + static uint32 &ms_nTotalMissionPeds; static void UpdatePedCount(uint32, bool); static void DealWithZoneChange(eLevelName oldLevel, eLevelName newLevel, bool); diff --git a/src/control/Script.cpp b/src/control/Script.cpp index f3a18195..4ce886c3 100644 --- a/src/control/Script.cpp +++ b/src/control/Script.cpp @@ -4,10 +4,15 @@ #include "Script.h" #include "ScriptCommands.h" +#include "Boat.h" #include "Camera.h" #include "CarCtrl.h" +#include "CivilianPed.h" +#include "CopPed.h" #include "DMAudio.h" +#include "EmergencyPed.h" #include "FileMgr.h" +#include "General.h" #include "Hud.h" #include "Messages.h" #include "ModelIndices.h" @@ -21,6 +26,7 @@ #include "User.h" #include "Weather.h" #include "World.h" +#include "Zones.h" uint8 (&CTheScripts::ScriptSpace)[SIZE_SCRIPT_SPACE] = *(uint8(*)[SIZE_SCRIPT_SPACE])*(uintptr*)0x74B248; CRunningScript(&CTheScripts::ScriptsArray)[MAX_NUM_SCRIPTS] = *(CRunningScript(*)[MAX_NUM_SCRIPTS])*(uintptr*)0x6F5C08; @@ -1342,6 +1348,7 @@ int8 CRunningScript::ProcessCommandsFrom0To99(int32 command) *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) -= *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); return 0; default: + assert(0); break; } return -1; @@ -1374,7 +1381,468 @@ void CRunningScript::UpdateCompareFlag(bool flag) } -WRAPPER int8 CRunningScript::ProcessCommandsFrom100To199(int32 command) { EAXJMP(0x43AEA0); } +int8 CRunningScript::ProcessCommandsFrom100To199(int32 command) +{ + switch (command) { + case COMMAND_SUB_INT_LVAR_FROM_INT_VAR: + *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) -= *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + case COMMAND_SUB_INT_VAR_FROM_INT_LVAR: + *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) -= *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + case COMMAND_SUB_FLOAT_LVAR_FROM_FLOAT_VAR: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) -= *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + case COMMAND_SUB_FLOAT_VAR_FROM_FLOAT_LVAR: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) -= *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + case COMMAND_MULT_INT_VAR_BY_INT_VAR: + *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) *= *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + case COMMAND_MULT_INT_LVAR_BY_INT_VAR: + *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) *= *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + case COMMAND_MULT_INT_VAR_BY_INT_LVAR: + *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) *= *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + case COMMAND_MULT_INT_LVAR_BY_INT_LVAR: + *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) *= *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + case COMMAND_MULT_FLOAT_VAR_BY_FLOAT_VAR: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) *= *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + case COMMAND_MULT_FLOAT_LVAR_BY_FLOAT_VAR: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) *= *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + case COMMAND_MULT_FLOAT_VAR_BY_FLOAT_LVAR: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) *= *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + case COMMAND_MULT_FLOAT_LVAR_BY_FLOAT_LVAR: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) *= *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + case COMMAND_DIV_INT_VAR_BY_INT_VAR: + *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) /= *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + case COMMAND_DIV_INT_LVAR_BY_INT_VAR: + *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) /= *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + case COMMAND_DIV_INT_VAR_BY_INT_LVAR: + *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) /= *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + case COMMAND_DIV_INT_LVAR_BY_INT_LVAR: + *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) /= *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + case COMMAND_DIV_FLOAT_VAR_BY_FLOAT_VAR: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) /= *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + case COMMAND_DIV_FLOAT_LVAR_BY_FLOAT_VAR: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) /= *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + case COMMAND_DIV_FLOAT_VAR_BY_FLOAT_LVAR: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) /= *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + case COMMAND_DIV_FLOAT_LVAR_BY_FLOAT_LVAR: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) /= *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + case COMMAND_ADD_TIMED_VAL_TO_FLOAT_VAR: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + CollectParameters(&m_nIp, 1); + *(float*)ptr += CTimer::GetTimeStep() * *(float*)&ScriptParams[0]; + return 0; + } + case COMMAND_ADD_TIMED_VAL_TO_FLOAT_LVAR: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + CollectParameters(&m_nIp, 1); + *(float*)ptr += CTimer::GetTimeStep() * *(float*)&ScriptParams[0]; + return 0; + } + case COMMAND_ADD_TIMED_FLOAT_VAR_TO_FLOAT_VAR: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) += CTimer::GetTimeStep() * *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + case COMMAND_ADD_TIMED_FLOAT_LVAR_TO_FLOAT_VAR: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) += CTimer::GetTimeStep() * *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + case COMMAND_ADD_TIMED_FLOAT_VAR_TO_FLOAT_LVAR: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) += CTimer::GetTimeStep() * *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + case COMMAND_ADD_TIMED_FLOAT_LVAR_TO_FLOAT_LVAR: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) += CTimer::GetTimeStep() * *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + case COMMAND_SUB_TIMED_VAL_FROM_FLOAT_VAR: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + CollectParameters(&m_nIp, 1); + *(float*)ptr -= CTimer::GetTimeStep() * *(float*)&ScriptParams[0]; + return 0; + } + case COMMAND_SUB_TIMED_VAL_FROM_FLOAT_LVAR: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + CollectParameters(&m_nIp, 1); + *(float*)ptr -= CTimer::GetTimeStep() * *(float*)&ScriptParams[0]; + return 0; + } + case COMMAND_SUB_TIMED_FLOAT_VAR_FROM_FLOAT_VAR: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) -= CTimer::GetTimeStep() * *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + case COMMAND_SUB_TIMED_FLOAT_LVAR_FROM_FLOAT_VAR: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) -= CTimer::GetTimeStep() * *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + case COMMAND_SUB_TIMED_FLOAT_VAR_FROM_FLOAT_LVAR: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) -= CTimer::GetTimeStep() * *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + case COMMAND_SUB_TIMED_FLOAT_LVAR_FROM_FLOAT_LVAR: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) -= CTimer::GetTimeStep() * *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + case COMMAND_SET_VAR_INT_TO_VAR_INT: + *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) = *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + case COMMAND_SET_LVAR_INT_TO_VAR_INT: + *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) = *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + case COMMAND_SET_VAR_INT_TO_LVAR_INT: + *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) = *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + case COMMAND_SET_LVAR_INT_TO_LVAR_INT: + *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) = *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + case COMMAND_SET_VAR_FLOAT_TO_VAR_FLOAT: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) = *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + case COMMAND_SET_LVAR_FLOAT_TO_VAR_FLOAT: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) = *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + case COMMAND_SET_VAR_FLOAT_TO_LVAR_FLOAT: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) = *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + case COMMAND_SET_LVAR_FLOAT_TO_LVAR_FLOAT: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) = *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + case COMMAND_CSET_VAR_INT_TO_VAR_FLOAT: + *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) = *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + case COMMAND_CSET_LVAR_INT_TO_VAR_FLOAT: + *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) = *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + case COMMAND_CSET_VAR_INT_TO_LVAR_FLOAT: + *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) = *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + case COMMAND_CSET_LVAR_INT_TO_LVAR_FLOAT: + *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) = *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + case COMMAND_CSET_VAR_FLOAT_TO_VAR_INT: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) = *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + case COMMAND_CSET_LVAR_FLOAT_TO_VAR_INT: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) = *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + case COMMAND_CSET_VAR_FLOAT_TO_LVAR_INT: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) = *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + return 0; + case COMMAND_CSET_LVAR_FLOAT_TO_LVAR_INT: + *(float*)GetPointerToScriptVariable(&m_nIp, VAR_LOCAL) = *GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + return 0; + case COMMAND_ABS_VAR_INT: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + *ptr = abs(*ptr); + return 0; + } + case COMMAND_ABS_LVAR_INT: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + *ptr = abs(*ptr); + return 0; + } + case COMMAND_ABS_VAR_FLOAT: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + *ptr = abs(*ptr); + return 0; + } + case COMMAND_ABS_LVAR_FLOAT: + { + int32* ptr = GetPointerToScriptVariable(&m_nIp, VAR_LOCAL); + *ptr = abs(*ptr); + return 0; + } + case COMMAND_GENERATE_RANDOM_FLOAT: + { + float* ptr = (float*)GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL); + CGeneral::GetRandomNumber(); + CGeneral::GetRandomNumber(); + CGeneral::GetRandomNumber(); /* To make it EXTRA random! */ + *ptr = CGeneral::GetRandomNumber() / 65536.0f; + /* Between 0 and 0.5 on PC (oh well...), never used in original script. */ + return 0; + } + case COMMAND_GENERATE_RANDOM_INT: + *GetPointerToScriptVariable(&m_nIp, VAR_GLOBAL) = CGeneral::GetRandomNumber(); + return 0; + case COMMAND_CREATE_CHAR: + { + CollectParameters(&m_nIp, 5); + switch (ScriptParams[1]) { + case MI_COP: + if (ScriptParams[0] = PEDTYPE_COP) + ScriptParams[1] = COP_STREET; + break; + case MI_SWAT: + if (ScriptParams[0] = PEDTYPE_COP) + ScriptParams[1] = COP_SWAT; + break; + case MI_FBI: + if (ScriptParams[0] = PEDTYPE_COP) + ScriptParams[1] = COP_FBI; + break; + case MI_ARMY: + if (ScriptParams[0] = PEDTYPE_COP) + ScriptParams[1] = COP_ARMY; + break; + case MI_MEDIC: + if (ScriptParams[0] = PEDTYPE_EMERGENCY) + ScriptParams[1] = PEDTYPE_EMERGENCY; + break; + case MI_FIREMAN: + if (ScriptParams[0] = PEDTYPE_FIREMAN) + ScriptParams[1] = PEDTYPE_FIREMAN; + break; + default: + break; + } + CPed* ped; + if (ScriptParams[0] == PEDTYPE_COP) + ped = new CCopPed((eCopType)ScriptParams[1]); + else if (ScriptParams[0] == PEDTYPE_EMERGENCY || ScriptParams[0] == PEDTYPE_FIREMAN) + ped = new CEmergencyPed(ScriptParams[1]); + else + ped = new CCivilianPed(ScriptParams[0], ScriptParams[1]); + ped->CharCreatedBy = MISSION_CHAR; + ped->bRespondsToThreats = false; + ped->m_ped_flagG2 = false; + CVector pos = *(CVector*)&ScriptParams[2]; + if (pos.z <= -100.0f) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + pos.z += 1.0f; + ped->GetPosition() = pos; + ped->SetOrientation(0.0f, 0.0f, 0.0f); + CTheScripts::ClearSpaceForMissionEntity(pos, ped); + CWorld::Add(ped); + ped->m_level = CTheZones::GetLevelFromPosition(pos); + CPopulation::ms_nTotalMissionPeds++; + ScriptParams[0] = CPools::GetPedPool()->GetIndex(ped); + StoreParameters(&m_nIp, 1); + if (m_bIsMissionScript) + CTheScripts::MissionCleanup.AddEntityToList(ScriptParams[0], CLEANUP_CHAR); + return 0; + } + case COMMAND_DELETE_CHAR: + { + CollectParameters(&m_nIp, 1); + CPed* ped = CPools::GetPedPool()->GetAt(ScriptParams[0]); + if (ped) { + if (ped->bInVehicle && ped->m_pMyVehicle) { + if (ped->m_pMyVehicle->pDriver == ped) { + ped->m_pMyVehicle->RemoveDriver(); + ped->m_pMyVehicle->m_status = STATUS_ABANDONED; + if (ped->m_pMyVehicle->m_nDoorLock == CARLOCK_LOCKED_INITIALLY) + ped->m_pMyVehicle->m_nDoorLock = CARLOCK_UNLOCKED; + if (ped->m_nPedType == PEDTYPE_COP && ped->m_pMyVehicle->IsLawEnforcementVehicle()) + ped->m_pMyVehicle->ChangeLawEnforcerState(0); + } + else { + ped->m_pMyVehicle->RemovePassenger(ped); + } + } + CWorld::RemoveReferencesToDeletedObject(ped); + delete ped; + --CPopulation::ms_nTotalMissionPeds; + } + if (m_bIsMissionScript) + CTheScripts::MissionCleanup.RemoveEntityFromList(ScriptParams[0], CLEANUP_CHAR); + return 0; + } + case COMMAND_CHAR_WANDER_DIR: + { + CollectParameters(&m_nIp, 2); + CPed* ped = CPools::GetPedPool()->GetAt(ScriptParams[0]); + assert(ped); + ped->ClearAll(); + int8 path = ScriptParams[1]; + if (ScriptParams[1] < 0 || ScriptParams[1] > 7) + path = CGeneral::GetRandomNumberInRange(0, 7); + ped->SetWanderPath(path); + return 0; + } + case COMMAND_CHAR_FOLLOW_PATH: + { + CollectParameters(&m_nIp, 4); + CPed* ped = CPools::GetPedPool()->GetAt(ScriptParams[0]); + assert(ped); + CVector pos = *(CVector*)&ScriptParams[1]; + if (pos.z <= -100.0f) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + ped->ClearAll(); + ped->SetFollowPath(pos); + return 0; + } + case COMMAND_CHAR_SET_IDLE: + { + CollectParameters(&m_nIp, 1); + CPed* ped = CPools::GetPedPool()->GetAt(ScriptParams[0]); + assert(ped); + ped->m_bScriptObjectiveCompleted = false; + ped->SetObjective(OBJECTIVE_IDLE); + return 0; + } + case COMMAND_GET_CHAR_COORDINATES: + { + CollectParameters(&m_nIp, 1); + CPed* ped = CPools::GetPedPool()->GetAt(ScriptParams[0]); + assert(ped); + CVehicle* vehicle; + CVector pos; + /* Seems a bit clumsy but I'll leave original flow */ + if (ped->bInVehicle) + vehicle = ped->m_pMyVehicle; + else + vehicle = nil; + if (vehicle) + pos = vehicle->GetPosition(); + else + pos = ped->GetPosition(); + *(CVector*)&ScriptParams[0] = pos; + StoreParameters(&m_nIp, 3); + return 0; + } + case COMMAND_SET_CHAR_COORDINATES: + { + CollectParameters(&m_nIp, 4); + CPed* ped = CPools::GetPedPool()->GetAt(ScriptParams[0]); + assert(ped); + CVehicle* vehicle; + if (ped->bInVehicle) + vehicle = ped->m_pMyVehicle; + else + vehicle = nil; + CVector pos = *(CVector*)&ScriptParams[1]; + if (pos.z <= -100.0f) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + /* The following block was once again written + * by someone not familiar with virtual functions. + * It doesn't require any ifs at all. + * To keep as close to original as possible, I'll keep it. + * Maybe there was more commented out/debug + * stuff, but I doubt it. + */ + if (!vehicle){ + pos.z += ped->GetDistanceFromCentreOfMassToBaseOfModel(); + ped->Teleport(pos); + CTheScripts::ClearSpaceForMissionEntity(pos, ped); + }else if (vehicle->IsBoat()){ + pos.z += vehicle->GetDistanceFromCentreOfMassToBaseOfModel(); + vehicle->Teleport(pos); + CTheScripts::ClearSpaceForMissionEntity(pos, vehicle); + }else{ + pos.z += vehicle->GetDistanceFromCentreOfMassToBaseOfModel(); + vehicle->Teleport(pos); + CTheScripts::ClearSpaceForMissionEntity(pos, vehicle); + } + /* Short version of this command. + * + * CollectParameters(&m_nIp, 4); + * CPed* ped = CPools::GetPedPool()->GetAt(ScriptParams[0]); + * assert(ped); + * CEntity* entityToMove = ped->bInVehicle ? ped->m_pMyVehicle : ped; + * CVector pos = *(CVector*)&ScriptParams[1]; + * if (pos.z <= -100.0f) + * pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + * pos.z += ped->GetDistanceFromCentreOfMassToBaseOfModel(); + * entityToMove->Teleport(pos); + * CTheScripts::ClearSpaceForMissionEntity(pos, entityToMove); + * + */ + return 0; + } + case COMMAND_IS_CHAR_STILL_ALIVE: + { + CollectParameters(&m_nIp, 1); + CPed* ped = CPools::GetPedPool()->GetAt(ScriptParams[0]); + UpdateCompareFlag(ped && ped->m_status != PED_DEAD && ped->m_status != PED_DIE); + return 0; + } + case COMMAND_IS_CHAR_IN_AREA_2D: + { + CollectParameters(&m_nIp, 6); + CPed* ped = CPools::GetPedPool()->GetAt(ScriptParams[0]); + assert(ped); + CVehicle* vehicle; + if (ped->bInVehicle) + vehicle = ped->m_pMyVehicle; + else + vehicle = nil; + float x1, y1, x2, y2; + x1 = *(float*)&ScriptParams[1]; + y1 = *(float*)&ScriptParams[2]; + x2 = *(float*)&ScriptParams[3]; + y2 = *(float*)&ScriptParams[4]; + if (vehicle) + UpdateCompareFlag(ped->m_pMyVehicle->IsWithinArea(x1, y1, x2, y2)); + else + UpdateCompareFlag(ped->IsWithinArea(x1, y1, x2, y2)); + CTheScripts::HighlightImportantArea((uint32)this + m_nIp, x1, y1, x2, y2, -100.0f); + if (CTheScripts::DbgFlag) + CTheScripts::DrawDebugSquare(x1, y1, x2, y2); + return 0; + } + case COMMAND_IS_CHAR_IN_AREA_3D: + { + CollectParameters(&m_nIp, 8); + CPed* ped = CPools::GetPedPool()->GetAt(ScriptParams[0]); + assert(ped); + CVehicle* vehicle; + if (ped->bInVehicle) + vehicle = ped->m_pMyVehicle; + else + vehicle = nil; + float x1, y1, z1, x2, y2, z2; + x1 = *(float*)&ScriptParams[1]; + y1 = *(float*)&ScriptParams[2]; + z1 = *(float*)&ScriptParams[3]; + x2 = *(float*)&ScriptParams[4]; + y2 = *(float*)&ScriptParams[5]; + z2 = *(float*)&ScriptParams[6]; + if (vehicle) + UpdateCompareFlag(ped->m_pMyVehicle->IsWithinArea(x1, y1, z1, x2, y2, z2)); + else + UpdateCompareFlag(ped->IsWithinArea(x1, y1, z1, x2, y2, z2)); + CTheScripts::HighlightImportantArea((uint32)this + m_nIp, x1, y1, x2, y2, -100.0f); + if (CTheScripts::DbgFlag) + CTheScripts::DrawDebugCube(x1, y1, z1, x2, y2, z2); + return 0; + } + case COMMAND_CREATE_CAR: + CollectParameters(&m_nIp, 4); + int32 handle; + if (CModelInfo::IsBoatModel(ScriptParams[0])){ + CBoat* boat = new CBoat(ScriptParams[0], MISSION_VEHICLE); + CVector pos = *(CVector*)&ScriptParams[1]; + if (pos.z <= -100.0f) + pos.z = CWorld::FindGroundZForCoord(pos.x, pos.y); + pos.z += boat->GetDistanceFromCentreOfMassToBaseOfModel(); + boat->GetPosition() = pos; + CTheScripts::ClearSpaceForMissionEntity(pos, boat); + boat->m_status = STATUS_ABANDONED; + }else if (CModelInfo::IsBikeModel(ScriptParams[0])){ + /* Do nothing. No bikes in GTA III. But check is there. */ + } + + } + return -1; +} + WRAPPER int8 CRunningScript::ProcessCommandsFrom200To299(int32 command) { EAXJMP(0x43D530); } WRAPPER int8 CRunningScript::ProcessCommandsFrom300To399(int32 command) { EAXJMP(0x43ED30); } WRAPPER int8 CRunningScript::ProcessCommandsFrom400To499(int32 command) { EAXJMP(0x440CB0); } diff --git a/src/core/World.cpp b/src/core/World.cpp index a31f87a7..2b2ddd06 100644 --- a/src/core/World.cpp +++ b/src/core/World.cpp @@ -26,6 +26,8 @@ bool &CWorld::bSecondShift = *(bool*)0x95CD54; bool &CWorld::bForceProcessControl = *(bool*)0x95CD6C; bool &CWorld::bProcessCutsceneOnly = *(bool*)0x95CD8B; +WRAPPER void CWorld::RemoveReferencesToDeletedObject(CEntity*) { EAXJMP(0x4B3BF0); } + void CWorld::Add(CEntity *ent) { diff --git a/src/core/World.h b/src/core/World.h index d6063d70..a08a8cb9 100644 --- a/src/core/World.h +++ b/src/core/World.h @@ -99,6 +99,7 @@ public: static float FindGroundZForCoord(float x, float y); static float FindGroundZFor3DCoord(float x, float y, float z, bool *found); static float FindRoofZFor3DCoord(float x, float y, float z, bool *found); + static void RemoveReferencesToDeletedObject(CEntity*); static float GetSectorX(float f) { return ((f - WORLD_MIN_X)/SECTOR_SIZE_X); } static float GetSectorY(float f) { return ((f - WORLD_MIN_Y)/SECTOR_SIZE_Y); } diff --git a/src/core/common.h b/src/core/common.h index 4b7bcb0a..e57c59d8 100644 --- a/src/core/common.h +++ b/src/core/common.h @@ -178,3 +178,4 @@ void re3_assert(const char *expr, const char *filename, unsigned int lineno, con #define max(a, b) (((a) > (b)) ? (a) : (b)) #define min(a, b) (((a) < (b)) ? (a) : (b)) +#define abs(a) (((a) < 0) ? (-a) : (a)) diff --git a/src/modelinfo/ModelInfo.cpp b/src/modelinfo/ModelInfo.cpp index 454a73f1..0c3ec76a 100644 --- a/src/modelinfo/ModelInfo.cpp +++ b/src/modelinfo/ModelInfo.cpp @@ -175,6 +175,13 @@ CModelInfo::IsBoatModel(int32 id) ((CVehicleModelInfo*)GetModelInfo(id))->m_vehicleType == VEHICLE_TYPE_BOAT; } +bool +CModelInfo::IsBikeModel(int32 id) +{ + return GetModelInfo(id)->m_type == MITYPE_VEHICLE && + ((CVehicleModelInfo*)GetModelInfo(id))->m_vehicleType == VEHICLE_TYPE_BIKE; +} + void CModelInfo::RemoveColModelsFromOtherLevels(eLevelName level) { diff --git a/src/modelinfo/ModelInfo.h b/src/modelinfo/ModelInfo.h index d20367d1..ee82276d 100644 --- a/src/modelinfo/ModelInfo.h +++ b/src/modelinfo/ModelInfo.h @@ -36,5 +36,6 @@ public: } static bool IsBoatModel(int32 id); + static bool IsBikeModel(int32 id); static void RemoveColModelsFromOtherLevels(eLevelName level); }; diff --git a/src/peds/CivilianPed.cpp b/src/peds/CivilianPed.cpp index cf8a0580..717eaa3f 100644 --- a/src/peds/CivilianPed.cpp +++ b/src/peds/CivilianPed.cpp @@ -6,7 +6,7 @@ WRAPPER void CCivilianPed::ProcessControl(void) { EAXJMP(0x4BFFE0); } CCivilianPed::CCivilianPed(int pedtype, int mi) : CPed(pedtype) { - CPed::SetModelIndex(mi); + SetModelIndex(mi); for (int i = 0; i < 10; i++) { m_nearPeds[i] = nil; diff --git a/src/peds/CopPed.cpp b/src/peds/CopPed.cpp index 0ac0473f..badcc4de 100644 --- a/src/peds/CopPed.cpp +++ b/src/peds/CopPed.cpp @@ -1,6 +1,62 @@ #include "common.h" #include "patcher.h" #include "CopPed.h" +#include "ModelIndices.h" + +CCopPed::CCopPed(eCopType copType) : CPed(PEDTYPE_COP) +{ + m_nCopType = copType; + switch (copType) { + case COP_STREET: + SetModelIndex(MI_COP); + GiveWeapon(WEAPONTYPE_COLT45, 1000); + m_currentWeapon = WEAPONTYPE_UNARMED; + m_fArmour = 0.0f; + m_wepSkills = 208; /* TODO: what is this? seems unused */ + m_wepAccuracy = 60; + break; + case COP_FBI: + SetModelIndex(MI_FBI); + GiveWeapon(WEAPONTYPE_COLT45, 1000); + GiveWeapon(WEAPONTYPE_AK47, 1000); + SetCurrentWeapon(WEAPONTYPE_AK47); + m_fArmour = 100.0f; + m_wepSkills = 176; /* TODO: what is this? seems unused */ + m_wepAccuracy = 76; + break; + case COP_SWAT: + SetModelIndex(MI_SWAT); + GiveWeapon(WEAPONTYPE_COLT45, 1000); + GiveWeapon(WEAPONTYPE_UZI, 1000); + SetCurrentWeapon(WEAPONTYPE_UZI); + m_fArmour = 50.0f; + m_wepSkills = 32; /* TODO: what is this? seems unused */ + m_wepAccuracy = 64; + break; + case COP_ARMY: + SetModelIndex(MI_ARMY); + GiveWeapon(WEAPONTYPE_COLT45, 1000); + GiveWeapon(WEAPONTYPE_M16, 1000); + GiveWeapon(WEAPONTYPE_GRENADE, 10); + SetCurrentWeapon(WEAPONTYPE_M16); + m_fArmour = 100.0f; + m_wepSkills = 32; /* TODO: what is this? seems unused */ + m_wepAccuracy = 84; + break; + default: + break; + } + m_bIsInPursuit = false; + field_1350 = 1; + m_bIsDisabledCop = false; + field_1356 = 0; + m_attackTimer = 0; + field_1351 = 0; + m_bZoneDisabledButClose = false; + m_bZoneDisabled = false; + field_1364 = -1; + m_pPointGunAt = nil; +} CCopPed::~CCopPed() { @@ -12,9 +68,11 @@ WRAPPER void CCopPed::ClearPursuit(void) { EAXJMP(0x4C28C0); } class CCopPed_ : public CCopPed { public: + CCopPed *ctor(eCopType type) { return ::new (this) CCopPed(type); }; void dtor(void) { CCopPed::~CCopPed(); } }; STARTPATCHES + InjectHook(0x4C11B0, &CCopPed_::ctor, PATCH_JUMP); InjectHook(0x4C13E0, &CCopPed_::dtor, PATCH_JUMP); ENDPATCHES diff --git a/src/peds/CopPed.h b/src/peds/CopPed.h index f8139046..17ca111f 100644 --- a/src/peds/CopPed.h +++ b/src/peds/CopPed.h @@ -31,6 +31,7 @@ public: int8 field_1366; int8 field_1367; + CCopPed(eCopType); ~CCopPed(); void ClearPursuit(void); diff --git a/src/peds/EmergencyPed.cpp b/src/peds/EmergencyPed.cpp index 664bd6f6..d4f46b0e 100644 --- a/src/peds/EmergencyPed.cpp +++ b/src/peds/EmergencyPed.cpp @@ -1,13 +1,36 @@ #include "common.h" #include "patcher.h" #include "EmergencyPed.h" +#include "ModelIndices.h" class CEmergencyPed_ : public CEmergencyPed { public: + CEmergencyPed *ctor(int pedtype) { return ::new (this) CEmergencyPed(pedtype); }; void dtor(void) { CEmergencyPed::~CEmergencyPed(); } }; +CEmergencyPed::CEmergencyPed(uint32 type) : CPed(type) +{ + switch (type){ + case PEDTYPE_EMERGENCY: + SetModelIndex(MI_MEDIC); + m_pRevivedPed = nil; + field_1360 = 0; + break; + case PEDTYPE_FIREMAN: + SetModelIndex(MI_FIREMAN); + m_pRevivedPed = nil; + break; + default: + break; + } + m_nEmergencyPedState = 0; + m_pAttendedAccident = nil; + field_1356 = 0; +} + STARTPATCHES + InjectHook(0x4C2E40, &CEmergencyPed_::ctor, PATCH_JUMP); InjectHook(0x4C2EF0, &CEmergencyPed_::dtor, PATCH_JUMP); ENDPATCHES diff --git a/src/peds/EmergencyPed.h b/src/peds/EmergencyPed.h index f21996e8..b9d979e3 100644 --- a/src/peds/EmergencyPed.h +++ b/src/peds/EmergencyPed.h @@ -1,11 +1,19 @@ #pragma once +#include "Fire.h" #include "Ped.h" class CEmergencyPed : public CPed { public: // 0x53C - uint8 stuff[24]; + CPed* m_pRevivedPed; + int32 m_nEmergencyPedState; // looks like flags + void* m_pAttendedAccident; //TODO: CAccident* + CFire* m_pAttendedFire; + int8 field_1356; + int32 field_1360; + + CEmergencyPed(uint32); }; static_assert(sizeof(CEmergencyPed) == 0x554, "CEmergencyPed: error"); diff --git a/src/peds/Ped.cpp b/src/peds/Ped.cpp index 4ad4ac1b..859ddda4 100644 --- a/src/peds/Ped.cpp +++ b/src/peds/Ped.cpp @@ -46,6 +46,9 @@ WRAPPER void CPed::SetDuck(uint32) { EAXJMP(0x4E4920); } WRAPPER void CPed::RegisterThreatWithGangPeds(CEntity*) { EAXJMP(0x4E3870); } WRAPPER void CPed::MakeChangesForNewWeapon(int8) { EAXJMP(0x4F2560); } WRAPPER bool CPed::Seek(void) { EAXJMP(0x4D1640); } +WRAPPER void CPed::ClearAll(void) { EAXJMP(0x4C7F20); } +WRAPPER void CPed::SetWanderPath(int8) { EAXJMP(0x4D2750); } +WRAPPER void CPed::SetFollowPath(CVector) { EAXJMP(0x4D2EA0); } bool &CPed::bNastyLimbsCheat = *(bool*)0x95CD44; bool &CPed::bPedCheat2 = *(bool*)0x95CD5A; @@ -1404,7 +1407,7 @@ CPed::PedSetDraggedOutCarCB(CAnimBlendAssociation *dragAssoc, void *arg) if (vehicle->pDriver == ped) { vehicle->RemoveDriver(); - if (vehicle->m_nDoorLock == CARLOCK_COP_CAR) + if (vehicle->m_nDoorLock == CARLOCK_LOCKED_INITIALLY) vehicle->m_nDoorLock = CARLOCK_UNLOCKED; if (ped->m_nPedType == PEDTYPE_COP && vehicle->IsLawEnforcementVehicle()) diff --git a/src/peds/Ped.h b/src/peds/Ped.h index cd7d88af..d13371ab 100644 --- a/src/peds/Ped.h +++ b/src/peds/Ped.h @@ -210,7 +210,7 @@ public: uint8 m_ped_flagD10 : 1; uint8 m_ped_flagD20 : 1; uint8 m_ped_flagD40 : 1; // reset when objective changes - uint8 m_ped_flagD80 : 1; + uint8 m_bScriptObjectiveCompleted : 1; uint8 m_ped_flagE1 : 1; uint8 m_ped_flagE2 : 1; @@ -460,6 +460,9 @@ public: void MakeChangesForNewWeapon(int8); void CheckAroundForPossibleCollisions(void); bool Seek(void); + void ClearAll(void); + void SetWanderPath(int8); + void SetFollowPath(CVector); // Static methods static void GetLocalPositionToOpenCarDoor(CVector *output, CVehicle *veh, uint32 enterType, float offset); diff --git a/src/vehicles/Vehicle.h b/src/vehicles/Vehicle.h index 55805e9d..3d751bfe 100644 --- a/src/vehicles/Vehicle.h +++ b/src/vehicles/Vehicle.h @@ -20,7 +20,7 @@ enum eCarLock { CARLOCK_LOCKED, CARLOCK_LOCKOUT_PLAYER_ONLY, CARLOCK_LOCKED_PLAYER_INSIDE, - CARLOCK_COP_CAR, + CARLOCK_LOCKED_INITIALLY, CARLOCK_FORCE_SHUT_DOORS, CARLOCK_SKIP_SHUT_DOORS };