Skip to content

Commit

Permalink
implement ps2-inspired gibbing method, consolidate corpse gibbing log…
Browse files Browse the repository at this point in the history
…ic, add new chunks and remove old, update licensing info
  • Loading branch information
GooberRF committed Dec 15, 2024
1 parent f8e94ec commit 7306bea
Show file tree
Hide file tree
Showing 20 changed files with 178 additions and 52 deletions.
2 changes: 1 addition & 1 deletion docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ Version 1.9.0 (not released yet)
- Make value of `spectate_mode_minimal_ui` persist between game launches
- Add `version` command
- Add `gore_level` command
- Add gibbing at gore level 2 when enemies die from explosives
- 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
114 changes: 71 additions & 43 deletions game_patch/object/entity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -203,60 +203,89 @@ CodeInjection entity_process_pre_hide_riot_shield_injection{
},
};

// avoids gibbing if gore level is too low or if this specific corpse shouldn't gib
CodeInjection corpse_damage_patch{
0x00417C6A,
[](auto& regs) {
rf::Corpse* cp = regs.esi;

if (rf::game_get_gore_level() < 2 ||
cp->corpse_flags & 0x400 || // drools_slime (used by snakes)
cp->corpse_flags & 0x4) // custom_state_anim (used by sea creature)
{
regs.eip = 0x00417C97;
}
}
};

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

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

int explode_vclip_index = rf::vclip_lookup("bloodsplat");
int chunk_explode_vclip_index = rf::vclip_lookup("bloodsplat");
float explode_vclip_radius = 1.0f;
const char* debris_filename = "df_meatchunks0.V3D";

static const int debris_max_lifetime = 7000; // ms
static const float debris_velocity = 8.5f;
static const float damage_scale = 1.0f;
static rf::String cust_snd_set = "gib bounce";

if (objp->type == rf::OT_ENTITY) { // use overrides from associated entity.tbl class if present
rf::Entity* ep = static_cast<rf::Entity*>(objp);

explode_vclip_index = (ep->info->explode_vclip_index > 0)
? ep->info->explode_vclip_index : explode_vclip_index;

explode_vclip_radius = (ep->info->explode_vclip_radius > 0.0f)
? ep->info->explode_vclip_radius : explode_vclip_radius;

debris_filename = (!ep->info->debris_filename.empty())
? ep->info->debris_filename.c_str() : debris_filename;
// only gib flesh entities and corpses
if (!objp || (objp->type != rf::OT_ENTITY && objp->type != rf::OT_CORPSE) || objp->material != 3) {
return;
}
else if (objp->type != rf::OT_CORPSE) { // do not gib anything except entities and corpses

// 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;
}

rf::game_do_explosion(
explode_vclip_index, objp->room, 0, &objp->pos, explode_vclip_radius, damage_scale, 0);
// 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;
}

rf::debris_spawn_from_object(
objp, debris_filename, chunk_explode_vclip_index, debris_max_lifetime, debris_velocity, &cust_snd_set);
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;
}
}
}
};

Expand Down Expand Up @@ -335,7 +364,6 @@ void entity_do_patch()
entity_process_pre_hide_riot_shield_injection.install();

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

// Commands
Expand Down
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
39 changes: 36 additions & 3 deletions 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 @@ -135,8 +168,8 @@ namespace rf

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

static auto& debris_spawn_from_object = addr_as_ref<void(Object* objp, const char* debris_v3d_filename,
int explode_index, int max_lifetime_ms, float velocity, rf::String* cust_snd_set)>(0x004133C0);
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
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
8 changes: 6 additions & 2 deletions resources/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +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/df_gore1.tga
images/gore1.tga
images/enviro0_1.tga
images/enviro10_1.tga
images/enviro20_1.tga
Expand Down Expand Up @@ -88,7 +88,11 @@ add_packfile(dashfaction.vpp
meshes/Vat1.v3m
meshes/coffeesmokedtbl2.v3m
meshes/coffeesmokedtblAlt.v3m
meshes/df_meatchunks0.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
File renamed without changes.
2 changes: 1 addition & 1 deletion resources/licensing-info.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Chris "Goober" Parsons:
* HUD textures for the big mode
* symbol glyphs in ttf fonts
* launcher header
* texture and mesh for gibs
* texture for gibs

natalie <[email protected]>:
* code contributions
Expand Down
1 change: 1 addition & 0 deletions resources/maps_df.txt
Original file line number Diff line number Diff line change
Expand Up @@ -450,3 +450,4 @@ data\maps\textures\damage\OilDrum_Debris.tga
data\maps\textures\damage\genericdebris01.tga
data\maps\textures\damage\offtablenew01_debris.tga
data\maps\textures\trim\damage.tga
data\maps\textures\gore\gore1.tga
Binary file removed resources/meshes/df_meatchunks0.v3m
Binary file not shown.
Binary file added resources/meshes/meatchunk1.v3m
Binary file not shown.
Binary file added resources/meshes/meatchunk2.v3m
Binary file not shown.
Binary file added resources/meshes/meatchunk3.v3m
Binary file not shown.
Binary file added resources/meshes/meatchunk4.v3m
Binary file not shown.
Binary file added resources/meshes/meatchunk5.v3m
Binary file not shown.

0 comments on commit 7306bea

Please sign in to comment.