Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reimplement cut stock game gibbing feature #294

Open
wants to merge 21 commits into
base: master
Choose a base branch
from
Open
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
2 changes: 2 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ Version 1.9.0 (not released yet)
- Add mod name to main menu
- Make value of `spectate_mode_minimal_ui` persist between game launches
- Add `version` command
- Add `gore_level` command
- Add gibbing for enemies and corpses at gore level 2

[@is-this-c](https://github.com/is-this-c)
- Support `©` in TrueType fonts
Expand Down
9 changes: 9 additions & 0 deletions game_patch/main/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,15 @@
GameConfig g_game_config;
HMODULE g_hmodule;

std::mt19937 g_rng;

void initialize_random_generator()
{
// seed rng with the current time
auto seed = std::chrono::steady_clock::now().time_since_epoch().count();
g_rng.seed(static_cast<unsigned long>(seed));
}

CallHook<void()> rf_init_hook{
0x004B27CD,
[]() {
Expand Down
6 changes: 6 additions & 0 deletions game_patch/main/main.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
#pragma once

#include <random>
#include <common/config/GameConfig.h>

extern GameConfig g_game_config;

// random number generator
extern std::mt19937 g_rng;
void initialize_random_generator();

#ifdef _WINDOWS_
extern HMODULE g_hmodule;
#endif
12 changes: 12 additions & 0 deletions game_patch/multi/server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,18 @@ FunHook<float(rf::Entity*, float, int, int, int)> entity_damage_hook{
}
}

// should entity gib?
if (damaged_ep->life < -100.0f && damage_type == 3 && // explosive
damaged_ep->material == 3 && // flesh
rf::game_get_gore_level() >= 2 &&
!(damaged_ep->entity_flags & 0x2000000) && // custom_corpse (used by snakes and sea creature)
!(damaged_ep->entity_flags & 0x1) && // dying
!(damaged_ep->entity_flags & 0x1000) && // in_water
!(damaged_ep->entity_flags & 0x2000)) // eye_under_water
{
damaged_ep->entity_flags |= 0x80;
}

float real_damage = entity_damage_hook.call_target(damaged_ep, damage, killer_handle, damage_type, killer_uid);

if (rf::is_server && is_pvp_damage && real_damage > 0.0f) {
Expand Down
116 changes: 116 additions & 0 deletions game_patch/object/entity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
#include <patch_common/CallHook.h>
#include <patch_common/AsmWriter.h>
#include <xlog/xlog.h>
#include "../os/console.h"
#include "../rf/entity.h"
#include "../rf/corpse.h"
#include "../rf/multi.h"
#include "../rf/weapon.h"
#include "../rf/player/player.h"
#include "../rf/particle_emitter.h"
Expand Down Expand Up @@ -201,6 +203,114 @@ CodeInjection entity_process_pre_hide_riot_shield_injection{
},
};

FunHook<void(int)> entity_blood_throw_gibs_hook{
0x0042E3C0, [](int handle) {
rf::Object* objp = rf::obj_from_handle(handle);

// should only gib on gore level 2 or higher
if (rf::game_get_gore_level() < 2) {
return;
}

// only gib flesh entities and corpses
if (!objp || (objp->type != rf::OT_ENTITY && objp->type != rf::OT_CORPSE) || objp->material != 3) {
return;
}

// skip entities with ambient flag (is in original but maybe not necessary?)
rf::Entity* entity = (objp->type == rf::OT_ENTITY) ? static_cast<rf::Entity*>(objp) : nullptr;
if (entity && (entity->info->flags & 0x800000)) {
return;
}

// skip corpses that shouldn't explode (drools_slime or custom_state_anim)
rf::Corpse* corpse = (objp->type == rf::OT_CORPSE) ? static_cast<rf::Corpse*>(objp) : nullptr;
if (corpse && (corpse->corpse_flags & 0x400 || corpse->corpse_flags & 0x4)) {
return;
}

static constexpr int gib_count = 14; // 7 in original
static constexpr float velocity_scale = 15.0f;
static constexpr float spin_scale_min = 10.0f;
static constexpr float spin_scale_max = 25.0f;
static constexpr int lifetime_ms = 7000;
static constexpr float velocity_factor = 0.5f;
static const char* snd_set = "gib bounce";
static const std::vector<const char*> gib_filenames = {
"meatchunk1.v3m",
"meatchunk2.v3m",
"meatchunk3.v3m",
"meatchunk4.v3m",
"meatchunk5.v3m"};

for (int i = 0; i < gib_count; ++i) {
rf::DebrisCreateStruct debris_info;

// random velocity
rf::Vector3 vel;
vel.rand_quick();
debris_info.vel = vel;
debris_info.vel *= velocity_scale;
debris_info.vel += objp->p_data.vel * velocity_factor;

// random spin
rf::Vector3 spin;
spin.rand_quick();
debris_info.spin = spin;
std::uniform_real_distribution<float> range_dist(spin_scale_min, spin_scale_max);
debris_info.spin *= range_dist(g_rng);

// random orient
rf::Matrix3 orient;
orient.rand_quick();
debris_info.orient = orient;

// sound set
rf::ImpactSoundSet* iss = rf::material_find_impact_sound_set(snd_set);
debris_info.iss = iss;

// other properties
debris_info.pos = objp->pos;
debris_info.lifetime_ms = lifetime_ms;
debris_info.debris_flags = 0x4;
debris_info.obj_flags = 0x8000; // start_hidden
debris_info.material = objp->material;
debris_info.room = objp->room;

// pick a random gib filename
std::uniform_int_distribution<size_t> dist(0, gib_filenames.size() - 1);
const char* gib_filename = gib_filenames[dist(g_rng)];

rf::Debris* gib = rf::debris_create(objp->handle, gib_filename, 0.3f, &debris_info, 0, -1.0f);
if (gib) {
gib->obj_flags |= rf::OF_INVULNERABLE;
}
}
}
};

ConsoleCommand2 gore_level_cmd{
"gore_level",
[](std::optional<int> gore_setting) {
if (gore_setting) {
if (*gore_setting >= 0 && *gore_setting <= 2) {
rf::game_set_gore_level(*gore_setting);
rf::console::print("Set gore level to {}", rf::game_get_gore_level());
}
else {
rf::console::print("Invalid gore level specified. Allowed range is 0 (minimal) to 2 (maximum).");
}
}
else {
rf::console::print("Gore level is {}", rf::game_get_gore_level());
}


},
"Set gore level.",
"gore_level [level]"
};

void entity_do_patch()
{
// Fix player being stuck to ground when jumping, especially when FPS is greater than 200
Expand Down Expand Up @@ -252,4 +362,10 @@ void entity_do_patch()

// Hide riot shield third person model if entity is hidden (e.g. in cutscenes)
entity_process_pre_hide_riot_shield_injection.install();

// Restore cut stock game feature for entities and corpses exploding into chunks
entity_blood_throw_gibs_hook.install();

// Commands
gore_level_cmd.register_cmd();
}
3 changes: 3 additions & 0 deletions game_patch/rf/geometry.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "os/array.h"
#include "os/linklist.h"
#include "gr/gr.h"
#include "sound/sound.h"

namespace rf
{
Expand Down Expand Up @@ -456,5 +457,7 @@ namespace rf
static auto& g_cache_clear = addr_as_ref<void()>(0x004F0B90);
static auto& g_get_room_render_list = addr_as_ref<void(GRoom ***rooms, int *num_rooms)>(0x004D3330);

static auto& material_find_impact_sound_set = addr_as_ref<ImpactSoundSet*(const char* name)>(0x004689A0);

static auto& bbox_intersect = addr_as_ref<bool(const Vector3& bbox1_min, const Vector3& bbox1_max, const Vector3& bbox2_min, const Vector3& bbox2_max)>(0x0046C340);
}
14 changes: 14 additions & 0 deletions game_patch/rf/math/matrix.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,20 @@ namespace rf
AddrCaller{0x004FC8A0}.this_call(this, &result);
return result;
}

void make_quick(const Vector3& forward_vector)
{
AddrCaller{0x004FCFA0}.this_call(this, &forward_vector);
}

void rand_quick()
{
Vector3 fvec;

fvec.rand_quick();

make_quick(fvec);
}
};
static_assert(sizeof(Matrix3) == 0x24);

