Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion rwengine/src/engine/GameState.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
#include <engine/ScreenText.hpp>
#include <objects/ObjectTypes.hpp>

#include <script/ScriptTypes.hpp>

class GameWorld;
class GameObject;
class ScriptMachine;
Expand Down Expand Up @@ -330,7 +332,7 @@ class GameState {
* @brief Stores a pointer to script global that stores the on-mission
* state.
*/
int32_t* scriptOnMissionFlag;
ScriptInt* scriptOnMissionFlag;

/** Objects created by the current mission */
std::vector<GameObject*> missionObjects;
Expand Down Expand Up @@ -386,6 +388,12 @@ class GameState {
*/
std::vector<TextDisplayData> texts;

/**
* Script timer
*/
ScriptInt* scriptTimerVariable = nullptr;
bool scriptTimerPaused = false;

/** The camera near value currently set by the script */
float cameraNear;
bool cameraFixed;
Expand Down
21 changes: 8 additions & 13 deletions rwengine/src/script/modules/GTA3ModuleImpl.inl
Original file line number Diff line number Diff line change
Expand Up @@ -3456,12 +3456,10 @@ void opcode_014d(const ScriptArguments& args, const ScriptString arg1, const Scr
@brief start_timer_at %1d%

opcode 014e
@arg arg1G Global timer storage
@arg timer
*/
void opcode_014e(const ScriptArguments& args, ScriptInt& arg1G) {
RW_UNIMPLEMENTED_OPCODE(0x014e);
RW_UNUSED(arg1G);
RW_UNUSED(args);
void opcode_014e(const ScriptArguments& args, ScriptInt& timer) {
args.getState()->scriptTimerVariable = &timer;
}

/**
Expand All @@ -3470,10 +3468,9 @@ void opcode_014e(const ScriptArguments& args, ScriptInt& arg1G) {
opcode 014f
@arg arg1G Global timer storage
*/
void opcode_014f(const ScriptArguments& args, ScriptInt& arg1G) {
RW_UNIMPLEMENTED_OPCODE(0x014f);
RW_UNUSED(arg1G);
RW_UNUSED(args);
void opcode_014f(const ScriptArguments& args, ScriptInt& unused) {
RW_UNUSED(unused);
args.getState()->scriptTimerVariable = nullptr;
}

/**
Expand Down Expand Up @@ -10416,10 +10413,8 @@ void opcode_0395(const ScriptArguments& args, ScriptVec3 coord, const ScriptFloa
opcode 0396
@arg arg1 Boolean true/false
*/
void opcode_0396(const ScriptArguments& args, const ScriptBoolean arg1) {
RW_UNIMPLEMENTED_OPCODE(0x0396);
RW_UNUSED(arg1);
RW_UNUSED(args);
void opcode_0396(const ScriptArguments& args, const ScriptBoolean paused) {
args.getState()->scriptTimerPaused = paused;
}

/**
Expand Down
66 changes: 56 additions & 10 deletions rwgame/DrawUI.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#include "DrawUI.hpp"
#include <ai/PlayerController.hpp>
#include <engine/GameState.hpp>
#include <objects/CharacterObject.hpp>
#include <data/WeaponData.hpp>
#include <engine/GameData.hpp>
#include <engine/GameState.hpp>
#include <objects/CharacterObject.hpp>
#include <render/GameRenderer.hpp>

#include <glm/gtc/constants.hpp>
Expand All @@ -12,29 +12,66 @@

constexpr size_t ui_textSize = 25;
constexpr size_t ui_textHeight = 22;
constexpr size_t ui_elementMargin = 3;
constexpr size_t ui_outerMargin = 20;
constexpr size_t ui_infoMargin = 10;
constexpr size_t ui_weaponSize = 64;
constexpr size_t ui_ammoSize = 14;
constexpr size_t ui_ammoHeight = 16;
constexpr size_t ui_wantedLevelHeight =
ui_outerMargin + ui_weaponSize + ui_elementMargin;
constexpr size_t ui_scriptTimerHeight =
ui_wantedLevelHeight + ui_textHeight + ui_elementMargin;
constexpr size_t ui_armourOffset = ui_textSize * 3;
constexpr size_t ui_maxWantedLevel = 6;
constexpr size_t ui_lowHealth = 9;
const glm::u8vec3 ui_timeColour(196, 165, 119);
const glm::u8vec3 ui_moneyColour(89, 113, 147);
const glm::u8vec3 ui_healthColour(187, 102, 47);
const glm::u8vec3 ui_armourColour(123, 136, 93);
const glm::u8vec3 ui_scriptTimerColour(186, 101, 50);
const glm::u8vec3 ui_shadowColour(0, 0, 0);
constexpr float ui_mapSize = 150.f;
constexpr float ui_worldSizeMin = 200.f;
constexpr float ui_worldSizeMax = 300.f;

void drawScriptTimer(GameWorld* world, GameRenderer* render) {
if (world->state->scriptTimerVariable) {
float scriptTimerTextX =
render->getRenderer()->getViewport().x - ui_outerMargin;
float scriptTimerTextY = ui_scriptTimerHeight;

TextRenderer::TextInfo ti;
ti.font = 1;
ti.size = ui_textSize;
ti.align = TextRenderer::TextInfo::Right;

{
int32_t seconds = *world->state->scriptTimerVariable / 1000;
std::stringstream ss;
ss << std::setw(2) << std::setfill('0') << seconds / 60
<< std::setw(0) << ":" << std::setw(2) << seconds % 60;

ti.text = GameStringUtil::fromString(ss.str());
}

ti.baseColour = ui_shadowColour;
ti.screenPosition =
glm::vec2(scriptTimerTextX + 1.f, scriptTimerTextY + 1.f);
render->text.renderText(ti);

ti.baseColour = ui_scriptTimerColour;
ti.screenPosition = glm::vec2(scriptTimerTextX, scriptTimerTextY);
render->text.renderText(ti);
}
}

void drawMap(ViewCamera& currentView, PlayerController* player,
GameWorld* world, GameRenderer* render) {
MapRenderer::MapInfo map;

if (world->state->hudFlash != HudFlash::FlashRadar
|| std::fmod(world->getGameTime(), 0.5f) >= .25f) {
if (world->state->hudFlash != HudFlash::FlashRadar ||
std::fmod(world->getGameTime(), 0.5f) >= .25f) {
glm::quat camRot = currentView.rotation;

map.rotation = glm::roll(camRot) - glm::half_pi<float>();
Expand Down Expand Up @@ -67,7 +104,7 @@ void drawPlayerInfo(PlayerController* player, GameWorld* world,
(ui_outerMargin + ui_weaponSize);
float iconY = ui_outerMargin;
float wantedX = render->getRenderer()->getViewport().x - (ui_outerMargin);
float wantedY = ui_outerMargin + ui_weaponSize + 3.f;
float wantedY = ui_wantedLevelHeight;

TextRenderer::TextInfo ti;
ti.font = 1;
Expand All @@ -81,12 +118,14 @@ void drawPlayerInfo(PlayerController* player, GameWorld* world,

ti.text = GameStringUtil::fromString(ss.str());
}

ti.baseColour = ui_shadowColour;
ti.screenPosition = glm::vec2(infoTextX + 1.f, infoTextY + 1.f);
render->text.renderText(ti);

ti.baseColour = ui_timeColour;
ti.screenPosition = glm::vec2(infoTextX, infoTextY);

render->text.renderText(ti);

infoTextY += ui_textHeight;
Expand All @@ -98,25 +137,30 @@ void drawPlayerInfo(PlayerController* player, GameWorld* world,

ti.text = GameSymbols::Money + GameStringUtil::fromString(ss.str());
}

ti.baseColour = ui_shadowColour;
ti.screenPosition = glm::vec2(infoTextX + 1.f, infoTextY + 1.f);
render->text.renderText(ti);

ti.baseColour = ui_moneyColour;

ti.screenPosition = glm::vec2(infoTextX, infoTextY);
render->text.renderText(ti);

infoTextY += ui_textHeight;

if ((world->state->hudFlash != HudFlash::FlashHealth
&& player->getCharacter()->getCurrentState().health > ui_lowHealth)
|| std::fmod(world->getGameTime(), 0.5f) >= .25f) { // UI: Blinking health indicator if health is low
if ((world->state->hudFlash != HudFlash::FlashHealth &&
player->getCharacter()->getCurrentState().health > ui_lowHealth) ||
std::fmod(world->getGameTime(), 0.5f) >=
.25f) { // UI: Blinking health indicator if health is low
std::stringstream ss;
ss << std::setw(3) << std::setfill('0')
<< (int)player->getCharacter()->getCurrentState().health;
ti.text = GameSymbols::Heart + GameStringUtil::fromString(ss.str());

ti.baseColour = ui_shadowColour;
ti.screenPosition = glm::vec2(infoTextX + 1.f, infoTextY + 1.f);

render->text.renderText(ti);

ti.baseColour = ui_healthColour;
Expand All @@ -129,6 +173,7 @@ void drawPlayerInfo(PlayerController* player, GameWorld* world,
ss << std::setw(3) << std::setfill('0')
<< (int)player->getCharacter()->getCurrentState().armour;
ti.text = GameSymbols::Armour + GameStringUtil::fromString(ss.str());

ti.baseColour = ui_shadowColour;
ti.screenPosition =
glm::vec2(infoTextX + 1.f - ui_armourOffset, infoTextY + 1.f);
Expand Down Expand Up @@ -201,8 +246,8 @@ void drawPlayerInfo(PlayerController* player, GameWorld* world,
// The clip is actually there, but it holds just one shot/charge
displayBulletsTotal += slotInfo.bulletsClip;

ti.text = GameStringUtil::fromString(
std::to_string(displayBulletsTotal));
ti.text =
GameStringUtil::fromString(std::to_string(displayBulletsTotal));
} else {
// Limit the maximal displayed length for the total bullet count
if (slotInfo.bulletsTotal > 9999) {
Expand All @@ -229,6 +274,7 @@ void drawHUD(ViewCamera& currentView, PlayerController* player,
if (player && player->getCharacter()) {
drawMap(currentView, player, world, render);
drawPlayerInfo(player, world, render);
drawScriptTimer(world, render);
}
}

Expand Down
20 changes: 18 additions & 2 deletions rwgame/RWGame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,7 @@ void RWGame::tick(float dt) {
State* currState = StateManager::get().states.back().get();

static float clockAccumulator = 0.f;
static float scriptTimerAccumulator = 0.f;
if (currState->shouldWorldUpdate()) {
world->chase.update(dt);

Expand All @@ -512,6 +513,22 @@ void RWGame::tick(float dt) {
clockAccumulator -= 1.f;
}

if (state.scriptTimerVariable && !state.scriptTimerPaused) {
scriptTimerAccumulator += dt;
while (scriptTimerAccumulator >= 1.f) {
(*state.scriptTimerVariable) -= 1000;
if (*state.scriptTimerVariable <= 0) {
(*state.scriptTimerVariable) = 0;
state.scriptTimerVariable = nullptr;
}
// 11 seconds
if (*state.scriptTimerVariable <= 11000) {
// @todo beep
}
scriptTimerAccumulator -= 1.f;
}
}

// Clean up old VisualFX
for (int i = 0; i < static_cast<int>(world->effects.size()); ++i) {
VisualFX* effect = world->effects[i];
Expand Down Expand Up @@ -615,8 +632,7 @@ void RWGame::render(float alpha, float time) {
}
RW_PROFILE_END();

if (!world->isPaused())
drawOnScreenText(world.get(), &renderer);
if (!world->isPaused()) drawOnScreenText(world.get(), &renderer);
}

void RWGame::renderDebugStats(float time) {
Expand Down