From a91c8254815f56c65e195eda99edf610b391e037 Mon Sep 17 00:00:00 2001 From: William Emfinger Date: Thu, 1 May 2025 16:26:04 -0500 Subject: [PATCH 1/7] feat(doom): Add haptic support to doom * Update doom to have callbacks for when the player is damaged and when they fire a weapon * Update doom implementation to trigger different haptic effects depending on the weapon fired and the amount of damage taken Haptics are awesome, and with doom we have the actual source code so we can do some fun stuff :) Build and run `main` on Box-Emu v0 which has haptics and ensure it feels good. --- components/doom/prboom/p_inter.c | 11 +++++++++- components/doom/prboom/p_pspr.c | 6 ++++++ components/doom/prboom/r_main.h | 17 ++++++++++++++++ components/doom/src/doom.cpp | 35 ++++++++++++++++++++++++++++++++ components/gui/include/gui.hpp | 4 ++++ main/main.cpp | 1 + 6 files changed, 73 insertions(+), 1 deletion(-) diff --git a/components/doom/prboom/p_inter.c b/components/doom/prboom/p_inter.c index be4341b..8d919d5 100644 --- a/components/doom/prboom/p_inter.c +++ b/components/doom/prboom/p_inter.c @@ -808,9 +808,10 @@ void P_DamageMobj(mobj_t *target,mobj_t *inflictor, mobj_t *source, int damage) (player->cheats&CF_GODMODE || player->powers[pw_invulnerability])) return; + int saved = 0; if (player->armortype) { - int saved = player->armortype == 1 ? damage/3 : damage/2; + saved = player->armortype == 1 ? damage/3 : damage/2; if (player->armorpoints <= saved) { // armor is used up @@ -825,6 +826,14 @@ void P_DamageMobj(mobj_t *target,mobj_t *inflictor, mobj_t *source, int damage) if (player->health < 0) player->health = 0; + // [WILLIAM]: trigger haptic effect for the player getting injured based + // on the amount of damage received (armor/base). Use damage + // (hits to health) and saved (hits to armor) to determine. + // + // printf("Player %d took %d damage (%d saved)\n", + // player - players, damage, saved); + R_PlayerHurt(player, damage, saved); + player->attacker = source; player->damagecount += damage; // add damage after armor / invuln diff --git a/components/doom/prboom/p_pspr.c b/components/doom/prboom/p_pspr.c index 8b4579e..bb59de3 100644 --- a/components/doom/prboom/p_pspr.c +++ b/components/doom/prboom/p_pspr.c @@ -282,6 +282,12 @@ static void P_FireWeapon(player_t *player) newstate = weaponinfo[player->readyweapon].atkstate; P_SetPsprite(player, ps_weapon, newstate); P_NoiseAlert(player->mo, player->mo); + // [WILLIAM]: trigger haptic effect for firing the weapon based on the + // weaponinfo[player->readyweapon]. player->readyweapon is the + // weapon enum (e.g. 0 is fist, 1 is gun, 2 is shotgun, etc.). + // + // printf("P_FireWeapon: %d\n", player->readyweapon); + R_PlayerFire(player); } // diff --git a/components/doom/prboom/r_main.h b/components/doom/prboom/r_main.h index 89a36ee..ccf4c8d 100644 --- a/components/doom/prboom/r_main.h +++ b/components/doom/prboom/r_main.h @@ -117,4 +117,21 @@ void R_Init(void); // Called by startup code. void R_SetViewSize(int blocks); // Called by M_Responder. void R_ExecuteSetViewSize(void); // cph - called by D_Display to complete a view resize +// +// HAPTICS - functions to call for various events that should trigger haptics +// + +// called when the player fires a weapon, can get player->readyweapon to know +// which weapon to use for the haptic feedback +void R_PlayerFire(player_t *player); + +// called when the player picks up a weapon, can get player->readyweapon to know +// which weapon +void R_PlayerPickupWeapon(player_t *player); + +// called when the player is hurt. damage is the amount of health lost, saved is +// the amount of health saved by armor (which is the same as the amount of armor +// lost) +void R_PlayerHurt(player_t *player, int damage, int saved); + #endif diff --git a/components/doom/src/doom.cpp b/components/doom/src/doom.cpp index f080672..bfe02cb 100644 --- a/components/doom/src/doom.cpp +++ b/components/doom/src/doom.cpp @@ -96,6 +96,41 @@ extern "C" { {(int)GamepadState::Button::Y, &key_weapontoggle}, }; + void R_PlayerFire(player_t *player) { + static auto& box = BoxEmu::get(); + int haptic_effect_index = 0; + int weapon_fired = player->readyweapon; + if (weapon_fired == wp_fist) { + haptic_effect_index = 3; + } else if (weapon_fired == wp_pistol) { + haptic_effect_index = 2; + } else if (weapon_fired == wp_shotgun) { + haptic_effect_index = 10; + } else if (weapon_fired == wp_chaingun) { + haptic_effect_index = 12; + } else if (weapon_fired == wp_missile) { + haptic_effect_index = 27; + } else if (weapon_fired == wp_plasma) { + haptic_effect_index = 14; + } else if (weapon_fired == wp_bfg) { + haptic_effect_index = 47; + } else if (weapon_fired == wp_supershotgun) { + haptic_effect_index = 52; + } + box.play_haptic_effect(haptic_effect_index); + } + + void R_PlayerHurt(player_t *player, int damage, int saved) { + static auto& box = BoxEmu::get(); + int haptic_effect_index = 0; + if (damage > 5) { + haptic_effect_index = saved > 0 ? 70 : 75; + } else if (damage > 0) { + haptic_effect_index = saved > 0 ? 78 : 64; + } + box.play_haptic_effect(haptic_effect_index); + } + void I_StartFrame(void) { } diff --git a/components/gui/include/gui.hpp b/components/gui/include/gui.hpp index 1294f19..eb6b35d 100644 --- a/components/gui/include/gui.hpp +++ b/components/gui/include/gui.hpp @@ -103,6 +103,10 @@ class Gui { paused_ = false; } + int get_haptic_waveform() const { + return haptic_waveform_; + } + void set_haptic_waveform(int new_waveform) { if (new_waveform > 123) { new_waveform = 1; diff --git a/main/main.cpp b/main/main.cpp index 963d3c9..25f3372 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -88,6 +88,7 @@ extern "C" void app_main(void) { } // have broken out of the loop, let the user know we're processing... + emu.set_haptic_effect(gui.get_haptic_waveform()); emu.play_haptic_effect(); gui.pause(); From 88ecb3f7f5c32c2dc63c7ad13aac805ce990ee34 Mon Sep 17 00:00:00 2001 From: William Emfinger Date: Thu, 1 May 2025 16:33:39 -0500 Subject: [PATCH 2/7] fix sa --- components/doom/src/doom.cpp | 2 +- components/msx/src/msx.cpp | 2 -- components/pool_allocator/include/pool_allocator.h | 2 +- components/pool_allocator/src/pool_allocator.c | 2 +- components/shared_memory/src/shared_memory.c | 2 +- main/cart.hpp | 6 +++--- 6 files changed, 7 insertions(+), 9 deletions(-) diff --git a/components/doom/src/doom.cpp b/components/doom/src/doom.cpp index bfe02cb..386ee94 100644 --- a/components/doom/src/doom.cpp +++ b/components/doom/src/doom.cpp @@ -279,7 +279,7 @@ extern "C" { if (haveSFX) { int16_t *audioBuffer = (int16_t *)mixbuffer; - int16_t *audioBufferEnd = audioBuffer + AUDIO_BUFFER_LENGTH; + const int16_t *audioBufferEnd = audioBuffer + AUDIO_BUFFER_LENGTH; while (audioBuffer < audioBufferEnd) { int totalSample = 0; int totalSources = 0; diff --git a/components/msx/src/msx.cpp b/components/msx/src/msx.cpp index a24bcad..1a03ce3 100644 --- a/components/msx/src/msx.cpp +++ b/components/msx/src/msx.cpp @@ -274,8 +274,6 @@ void TrashMachine(void) void SetColor(byte N, byte R, byte G, byte B) { uint16_t color = make_color(R, G, B); - // color = (color >> 8) | (color << 8); - color = color; if (N) XPal[N] = color; else diff --git a/components/pool_allocator/include/pool_allocator.h b/components/pool_allocator/include/pool_allocator.h index 86ec5d4..70a6069 100644 --- a/components/pool_allocator/include/pool_allocator.h +++ b/components/pool_allocator/include/pool_allocator.h @@ -16,7 +16,7 @@ extern "C" { void pool_create(void* region, size_t size); void pool_destroy(); -int pool_contains(void* ptr); +int pool_contains(const void* ptr); void* pool_alloc(size_t size); void pool_free(void* ptr); diff --git a/components/pool_allocator/src/pool_allocator.c b/components/pool_allocator/src/pool_allocator.c index 96851d3..c6c67eb 100644 --- a/components/pool_allocator/src/pool_allocator.c +++ b/components/pool_allocator/src/pool_allocator.c @@ -28,7 +28,7 @@ void pool_create(void* mem, size_t size) { free_list->next = NULL; } -int pool_contains(void* ptr) { +int pool_contains(const void* ptr) { return (ptr >= memory_pool && ptr < memory_pool + memory_pool_size); } diff --git a/components/shared_memory/src/shared_memory.c b/components/shared_memory/src/shared_memory.c index a7457c7..94a1b3b 100644 --- a/components/shared_memory/src/shared_memory.c +++ b/components/shared_memory/src/shared_memory.c @@ -69,7 +69,7 @@ void* shared_mem_allocate(const shared_mem_request_t* request) { } void shared_mem_clear(void) { - printf("Num bytes allocated: %d\n", current_offset_); + printf("Num bytes allocated: %d\n", (int)current_offset_); // TODO: Use SIMD-accelerated memset from ESP32s3 vector instructions memset(memory_pool_, 0, TOTAL_MEMORY_SIZE); current_offset_ = 0; diff --git a/main/cart.hpp b/main/cart.hpp index 8d406e4..d198965 100644 --- a/main/cart.hpp +++ b/main/cart.hpp @@ -284,7 +284,7 @@ class Cart { return menu_->get_selected_slot(); } - virtual std::string get_save_path(bool bypass_exist_check=false) const { + std::string get_save_path(bool bypass_exist_check=false) const { namespace fs = std::filesystem; auto save_path = savedir_ + "/" + @@ -297,7 +297,7 @@ class Cart { return ""; } - virtual std::string get_paused_image_path() const { + std::string get_paused_image_path() const { namespace fs = std::filesystem; auto save_path = savedir_ + "/paused" + @@ -305,7 +305,7 @@ class Cart { return save_path; } - virtual std::string get_screenshot_path(bool bypass_exist_check=false) const { + std::string get_screenshot_path(bool bypass_exist_check=false) const { auto save_path = get_save_path(bypass_exist_check); if (!save_path.empty()) { return save_path + get_screenshot_extension(); From 87d7f0efc7897b02754ae89a05fbef0a059fa517 Mon Sep 17 00:00:00 2001 From: William Emfinger Date: Thu, 1 May 2025 16:40:41 -0500 Subject: [PATCH 3/7] improve maintainability --- components/doom/src/doom.cpp | 45 +++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/components/doom/src/doom.cpp b/components/doom/src/doom.cpp index 386ee94..d77abca 100644 --- a/components/doom/src/doom.cpp +++ b/components/doom/src/doom.cpp @@ -21,6 +21,32 @@ static std::unique_ptr audio_task; static const char *doom_argv[10]; +enum class WeaponHaptics : int { + FIST = 3, + PISTOL = 2, + SHOTGUN = 10, + CHAINGUN = 12, + ROCKET_LAUNCHER = 27, + PLASMA_RIFLE = 14, + BFG9000 = 47, + CHAINSAW = 15, + SUPER_SHOTGUN = 52 +}; + +// NOTE: The order of the enum values must match the order of the weapons in the +// game, which is the wp_* enum values defined in doomdef.h +static constexpr int WeaponHapticLookup[] = { + (int)WeaponHaptics::FIST, + (int)WeaponHaptics::PISTOL, + (int)WeaponHaptics::SHOTGUN, + (int)WeaponHaptics::CHAINGUN, + (int)WeaponHaptics::ROCKET_LAUNCHER, + (int)WeaponHaptics::PLASMA_RIFLE, + (int)WeaponHaptics::BFG9000, + (int)WeaponHaptics::CHAINSAW, + (int)WeaponHaptics::SUPER_SHOTGUN +}; + // prboom includes extern "C" { ///////////////////////////////////////////// @@ -98,25 +124,8 @@ extern "C" { void R_PlayerFire(player_t *player) { static auto& box = BoxEmu::get(); - int haptic_effect_index = 0; int weapon_fired = player->readyweapon; - if (weapon_fired == wp_fist) { - haptic_effect_index = 3; - } else if (weapon_fired == wp_pistol) { - haptic_effect_index = 2; - } else if (weapon_fired == wp_shotgun) { - haptic_effect_index = 10; - } else if (weapon_fired == wp_chaingun) { - haptic_effect_index = 12; - } else if (weapon_fired == wp_missile) { - haptic_effect_index = 27; - } else if (weapon_fired == wp_plasma) { - haptic_effect_index = 14; - } else if (weapon_fired == wp_bfg) { - haptic_effect_index = 47; - } else if (weapon_fired == wp_supershotgun) { - haptic_effect_index = 52; - } + int haptic_effect_index = WeaponHapticLookup[weapon_fired]; box.play_haptic_effect(haptic_effect_index); } From 1b43e30e0ba89e987f8d1e2c962a72fe5bc67cf5 Mon Sep 17 00:00:00 2001 From: William Emfinger Date: Thu, 1 May 2025 17:34:48 -0500 Subject: [PATCH 4/7] more haptics --- components/doom/prboom/p_inter.c | 29 +++++++++++++++++++++++ components/doom/prboom/r_main.h | 8 ++++++- components/doom/src/doom.cpp | 40 ++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 1 deletion(-) diff --git a/components/doom/prboom/p_inter.c b/components/doom/prboom/p_inter.c index 8d919d5..db2b6e9 100644 --- a/components/doom/prboom/p_inter.c +++ b/components/doom/prboom/p_inter.c @@ -113,6 +113,11 @@ static boolean P_GiveAmmo(player_t *player, ammotype_t ammo, int num) else num = clipammo[ammo]/2; + // [WILLIAM] - trigger haptic effect for the player picking up ammo + // printf("Player %d picked up ammo %d\n", + // player - players, num); + R_PlayerPickupAmmo(player, ammo, num); + // give double ammo in trainer mode, you'll need in nightmare if (gameskill == sk_baby || gameskill == sk_nightmare) num <<= 1; @@ -210,6 +215,11 @@ static boolean P_GiveWeapon(player_t *player, weapontype_t weapon, boolean dropp gaveweapon = true; player->weaponowned[weapon] = true; player->pendingweapon = weapon; + // [WILLIAM] - trigger haptic effect for the player picking up a weapon + // + // printf("Player %d picked up weapon %d\n", + // player - players, weapon); + R_PlayerPickupWeapon(player, weapon); } return gaveweapon || gaveammo; } @@ -227,6 +237,10 @@ static boolean P_GiveBody(player_t *player, int num) if (player->health > maxhealth) player->health = maxhealth; player->mo->health = player->health; + // [WILLIAM] - trigger haptic effect for the player picking up health + // printf("Player %d picked up health %d\n", + // player - players, num); + R_PlayerPickupHealth(player, num); return true; } @@ -243,6 +257,10 @@ static boolean P_GiveArmor(player_t *player, int armortype) return false; // don't pick up player->armortype = armortype; player->armorpoints = hits; + // [WILLIAM] - trigger haptic effect for the player picking up armor + // printf("Player %d picked up armor %d\n", + // player - players, armortype); + R_PlayerPickupArmor(player, armortype); return true; } @@ -256,6 +274,11 @@ static void P_GiveCard(player_t *player, card_t card) return; player->bonuscount = BONUSADD; player->cards[card] = 1; + + // [WILLIAM] - trigger haptic effect for the player picking up a card + // printf("Player %d picked up card %d\n", + // player - players, card); + R_PlayerPickupCard(player, card); } // @@ -289,6 +312,12 @@ boolean P_GivePower(player_t *player, int power) if (player->powers[power] >= 0) player->powers[power] = tics[power]; + + // [WILLIAM] - trigger haptic effect for the player picking up a powerup + // printf("Player %d picked up powerup %d\n", + // player - players, power); + R_PlayerPickupPowerUp(player, power); + return true; } diff --git a/components/doom/prboom/r_main.h b/components/doom/prboom/r_main.h index ccf4c8d..3525481 100644 --- a/components/doom/prboom/r_main.h +++ b/components/doom/prboom/r_main.h @@ -127,7 +127,13 @@ void R_PlayerFire(player_t *player); // called when the player picks up a weapon, can get player->readyweapon to know // which weapon -void R_PlayerPickupWeapon(player_t *player); +void R_PlayerPickupWeapon(player_t *player, int weapon); + +void R_PlayerPickupAmmo(player_t *player, ammotype_t ammo, int num); +void R_PlayerPickupHealth(player_t *player, int health); +void R_PlayerPickupArmor(player_t *player, int armor); +void R_PlayerPickupCard(player_t *player, card_t card); +void R_PlayerPickupPowerUp(player_t *player, int powerup); // called when the player is hurt. damage is the amount of health lost, saved is // the amount of health saved by armor (which is the same as the amount of armor diff --git a/components/doom/src/doom.cpp b/components/doom/src/doom.cpp index d77abca..c5ff0e6 100644 --- a/components/doom/src/doom.cpp +++ b/components/doom/src/doom.cpp @@ -133,13 +133,53 @@ extern "C" { static auto& box = BoxEmu::get(); int haptic_effect_index = 0; if (damage > 5) { + // 70 - transition ramp down long smooth 1 - 100 to 0% + // 75 - transition ramp down short smooth 2 - 100 to 0% haptic_effect_index = saved > 0 ? 70 : 75; } else if (damage > 0) { + // 78 - transition ramp down medium sharp 1 - 100 to 0% + // 64 - transition hum 100% haptic_effect_index = saved > 0 ? 78 : 64; } box.play_haptic_effect(haptic_effect_index); } + void R_PlayerPickupWeapon(player_t *player, int weapon) { + static auto& box = BoxEmu::get(); + // play 29 (short double click strong 3 - 60%) + box.play_haptic_effect(29); + } + + void R_PlayerPickupAmmo(player_t *player, ammotype_t ammo, int num) { + static auto& box = BoxEmu::get(); + // play 34 (short double sharp tick 1 - 100%) + box.play_haptic_effect(34); + } + + void R_PlayerPickupHealth(player_t *player, int health) { + static auto& box = BoxEmu::get(); + // play 18 (strong click 2 - 80%) + box.play_haptic_effect(18); + } + + void R_PlayerPickupArmor(player_t *player, int armor) { + static auto& box = BoxEmu::get(); + // play 19 (strong click 3 - 60%) + box.play_haptic_effect(19); + } + + void R_PlayerPickupCard(player_t *player, card_t card) { + static auto& box = BoxEmu::get(); + // play 5 (sharp click - 60%) + box.play_haptic_effect(5); + } + + void R_PlayerPickupPowerUp(player_t *player, int powerup) { + static auto& box = BoxEmu::get(); + // play 12 (triple click - 100%) + box.play_haptic_effect(12); + } + void I_StartFrame(void) { } From 06b42ec9cc1256c4364650f6c135d711ef6d0ed4 Mon Sep 17 00:00:00 2001 From: William Emfinger Date: Fri, 2 May 2025 10:35:13 -0500 Subject: [PATCH 5/7] add player interaction haptics and fix sa --- components/doom/prboom/p_inter.c | 4 ++++ components/doom/prboom/p_map.c | 8 +++++--- components/doom/prboom/p_switch.c | 14 +++++++++++--- components/doom/prboom/r_main.h | 2 ++ components/doom/src/doom.cpp | 6 ++++++ components/msx/src/msx.cpp | 1 - 6 files changed, 28 insertions(+), 7 deletions(-) diff --git a/components/doom/prboom/p_inter.c b/components/doom/prboom/p_inter.c index db2b6e9..2a3e27a 100644 --- a/components/doom/prboom/p_inter.c +++ b/components/doom/prboom/p_inter.c @@ -361,6 +361,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher) // bonus items case SPR_BON1: + R_PlayerPickupHealth(player, 1); player->health++; // can go over 100% if (player->health > (maxhealth * 2)) player->health = (maxhealth * 2); @@ -369,6 +370,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher) break; case SPR_BON2: + R_PlayerPickupArmor(player, 1); player->armorpoints++; // can go over 100% if (player->armorpoints > max_armor) player->armorpoints = max_armor; @@ -378,6 +380,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher) break; case SPR_SOUL: + R_PlayerPickupHealth(player, soul_health); player->health += soul_health; if (player->health > max_soul) player->health = max_soul; @@ -389,6 +392,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher) case SPR_MEGA: if (gamemode != commercial) return; + R_PlayerPickupHealth(player, mega_health); player->health = mega_health; player->mo->health = player->health; P_GiveArmor (player,blue_armor_class); diff --git a/components/doom/prboom/p_map.c b/components/doom/prboom/p_map.c index 8db3443..52994d8 100644 --- a/components/doom/prboom/p_map.c +++ b/components/doom/prboom/p_map.c @@ -1727,7 +1727,7 @@ boolean PTR_NoWayTraverse(intercept_t* in) // Looks for special lines in front of the player to activate. // void P_UseLines (player_t* player) - { +{ int angle; fixed_t x1; fixed_t y1; @@ -1749,10 +1749,12 @@ void P_UseLines (player_t* player) // // This added test makes the "oof" sound work on 2s lines -- killough: - if (P_PathTraverse ( x1, y1, x2, y2, PT_ADDLINES, PTR_UseTraverse )) - if (!comp[comp_sound] && !P_PathTraverse ( x1, y1, x2, y2, PT_ADDLINES, PTR_NoWayTraverse )) + if (P_PathTraverse ( x1, y1, x2, y2, PT_ADDLINES, PTR_UseTraverse )) { + if (!comp[comp_sound] && !P_PathTraverse ( x1, y1, x2, y2, PT_ADDLINES, PTR_NoWayTraverse )) { S_StartSound (usething, sfx_noway); + } } +} // diff --git a/components/doom/prboom/p_switch.c b/components/doom/prboom/p_switch.c index 05883fa..aa6220d 100644 --- a/components/doom/prboom/p_switch.c +++ b/components/doom/prboom/p_switch.c @@ -318,9 +318,11 @@ P_UseSpecialLine linefunc = EV_DoGenCrusher; } - if (linefunc) + if (linefunc) { + // [WILLIAM] - Callback to trigger haptics when using a switch + R_PlayerInteract(thing->player, line->special); switch((line->special & TriggerType) >> TriggerTypeShift) - { + { case PushOnce: if (!side) if (linefunc(line)) @@ -340,7 +342,8 @@ P_UseSpecialLine return true; default: // if not a switch/push type, do nothing here return false; - } + } + } } // Switches that other things can activate. @@ -372,6 +375,11 @@ P_UseSpecialLine if (!P_CheckTag(line)) //jff 2/27/98 disallow zero tag on some types return false; + if (thing->player) { + // [WILLIAM] - Callback to trigger haptics when using a switch + R_PlayerInteract(thing->player, line->special); + } + // Dispatch to handler according to linedef type switch (line->special) { diff --git a/components/doom/prboom/r_main.h b/components/doom/prboom/r_main.h index 3525481..0845cdb 100644 --- a/components/doom/prboom/r_main.h +++ b/components/doom/prboom/r_main.h @@ -135,6 +135,8 @@ void R_PlayerPickupArmor(player_t *player, int armor); void R_PlayerPickupCard(player_t *player, card_t card); void R_PlayerPickupPowerUp(player_t *player, int powerup); +void R_PlayerInteract(player_t *player, int special); + // called when the player is hurt. damage is the amount of health lost, saved is // the amount of health saved by armor (which is the same as the amount of armor // lost) diff --git a/components/doom/src/doom.cpp b/components/doom/src/doom.cpp index c5ff0e6..ac8c9e0 100644 --- a/components/doom/src/doom.cpp +++ b/components/doom/src/doom.cpp @@ -144,6 +144,12 @@ extern "C" { box.play_haptic_effect(haptic_effect_index); } + void R_PlayerInteract(player_t *player, int special) { + static auto& box = BoxEmu::get(); + // play 4 (sharp click - 100%) + box.play_haptic_effect(4); + } + void R_PlayerPickupWeapon(player_t *player, int weapon) { static auto& box = BoxEmu::get(); // play 29 (short double click strong 3 - 60%) diff --git a/components/msx/src/msx.cpp b/components/msx/src/msx.cpp index 1a03ce3..d6f7d7e 100644 --- a/components/msx/src/msx.cpp +++ b/components/msx/src/msx.cpp @@ -360,7 +360,6 @@ unsigned int WaitKey(void) // wait no more than 100ms for the user to press any key while (!wait_for_key(GamepadState::Button::ANY, true, 100)) { // wait for key - continue; } return GetKey(); From bc1f6dc6668bce6e8856d04147a024331ddd14af Mon Sep 17 00:00:00 2001 From: William Emfinger Date: Fri, 2 May 2025 10:39:52 -0500 Subject: [PATCH 6/7] update readme --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index 21067ef..c47d902 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,16 @@ ESP32-S3-BOX-3 which provides: - Genesis emulator (gwenesis) - full speed / buttery smooth when muted; unmuted it runs a little slower but has nice sound - Regular Controls (D-Pad/A/B/C/Start/Select) (note: A is mapped to B, B is mapped to A, and C is mapped to Y) - Doom engine (prboom) - full speed with audio and control inputs. A is fire/enter, B is strafe/backspace, X is use, Y is weapontoggle, START is escape, and SELECT is map. + - Added haptic feedback to doom for when the player + - Fires a weapon (depending on the weapon that is fired) + - Receives damage (depending on amount of health / armor damage received) + - Interacts, e.g. with doors + - Picks up a weapon + - Picks up ammo + - Picks up health + - Picks up armor + - Picks up a power up + - Picks up a card / key - LVGL main menu with rom select (including boxart display) and settings page (all generated from Squareline Studio) - LVGL emulation paused menu with save slot select, save slot image display, @@ -122,6 +132,7 @@ This project has the following features (still WIP): - [x] MSX emulator - [x] Sega Mega Drive / Genesis emulator - [x] Doom + - [x] Haptics :rocket: - [ ] Dark Forces (WIP) - [ ] SNES emulator (WIP) - [x] uSD card (FAT) filesystem over SPI From bf46ce7445fa0bae9f0020488e2bccbecac1353f Mon Sep 17 00:00:00 2001 From: William Emfinger Date: Fri, 2 May 2025 10:43:38 -0500 Subject: [PATCH 7/7] Update components/doom/src/doom.cpp Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- components/doom/src/doom.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/components/doom/src/doom.cpp b/components/doom/src/doom.cpp index ac8c9e0..c3c4ea4 100644 --- a/components/doom/src/doom.cpp +++ b/components/doom/src/doom.cpp @@ -125,8 +125,14 @@ extern "C" { void R_PlayerFire(player_t *player) { static auto& box = BoxEmu::get(); int weapon_fired = player->readyweapon; - int haptic_effect_index = WeaponHapticLookup[weapon_fired]; - box.play_haptic_effect(haptic_effect_index); + if (weapon_fired >= 0 && weapon_fired < sizeof(WeaponHapticLookup) / sizeof(WeaponHapticLookup[0])) { + int haptic_effect_index = WeaponHapticLookup[weapon_fired]; + box.play_haptic_effect(haptic_effect_index); + } else { + // Handle invalid weapon index (e.g., log an error or use a default effect) + // For now, we skip playing the haptic effect. + // Example: box.play_haptic_effect(DEFAULT_HAPTIC_EFFECT); + } } void R_PlayerHurt(player_t *player, int damage, int saved) {