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 9 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
1 change: 1 addition & 0 deletions common/include/common/config/GameConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ struct GameConfig
CfgVar<bool> mesh_static_lighting = true;
CfgVar<bool> glares = true;
CfgVar<bool> show_enemy_bullets = true;
CfgVar<bool> gibbing = false;

static constexpr float min_fov = 75.0f;
static constexpr float max_fov = 160.0f;
Expand Down
1 change: 1 addition & 0 deletions common/src/config/GameConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ bool GameConfig::visit_vars(T&& visitor, bool is_save)
result &= visitor(dash_faction_key, "Swap Assault Rifle Controls", swap_assault_rifle_controls);
result &= visitor(dash_faction_key, "Swap Grenade Controls", swap_grenade_controls);
result &= visitor(dash_faction_key, "Glares", glares);
result &= visitor(dash_faction_key, "Gibbing", gibbing);
result &= visitor(dash_faction_key, "Linear Pitch", linear_pitch);
result &= visitor(dash_faction_key, "Show Enemy Bullets", show_enemy_bullets);
result &= visitor(dash_faction_key, "Keep Launcher Open", keep_launcher_open);
Expand Down
1 change: 1 addition & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ Version 1.9.0 (not released yet)
- Add level filename to "Level Initializing" console message
- Properly handle WM_PAINT in dedicated server, may improve performance (DF bug)
- Fix crash when `verify_level` command is run without a level being loaded
- Add gibbing when enemies die from explosives (enable with `toggle_gibs` command)

Version 1.8.0 (released 2022-09-17)
-----------------------------------
Expand Down
11 changes: 11 additions & 0 deletions game_patch/misc/player.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,16 @@ CodeInjection sr_load_player_weapon_anims_injection{
},
};

ConsoleCommand2 toggle_gibs_cmd{
GooberRF marked this conversation as resolved.
Show resolved Hide resolved
"toggle_gibs",
GooberRF marked this conversation as resolved.
Show resolved Hide resolved
[]() {
g_game_config.gibbing = !g_game_config.gibbing;
g_game_config.save();
rf::console::print("Gibbing is {}.", g_game_config.gibbing ? "enabled" : "disabled");
},
"Toggle entities and corpses exploding into chunks from explosives",
};

void player_do_patch()
{
// general hooks
Expand Down Expand Up @@ -349,4 +359,5 @@ void player_do_patch()

// Commands
damage_screen_flash_cmd.register_cmd();
toggle_gibs_cmd.register_cmd();
}
79 changes: 79 additions & 0 deletions game_patch/object/entity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <xlog/xlog.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 +202,79 @@ CodeInjection entity_process_pre_hide_riot_shield_injection{
},
};

FunHook<void(int)> entity_blood_throw_gibs_hook{
0x0042E3C0, [](int handle) {
if (g_game_config.gibbing && !rf::is_multi) {
GooberRF marked this conversation as resolved.
Show resolved Hide resolved
rf::Object* objp = rf::obj_from_handle(handle);

if (!objp) {
return; // invalid object
}

rf::Vector3 pos = objp->pos;
GooberRF marked this conversation as resolved.
Show resolved Hide resolved
rf::GRoom* room = objp->room;
int explosion_vclip = 30;
GooberRF marked this conversation as resolved.
Show resolved Hide resolved
int chunk_explosion_vclip = 30;
float explosion_vclip_radius = 1.0f;
rf::String debris_filename = "df_meatchunks0.V3D";

int debris_max_lifetime = 7000;
GooberRF marked this conversation as resolved.
Show resolved Hide resolved
float debris_velocity = 8.5f;
float damage_scale = 1.0f;
rf::String cust_snd_set = "gib bounce";
GooberRF marked this conversation as resolved.
Show resolved Hide resolved

if (objp->type == rf::OT_ENTITY) {
rf::Entity* ep = static_cast<rf::Entity*>(objp);

explosion_vclip = (ep->info->explode_vclip_index < 0)
GooberRF marked this conversation as resolved.
Show resolved Hide resolved
? ep->info->explode_vclip_index : explosion_vclip;

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

debris_filename = (!ep->info->debris_filename.empty())
GooberRF marked this conversation as resolved.
Show resolved Hide resolved
? ep->info->debris_filename : debris_filename;
}
else if (objp->type = rf::OT_CORPSE) {
GooberRF marked this conversation as resolved.
Show resolved Hide resolved
}
else {
GooberRF marked this conversation as resolved.
Show resolved Hide resolved
return;
}

rf::game_do_explosion(
GooberRF marked this conversation as resolved.
Show resolved Hide resolved
explosion_vclip, room, 0, &pos, explosion_vclip_radius, damage_scale, 0);

rf::debris_spawn_from_object(
objp, debris_filename, chunk_explosion_vclip, debris_max_lifetime, debris_velocity, &cust_snd_set);
}
}
};

