diff --git a/.gitignore b/.gitignore index 5761abc..9d22eb4 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ *.o +*.so diff --git a/libretro/libretro.c b/libretro/libretro.c index 5659d72..f68d93f 100644 --- a/libretro/libretro.c +++ b/libretro/libretro.c @@ -194,6 +194,68 @@ static gamepad_layout_t gp_modern = { // Based on Original XBOX Doom 3 Collectio 16, }; +static struct retro_rumble_interface rumble = {0}; +static bool rumble_enabled = false; +static uint16_t rumble_damage_strength = 0; +static int16_t rumble_damage_counter = -1; +static uint16_t rumble_touch_strength = 0; +static int16_t rumble_touch_counter = -1; + +void retro_set_rumble_damage(int damage, float duration) +{ + /* Rumble scales linearly from 0xFFF to 0xFFFF + * as damage increases from 1 to 80 */ + int capped_damage = (damage < 80) ? damage : 80; + uint16_t strength = 0; + + if (!rumble.set_rumble_state || + (!rumble_enabled && (capped_damage > 0))) + return; + + if ((capped_damage > 0) && (duration > 0.0f)) + { + strength = 0xFFF + (capped_damage * 0x300); + rumble_damage_counter = (int16_t)((duration * (float)tic_vars.fps / 1000.0f) + 1.0f); + } + + /* Return early if: + * - strength and last set value are both zero + * - strength is greater than zero but less than + * (or equal to) last set value */ + if (((strength == 0) && (rumble_damage_strength == 0)) || + ((strength > 0) && (strength <= rumble_damage_strength))) + return; + + rumble.set_rumble_state(0, RETRO_RUMBLE_STRONG, strength); + rumble_damage_strength = strength; +} + +void retro_set_rumble_touch(unsigned intensity, float duration) +{ + /* Rumble scales linearly from 0x1FE to 0xFFFF + * as intensity increases from 1 to 20 */ + unsigned capped_intensity = (intensity < 20) ? intensity : 20; + uint16_t strength = 0; + + if (!rumble.set_rumble_state || + (!rumble_enabled && (capped_intensity > 0))) + return; + + if ((capped_intensity > 0) && (duration > 0.0f)) + { + strength = 0x1FE + (capped_intensity * 0xCB3); + rumble_touch_counter = (int16_t)((duration * (float)tic_vars.fps / 1000.0f) + 1.0f); + } + + /* Return early if strength matches last + * set value */ + if (strength == rumble_touch_strength) + return; + + rumble.set_rumble_state(0, RETRO_RUMBLE_WEAK, strength); + rumble_touch_strength = strength; +} + char* FindFileInDir(const char* dir, const char* wfname, const char* ext); static void check_system_specs(void) @@ -227,7 +289,18 @@ void retro_init(void) void retro_deinit(void) { D_DoomDeinit(); + libretro_supports_bitmasks = false; + + retro_set_rumble_damage(0, 0.0f); + retro_set_rumble_touch(0, 0.0f); + + memset(&rumble, 0, sizeof(struct retro_rumble_interface)); + rumble_enabled = false; + rumble_damage_strength = 0; + rumble_damage_counter = -1; + rumble_touch_strength = 0; + rumble_touch_counter = -1; } unsigned retro_api_version(void) @@ -450,12 +523,23 @@ static void update_variables(bool startup) find_recursive_on = false; } + var.key = "prboom-rumble"; + var.value = NULL; + rumble_enabled = false; + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + if (!strcmp(var.value, "enabled")) + rumble_enabled = true; + + if (!rumble_enabled) + { + retro_set_rumble_damage(0, 0.0f); + retro_set_rumble_touch(0, 0.0f); + } + var.key = "prboom-analog_deadzone"; var.value = NULL; if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) - { - analog_deadzone = (int)(atoi(var.value) * 0.01f * ANALOG_RANGE); - } + analog_deadzone = (int)(atoi(var.value) * 0.01f * ANALOG_RANGE); } void I_SafeExit(int rc); @@ -473,6 +557,22 @@ void retro_run(void) } D_DoomLoop(); I_UpdateSound(); + + if (rumble_damage_counter > -1) + { + rumble_damage_counter--; + + if (rumble_damage_counter == 0) + retro_set_rumble_damage(0, 0.0f); + } + + if (rumble_touch_counter > -1) + { + rumble_touch_counter--; + + if (rumble_touch_counter == 0) + retro_set_rumble_touch(0, 0.0f); + } } static void extract_basename(char *buf, const char *path, size_t size) @@ -550,6 +650,14 @@ bool retro_load_game(const struct retro_game_info *info) int argc = 0; static char *argv[32] = {NULL}; + if (environ_cb(RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE, &rumble)) + { + if (log_cb) + log_cb(RETRO_LOG_INFO, "Rumble environment supported.\n"); + } + else if (log_cb) + log_cb(RETRO_LOG_INFO, "Rumble environment not supported.\n"); + update_variables(true); argv[argc++] = strdup("prboom"); diff --git a/libretro/libretro_core_options.h b/libretro/libretro_core_options.h index 82280a9..e764703 100644 --- a/libretro/libretro_core_options.h +++ b/libretro/libretro_core_options.h @@ -32,10 +32,10 @@ struct retro_core_option_definition option_defs_us[] = { "Internal resolution (restart)", "Configure the resolution. Requires a restart.", { - { "320x200", NULL }, - { "640x400", NULL }, - { "960x600", NULL }, - { "1280x800", NULL }, + { "320x200", NULL }, + { "640x400", NULL }, + { "960x600", NULL }, + { "1280x800", NULL }, { "1600x1000", NULL }, { "1920x1200", NULL }, { "2240x1400", NULL }, @@ -49,8 +49,8 @@ struct retro_core_option_definition option_defs_us[] = { "Mouse active when using Gamepad", "Allows you to use mouse inputs even when User 1's device type isn't set to 'RetroKeyboard/Mouse'.", { - { "disabled", "Disabled"}, - { "enabled", "Enabled"}, + { "disabled", NULL }, + { "enabled", NULL }, { NULL, NULL }, }, "disabled" @@ -60,21 +60,32 @@ struct retro_core_option_definition option_defs_us[] = { "Look on parent folders for IWADs", "Scans parent folders for IWADs. NOTE: You need to disable this if you want to run SIGIL.", { - { "disabled", "Disabled" }, - { "enabled", "Enabled" }, + { "disabled", NULL }, + { "enabled", NULL }, { NULL, NULL }, }, "enabled" }, + { + "prboom-rumble", + "Rumble Effects", + "Enables haptic feedback when using a rumble-equipped gamepad.", + { + { "disabled", NULL }, + { "enabled", NULL }, + { NULL, NULL }, + }, + "disabled" + }, { "prboom-analog_deadzone", "Analog Deadzone (percent)", - "Sets the deadzone of the Gamepad analog sticks when the input device type is set to 'Gamepad Modern'.", + "Sets the deadzone of the gamepad analog sticks when the input device type is set to 'Gamepad Modern'.", { { "0", NULL }, { "5", NULL }, - { "10", NULL }, - { "15", NULL }, + { "10", NULL }, + { "15", NULL }, { "20", NULL }, { "25", NULL }, { "30", NULL }, diff --git a/src/p_enemy.c b/src/p_enemy.c index f80a920..b1efc32 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -68,6 +68,8 @@ typedef enum static void P_NewChaseDir(mobj_t *actor); void P_ZBumpCheck(mobj_t *); // phares +extern void retro_set_rumble_damage(int damage, float duration); + // // ENEMY THINKING // Enemies are allways spawned @@ -2108,6 +2110,7 @@ void A_Fall(mobj_t *actor) void A_Explode(mobj_t *thingy) { P_RadiusAttack( thingy, thingy->target, 128 ); + retro_set_rumble_damage(60, 500.f); } // @@ -2546,6 +2549,7 @@ void A_Die(mobj_t *actor) void A_Detonate(mobj_t *mo) { P_RadiusAttack(mo, mo->target, mo->info->damage); + retro_set_rumble_damage(60, 500.f); } // diff --git a/src/p_inter.c b/src/p_inter.c index 7c0d929..8f3784b 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -288,6 +288,8 @@ boolean P_GivePower(player_t *player, int power) // P_TouchSpecialThing // +extern void retro_set_rumble_touch(unsigned intensity, float duration); + void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher) { player_t *player; @@ -314,12 +316,14 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher) if (!P_GiveArmor (player, green_armor_class)) return; player->message = s_GOTARMOR; // Ty 03/22/98 - externalized + retro_set_rumble_touch(12, 160.0f); break; case SPR_ARM2: if (!P_GiveArmor (player, blue_armor_class)) return; player->message = s_GOTMEGA; // Ty 03/22/98 - externalized + retro_set_rumble_touch(14, 160.0f); break; // bonus items @@ -329,6 +333,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher) player->health = (maxhealth * 2); player->mo->health = player->health; player->message = s_GOTHTHBONUS; // Ty 03/22/98 - externalized + retro_set_rumble_touch(5, 160.0f); break; case SPR_BON2: @@ -338,6 +343,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher) if (!player->armortype) player->armortype = green_armor_class; player->message = s_GOTARMBONUS; // Ty 03/22/98 - externalized + retro_set_rumble_touch(5, 160.0f); break; case SPR_SOUL: @@ -347,6 +353,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher) player->mo->health = player->health; player->message = s_GOTSUPER; // Ty 03/22/98 - externalized sound = sfx_getpow; + retro_set_rumble_touch(14, 160.0f); break; case SPR_MEGA: @@ -357,6 +364,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher) P_GiveArmor (player,blue_armor_class); player->message = s_GOTMSPHERE; // Ty 03/22/98 - externalized sound = sfx_getpow; + retro_set_rumble_touch(16, 160.0f); break; // cards @@ -365,6 +373,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher) if (!player->cards[it_bluecard]) player->message = s_GOTBLUECARD; // Ty 03/22/98 - externalized P_GiveCard (player, it_bluecard); + retro_set_rumble_touch(7, 150.0f); if (!netgame) break; return; @@ -373,6 +382,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher) if (!player->cards[it_yellowcard]) player->message = s_GOTYELWCARD; // Ty 03/22/98 - externalized P_GiveCard (player, it_yellowcard); + retro_set_rumble_touch(7, 150.0f); if (!netgame) break; return; @@ -381,6 +391,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher) if (!player->cards[it_redcard]) player->message = s_GOTREDCARD; // Ty 03/22/98 - externalized P_GiveCard (player, it_redcard); + retro_set_rumble_touch(7, 150.0f); if (!netgame) break; return; @@ -389,6 +400,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher) if (!player->cards[it_blueskull]) player->message = s_GOTBLUESKUL; // Ty 03/22/98 - externalized P_GiveCard (player, it_blueskull); + retro_set_rumble_touch(8, 150.0f); if (!netgame) break; return; @@ -397,6 +409,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher) if (!player->cards[it_yellowskull]) player->message = s_GOTYELWSKUL; // Ty 03/22/98 - externalized P_GiveCard (player, it_yellowskull); + retro_set_rumble_touch(8, 150.0f); if (!netgame) break; return; @@ -405,6 +418,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher) if (!player->cards[it_redskull]) player->message = s_GOTREDSKULL; // Ty 03/22/98 - externalized P_GiveCard (player, it_redskull); + retro_set_rumble_touch(8, 150.0f); if (!netgame) break; return; @@ -414,6 +428,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher) if (!P_GiveBody (player, 10)) return; player->message = s_GOTSTIM; // Ty 03/22/98 - externalized + retro_set_rumble_touch(6, 160.0f); break; case SPR_MEDI: @@ -424,6 +439,8 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher) player->message = s_GOTMEDINEED; // Ty 03/22/98 - externalized else player->message = s_GOTMEDIKIT; // Ty 03/22/98 - externalized + + retro_set_rumble_touch(8, 160.0f); break; @@ -433,6 +450,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher) return; player->message = s_GOTINVUL; // Ty 03/22/98 - externalized sound = sfx_getpow; + retro_set_rumble_touch(18, 160.0f); break; case SPR_PSTR: @@ -442,6 +460,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher) if (player->readyweapon != WP_FIST) player->pendingweapon = WP_FIST; sound = sfx_getpow; + retro_set_rumble_touch(20, 180.0f); break; case SPR_PINS: @@ -449,6 +468,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher) return; player->message = s_GOTINVIS; // Ty 03/22/98 - externalized sound = sfx_getpow; + retro_set_rumble_touch(18, 160.0f); break; case SPR_SUIT: @@ -456,6 +476,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher) return; player->message = s_GOTSUIT; // Ty 03/22/98 - externalized sound = sfx_getpow; + retro_set_rumble_touch(18, 160.0f); break; case SPR_PMAP: @@ -463,6 +484,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher) return; player->message = s_GOTMAP; // Ty 03/22/98 - externalized sound = sfx_getpow; + retro_set_rumble_touch(18, 160.0f); break; case SPR_PVIS: @@ -470,6 +492,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher) return; player->message = s_GOTVISOR; // Ty 03/22/98 - externalized sound = sfx_getpow; + retro_set_rumble_touch(18, 160.0f); break; // ammo @@ -485,48 +508,57 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher) return; } player->message = s_GOTCLIP; // Ty 03/22/98 - externalized + + retro_set_rumble_touch(6, 140.0f); break; case SPR_AMMO: if (!P_GiveAmmo (player, AM_CLIP,5)) return; player->message = s_GOTCLIPBOX; // Ty 03/22/98 - externalized + retro_set_rumble_touch(8, 140.0f); break; case SPR_ROCK: if (!P_GiveAmmo (player, AM_MISL,1)) return; player->message = s_GOTROCKET; // Ty 03/22/98 - externalized + retro_set_rumble_touch(6, 140.0f); break; case SPR_BROK: if (!P_GiveAmmo (player, AM_MISL,5)) return; player->message = s_GOTROCKBOX; // Ty 03/22/98 - externalized + retro_set_rumble_touch(8, 140.0f); break; case SPR_CELL: if (!P_GiveAmmo (player, AM_CELL,1)) return; player->message = s_GOTCELL; // Ty 03/22/98 - externalized + retro_set_rumble_touch(6, 140.0f); break; case SPR_CELP: if (!P_GiveAmmo (player, AM_CELL,5)) return; player->message = s_GOTCELLBOX; // Ty 03/22/98 - externalized + retro_set_rumble_touch(8, 140.0f); break; case SPR_SHEL: if (!P_GiveAmmo (player, AM_SHELL,1)) return; player->message = s_GOTSHELLS; // Ty 03/22/98 - externalized + retro_set_rumble_touch(6, 140.0f); break; case SPR_SBOX: if (!P_GiveAmmo (player, AM_SHELL,5)) return; player->message = s_GOTSHELLBOX; // Ty 03/22/98 - externalized + retro_set_rumble_touch(8, 140.0f); break; case SPR_BPAK: @@ -539,6 +571,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher) for (i=0 ; imessage = s_GOTBACKPACK; // Ty 03/22/98 - externalized + retro_set_rumble_touch(12, 160.0f); break; // weapons @@ -547,6 +580,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher) return; player->message = s_GOTBFG9000; // Ty 03/22/98 - externalized sound = sfx_wpnup; + retro_set_rumble_touch(20, 180.0f); break; case SPR_MGUN: @@ -554,6 +588,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher) return; player->message = s_GOTCHAINGUN; // Ty 03/22/98 - externalized sound = sfx_wpnup; + retro_set_rumble_touch(15, 180.0f); break; case SPR_CSAW: @@ -561,6 +596,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher) return; player->message = s_GOTCHAINSAW; // Ty 03/22/98 - externalized sound = sfx_wpnup; + retro_set_rumble_touch(15, 180.0f); break; case SPR_LAUN: @@ -568,6 +604,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher) return; player->message = s_GOTLAUNCHER; // Ty 03/22/98 - externalized sound = sfx_wpnup; + retro_set_rumble_touch(18, 180.0f); break; case SPR_PLAS: @@ -575,6 +612,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher) return; player->message = s_GOTPLASMA; // Ty 03/22/98 - externalized sound = sfx_wpnup; + retro_set_rumble_touch(17, 180.0f); break; case SPR_SHOT: @@ -582,6 +620,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher) return; player->message = s_GOTSHOTGUN; // Ty 03/22/98 - externalized sound = sfx_wpnup; + retro_set_rumble_touch(14, 180.0f); break; case SPR_SGN2: @@ -589,6 +628,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher) return; player->message = s_GOTSHOTGUN2; // Ty 03/22/98 - externalized sound = sfx_wpnup; + retro_set_rumble_touch(16, 180.0f); break; default: diff --git a/src/p_pspr.c b/src/p_pspr.c index f3fe711..625c085 100644 --- a/src/p_pspr.c +++ b/src/p_pspr.c @@ -54,6 +54,8 @@ extern void P_Thrust(player_t *, angle_t, fixed_t); +extern void retro_set_rumble_damage(int damage, float duration); + // The following array holds the recoil values // phares static const int recoil_values[] = { // phares @@ -669,6 +671,8 @@ void A_Punch(player_t *player, pspdef_t *psp) player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, linetarget->x, linetarget->y); R_SmoothPlaying_Reset(player); // e6y + + retro_set_rumble_damage(30, 120.0f); } // @@ -718,6 +722,8 @@ void A_Saw(player_t *player, pspdef_t *psp) player->mo->flags |= MF_JUSTATTACKED; R_SmoothPlaying_Reset(player); // e6y + + retro_set_rumble_damage(40, 120.0f); } // @@ -728,6 +734,7 @@ void A_FireMissile(player_t *player, pspdef_t *psp) { player->ammo[weaponinfo[player->readyweapon].ammo]--; P_SpawnPlayerMissile(player->mo, MT_ROCKET); + retro_set_rumble_damage(50, 120.0f); } // @@ -738,6 +745,7 @@ void A_FireBFG(player_t *player, pspdef_t *psp) { player->ammo[weaponinfo[player->readyweapon].ammo] -= BFGCELLS; P_SpawnPlayerMissile(player->mo, MT_BFG); + retro_set_rumble_damage(50, 120.0f); } // @@ -802,6 +810,7 @@ void A_FireOldBFG(player_t *player, pspdef_t *psp) P_CheckMissileSpawn(th); } while ((type != MT_PLASMA2) && (type = MT_PLASMA2)); //killough: obfuscated! // lgtm[cpp/assign-where-compare-meant] + retro_set_rumble_damage(50, 120.0f); } // @@ -814,6 +823,7 @@ void A_FirePlasma(player_t *player, pspdef_t *psp) A_FireSomething(player,P_Random(pr_plasma)&1); // phares P_SpawnPlayerMissile(player->mo, MT_PLASMA); + retro_set_rumble_damage(50, 120.0f); } // @@ -874,6 +884,8 @@ void A_FirePistol(player_t *player, pspdef_t *psp) A_FireSomething(player,0); // phares P_BulletSlope(player->mo); P_GunShot(player->mo, !player->refire); + + retro_set_rumble_damage(30, 120.0f); } // @@ -895,6 +907,8 @@ void A_FireShotgun(player_t *player, pspdef_t *psp) for (i=0; i<7; i++) P_GunShot(player->mo, false); + + retro_set_rumble_damage(40, 120.0f); } // @@ -924,6 +938,8 @@ void A_FireShotgun2(player_t *player, pspdef_t *psp) P_LineAttack(player->mo, angle, MISSILERANGE, bulletslope + ((t - P_Random(pr_shotgun))<<5), damage); } + + retro_set_rumble_damage(40, 120.0f); } // @@ -946,6 +962,8 @@ void A_FireCGun(player_t *player, pspdef_t *psp) P_BulletSlope(player->mo); P_GunShot(player->mo, !player->refire); + + retro_set_rumble_damage(10, 120.0f); } #ifdef HEXEN diff --git a/src/p_switch.c b/src/p_switch.c index ac36a5b..e875d17 100644 --- a/src/p_switch.c +++ b/src/p_switch.c @@ -220,6 +220,9 @@ static void P_StartButton // // No return // + +extern void retro_set_rumble_touch(unsigned intensity, float duration); + void P_ChangeSwitchTexture ( line_t* line, int useAgain ) @@ -280,6 +283,8 @@ void P_ChangeSwitchTexture if (useAgain) P_StartButton(line, position, switchlist[i], BUTTONTIME); + + retro_set_rumble_touch(12, 200.0f); } diff --git a/src/st_stuff.c b/src/st_stuff.c index 6b75aca..14d8377 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -360,6 +360,9 @@ static int st_fragscount; // used to use appopriately pained face static int st_oldhealth = -1; +// used to track armour reduction +static int st_oldarmour = -1; + // used for evil grin static boolean oldweaponsowned[NUMWEAPONS]; @@ -697,12 +700,28 @@ static void ST_updateWidgets(void) } +extern void retro_set_rumble_damage(int damage, float duration); + void ST_Ticker(void) { st_clock++; st_randomnumber = M_Random(); ST_updateWidgets(); + + /* If player has taken damage, trigger a + * rumble effect */ + if (st_oldhealth > plyr->health) + { + int damage = st_oldhealth - plyr->health; + /* Add any armour damage */ + if (st_oldarmour > plyr->armorpoints) + damage += st_oldarmour - plyr->armorpoints; + + retro_set_rumble_damage(damage, 333.3333f); + } + st_oldhealth = plyr->health; + st_oldarmour = plyr->armorpoints; } int st_palette = 0;