Expand Down
19 changes: 19 additions & 0 deletions game_patch/rf/math/vector.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
#pragma once

#include <cmath>
#include <numbers>
#include <patch_common/MemUtils.h>
#include "../os/os.h"
#include "../../main/main.h"

namespace rf
{
Expand Down Expand Up @@ -157,6 +160,22 @@ namespace rf
{
*this /= len();
}

void rand_quick()
{
constexpr float TWO_PI = 6.2831855f;

std::uniform_real_distribution<float> z_dist(-1.0f, 1.0f);
z = z_dist(g_rng);

std::uniform_real_distribution<float> angle_dist(0.0f, TWO_PI);
float angle = angle_dist(g_rng);

float scale = std::sqrt(1.0f - z * z);

x = std::cos(angle) * scale;
y = std::sin(angle) * scale;
}
};
static_assert(sizeof(Vector3) == 0xC);

Expand Down
38 changes: 37 additions & 1 deletion game_patch/rf/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "math/matrix.h"
#include "os/array.h"
#include "os/string.h"
#include "sound/sound.h"
#include "physics.h"
#include "vmesh.h"

Expand Down Expand Up @@ -36,9 +37,10 @@ namespace rf
OT_GLARE = 0xA,
};

enum ObjectFlags
enum ObjectFlags : int
{
OF_DELAYED_DELETE = 0x2,
OF_INVULNERABLE = 0x4,
OF_WAS_RENDERED = 0x10,
OF_IN_LIQUID = 0x80000,
OF_HAS_ALPHA = 0x100000,
Expand Down Expand Up @@ -121,6 +123,37 @@ namespace rf
};
static_assert(sizeof(ObjectCreateInfo) == 0x98);