CodeInjection entity_damage_explosive_death_injection{
0x0041A413,
[](auto& regs) {
rf::Entity* ep = regs.esi;
if (g_game_config.gibbing && !rf::is_multi && ep) {
int damage_type = regs.ebp;
ep->ai.explosive_last_damage = (damage_type == 3);
if (ep->ai.explosive_last_damage && ep->info->body_temp >= 90.0f) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this body temp check deserve a comment maybe, but still I'm not sure it's a good way to approach this. I've read something that you wanted to check "humanoid" flag but I think it's not necessary a good thing to check. But what about checking if material is flash?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Basing it on body_temp appears, based on my analysis of the stock game files, the only realistic way to ensure this behaves properly in the stock game. The only entities that have body_temp > 90 (and would therefore gib) are humanoid characters and the reeper/baby_reeper. This avoids a situation where entities that have custom death animations and/or are enormous (like the rock snake) but have material flesh are gibbed. body_temp perfectly limits the entities affected in the stock game and provides a very straightforward and sensical way for custom mod authors to make custom entities in their mod compatible with this feature.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For me it's not sensical to depend on some magic number that happens to work for stock game entities and has no other explanation. If what you want is to exclude entities with custom death animations or enormous one why not specify it directly? Body temp field was added with the intention to define color in IR scanners (e.g. railgun), not to determine how entity dies.
You also repeated that condition twice... Please follow DRY principle.

ep->death_anim_index = -1;
GooberRF marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
};

CodeInjection entity_dying_frame_explode_injection{
0x0041EE4C,
[](auto& regs) {
rf::Entity* ep = regs.esi;
if (g_game_config.gibbing && !rf::is_multi && ep && ep->ai.explosive_last_damage &&
GooberRF marked this conversation as resolved.
Show resolved Hide resolved
ep->info->body_temp >= 90.0f) {
regs.eip = 0x0041EE55;
}
},
};

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 +326,9 @@ 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();
entity_damage_explosive_death_injection.install();
entity_dying_frame_explode_injection.install();
}
3 changes: 3 additions & 0 deletions game_patch/rf/ai.h
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,9 @@ namespace rf
float movement_radius;
float movement_height;
bool use_custom_attack_range;
#ifdef DASH_FACTION
bool explosive_last_damage;
GooberRF marked this conversation as resolved.
Show resolved Hide resolved
#endif
float custom_attack_range;
int ai_flags;
};
Expand Down
3 changes: 3 additions & 0 deletions game_patch/rf/entity.h
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,9 @@ namespace rf
static auto& entity_turn_weapon_on = addr_as_ref<void __cdecl(int entity_handle, int weapon_type, bool alt_fire)>(0x0041A870);
static auto& entity_turn_weapon_off = addr_as_ref<void __cdecl(int entity_handle, int weapon_type)>(0x0041AE70);
static auto& entity_restore_mesh = addr_as_ref<void(Entity *ep, const char *mesh_name)>(0x0042C570);
static auto entity_blood_throw_gibs = addr_as_ref<void(int)>(0x0042E3C0);
GooberRF marked this conversation as resolved.
Show resolved Hide resolved
static auto& game_do_explosion = addr_as_ref<void(int vclip, rf::GRoom* src_room, rf::Vector3* src_pos,
GooberRF marked this conversation as resolved.
Show resolved Hide resolved
Vector3* pos, float radius, float damage_scale, rf::Vector3* dir)>(0x00436490);

static auto& entity_list = addr_as_ref<Entity>(0x005CB060);
static auto& local_player_entity = addr_as_ref<Entity*>(0x005CB054);
Expand Down
3 changes: 3 additions & 0 deletions game_patch/rf/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,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_spawn_from_object = addr_as_ref<void __cdecl(rf::Object* objp, const char* debris_v3d_filename,
GooberRF marked this conversation as resolved.
Show resolved Hide resolved
int explode_index, int max_lifetime_ms, float velocity, rf::String* cust_snd_set)>(0x004133C0);
GooberRF marked this conversation as resolved.
Show resolved Hide resolved
}

template<>
Expand Down
2 changes: 2 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/df_gore1.tga
images/enviro0_1.tga
images/enviro10_1.tga
images/enviro20_1.tga
Expand Down Expand Up @@ -87,6 +88,7 @@ add_packfile(dashfaction.vpp
meshes/Vat1.v3m
meshes/coffeesmokedtbl2.v3m
meshes/coffeesmokedtblAlt.v3m
meshes/df_meatchunks0.v3m
GooberRF marked this conversation as resolved.
Show resolved Hide resolved

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/df_gore1.tga
Binary file not shown.
Binary file added resources/meshes/df_meatchunks0.v3m
Binary file not shown.