struct Debris : Object
{
Debris* next;
Debris* prev;
void* solid;
int vmesh_submesh;
int debris_flags;
int explosion_index;
Timestamp lifetime;
int frame_num;
int sound;
String* custom_sound_set;
};
static_assert(sizeof(Debris) == 0x2B4);

struct DebrisCreateStruct
{
Vector3 pos;
Matrix3 orient;
Vector3 vel;
Vector3 spin;
int lifetime_ms;
int material;
int explosion_index;
int debris_flags;
int obj_flags;
void* room;
ImpactSoundSet* iss;
};
static_assert(sizeof(DebrisCreateStruct) == 0x64);

static auto& obj_lookup_from_uid = addr_as_ref<Object*(int uid)>(0x0048A4A0);
static auto& obj_from_handle = addr_as_ref<Object*(int handle)>(0x0040A0E0);
static auto& obj_flag_dead = addr_as_ref<void(Object* obj)>(0x0048AB40);
Expand All @@ -134,6 +167,9 @@ namespace rf
static auto& obj_light_calculate = addr_as_ref<void()>(0x0048B0E0);

static auto& object_list = addr_as_ref<Object>(0x0073D880);

static auto& debris_create = addr_as_ref<Debris*(int parent_handle, const char* vmesh_filename,
float mass, DebrisCreateStruct* dcs, int mesh_num, float collision_radius)>(0x00412E70);
}

template<>
Expand Down
2 changes: 2 additions & 0 deletions game_patch/rf/player/player.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,4 +173,6 @@ namespace rf
static auto& player_do_frame = addr_as_ref<void(Player*)>(0x004A2700);
static auto& player_make_weapon_current_selection = addr_as_ref<void(Player *player, int weapon_type)>(0x004A4980);
static auto& player_start_death_fade = addr_as_ref<void(Player *pp, float time_sec, void (*callback)(Player *))>(0x004A73E0);
static auto& game_get_gore_level = addr_as_ref<int()>(0x00436A20);
static auto& game_set_gore_level = addr_as_ref<int(int gore_setting)>(0x00436A10);
GooberRF marked this conversation as resolved.
Show resolved Hide resolved
}
10 changes: 10 additions & 0 deletions game_patch/rf/sound/sound.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "../math/vector.h"
#include "../math/matrix.h"
#include "../os/timestamp.h"
#include "../os/string.h"

namespace rf
{
Expand Down Expand Up @@ -54,6 +55,15 @@ namespace rf
};
static_assert(sizeof(AmbientSound) == 0x18);

struct ImpactSoundSet
{
int sounds[40];
int num_material_sounds[10];
int is_all_sounds;
String name;
};
static_assert(sizeof(ImpactSoundSet) == 0xD4);

constexpr int SOUND_GROUP_EFFECTS = 0;
constexpr int SOUND_GROUP_MUSIC = 1;
constexpr int SOUND_GROUP_VOICE_MESSAGES = 2;
Expand Down
3 changes: 1 addition & 2 deletions game_patch/rf/weapon.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,10 @@
#include <patch_common/MemUtils.h>
#include "object.h"
#include "os/timestamp.h"
#include "sound/sound.h"

namespace rf
{
struct ImpactSoundSet;

struct WeaponStateAction
{
String name;
Expand Down
6 changes: 6 additions & 0 deletions resources/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ add_packfile(dashfaction.vpp
images/bullet_icon_powercell_1.tga
images/bullet_icon_rocket_1.tga
images/bullet_icon_shotgun_1.tga
images/gore1.tga
images/enviro0_1.tga
images/enviro10_1.tga
images/enviro20_1.tga
Expand Down Expand Up @@ -87,6 +88,11 @@ add_packfile(dashfaction.vpp
meshes/Vat1.v3m
meshes/coffeesmokedtbl2.v3m
meshes/coffeesmokedtblAlt.v3m
meshes/meatchunk1.v3m
meshes/meatchunk2.v3m
meshes/meatchunk3.v3m
meshes/meatchunk4.v3m
meshes/meatchunk5.v3m

standard_vs:${CMAKE_BINARY_DIR}/shaders/standard_vs.bin
character_vs:${CMAKE_BINARY_DIR}/shaders/character_vs.bin
Expand Down
Binary file added resources/images/gore1.tga
Binary file not shown.
Loading