diff --git a/prboom2/src/d_deh.c b/prboom2/src/d_deh.c index c2226729e..4bdadf16f 100644 --- a/prboom2/src/d_deh.c +++ b/prboom2/src/d_deh.c @@ -1046,7 +1046,7 @@ typedef struct // killough 8/9/98: make DEH_BLOCKMAX self-adjusting #define DEH_BLOCKMAX (sizeof deh_blocks/sizeof*deh_blocks) // size of array #define DEH_MAXKEYLEN 32 // as much of any key as we'll look at -#define DEH_MOBJINFOMAX 25 // number of ints in the mobjinfo_t structure (!) +#define DEH_MOBJINFOMAX 27 // number of mobjinfo configuration keys // Put all the block header values, and the function to be called when that // one is encountered, in this array: @@ -1112,6 +1112,10 @@ static const char *deh_mobjinfo[DEH_MOBJINFOMAX] = "Bits2", // .flags "Respawn frame", // .raisestate "Dropped item", // .droppeditem + + // mbf21 + "Infighting group", // .infighting_group + "Projectile group", // .projectile_group }; // Strings that are used to indicate flags ("Bits" in mobjinfo) @@ -1888,6 +1892,27 @@ static void setMobjInfoValue(int mobjInfoIndex, int keyIndex, uint_64_t value) { } break; case 24: mi->droppeditem = (int)(value-1); return; // make it base zero (deh is 1-based) + + // mbf21 + // custom groups count from the end of the vanilla list + // -> no concern for clashes + case 25: + mi->infighting_group = (int)(value); + if (mi->infighting_group < 0) + { + I_Error("Infighting groups must be >= 0 (check your dehacked)"); + return; + } + mi->infighting_group = mi->infighting_group + IG_END; + return; + case 26: + mi->projectile_group = (int)(value); + if (mi->projectile_group < 0) + mi->projectile_group = PG_GROUPLESS; + else + mi->projectile_group = mi->projectile_group + PG_END; + return; + default: return; } } diff --git a/prboom2/src/dsda/global.c b/prboom2/src/dsda/global.c index a75b66651..ac293d352 100644 --- a/prboom2/src/dsda/global.c +++ b/prboom2/src/dsda/global.c @@ -251,6 +251,10 @@ static void dsda_InitDoom(void) { mobjinfo[i].droppeditem = mobjinfo_p->droppeditem; mobjinfo[i].crashstate = 0; // not in doom mobjinfo[i].flags2 = 0; // not in doom + + // mbf21 + mobjinfo[i].infighting_group = IG_DEFAULT; + mobjinfo[i].projectile_group = PG_DEFAULT; } // don't want to reorganize info.c structure for a few tweaks... @@ -264,6 +268,9 @@ static void dsda_InitDoom(void) { mobjinfo[MT_BABY].flags2 = MF2_MAP07BOSS2; mobjinfo[MT_BRUISER].flags2 = MF2_E1M8BOSS; mobjinfo[MT_UNDEAD].flags2 = MF2_LONGMELEE | MF2_RANGEHALF; + + mobjinfo[MT_BRUISER].projectile_group = PG_BARON; + mobjinfo[MT_KNIGHT].projectile_group = PG_BARON; } static void dsda_InitHeretic(void) { @@ -371,8 +378,16 @@ static void dsda_InitHeretic(void) { mobjinfo[j].droppeditem = 0; // not in heretic mobjinfo[j].crashstate = mobjinfo_p->crashstate; mobjinfo[j].flags2 = mobjinfo_p->flags2; + + // mbf21 + mobjinfo[j].infighting_group = IG_DEFAULT; + mobjinfo[j].projectile_group = PG_DEFAULT; } + // don't want to reorganize info.c structure for a few tweaks... + mobjinfo[HERETIC_MT_SORCERER2].infighting_group = IG_WIZARD; + mobjinfo[HERETIC_MT_WIZARD].infighting_group = IG_WIZARD; + // heretic doesn't use "clip" concept for (i = 0; i < NUMAMMO; ++i) clipammo[i] = 1; diff --git a/prboom2/src/info.h b/prboom2/src/info.h index 95f213ac0..cacc2f7f5 100644 --- a/prboom2/src/info.h +++ b/prboom2/src/info.h @@ -2995,6 +2995,19 @@ typedef enum { TOTAL_NUMMOBJTYPES = HERETIC_NUMMOBJTYPES } mobjtype_t; +typedef enum { + IG_DEFAULT, + IG_WIZARD, + IG_END +} infighting_group_t; + +typedef enum { + PG_GROUPLESS = -1, + PG_DEFAULT, + PG_BARON, + PG_END +} projectile_group_t; + /******************************************************************** * Definition of the Thing structure ********************************************************************/ @@ -3055,6 +3068,10 @@ typedef struct // heretic int crashstate; uint_64_t flags2; + + // mbf21 + int infighting_group; + int projectile_group; } mobjinfo_t; typedef struct diff --git a/prboom2/src/mbf21.md b/prboom2/src/mbf21.md index 57304cd37..d2c3646b7 100644 --- a/prboom2/src/mbf21.md +++ b/prboom2/src/mbf21.md @@ -52,6 +52,44 @@ This is proof-of-concept implemented in dsda-doom. #### Option default changes - comp_pursuit: 1 (was 0) +#### Dehacked Thing Groups + +##### Infighting +- Add `Infighting group = N` in Thing definition. +- `N` is a nonnegative integer. +- Things with the same value of `N` will not target each other after taking damage. + +##### Projectile +- Add `Projectile group = M` in Thing definition. +- `M` is an integer. +- Things with the same value of `M` will not deal projectile damage to each other. +- A negative value of `M` means that species has no projectile immunity, even to other things in the same species. + +##### Examples + +``` +Thing 12 (Imp) +Projectile group = -1 + +Thing 16 (Baron of Hell) +Projectile group = 2 + +Thing 18 (Hell Knight) +Infighting group = 1 +Projectile group = 1 + +Thing 21 (Arachnotron) +Infighting group = 1 +Projectile group = 2 +``` + +In this example: +- Imp projectiles now damage other Imps (and they will infight with their own kind). +- Barons and Arachnotrons are in the same projectile group: their projectiles will no longer damage each other. +- Barons and Hell Knights are not in the same projectile group: their projectiles will now damage each other, leading to infighting. +- Hell Knights and Arachnotrons are in the same infighting group: they will not infight with each other, despite taking damage from each other's projectiles. +- Note that the group numbers for infighting and projectiles are separate - being in infighting group 1 doesn't mean you are in projectile group 1. + #### New Thing Flags Implementations match between DSDA-Doom and Eternity Engine, diff --git a/prboom2/src/p_inter.c b/prboom2/src/p_inter.c index 830d42d2f..b94c33d7b 100644 --- a/prboom2/src/p_inter.c +++ b/prboom2/src/p_inter.c @@ -891,6 +891,13 @@ static void P_KillMobj(mobj_t *source, mobj_t *target) // and other environmental stuff. // +static dboolean P_InfightingImmune(mobj_t *target, mobj_t *source) +{ + return // not default behaviour, and same group + mobjinfo[target->type].infighting_group != IG_DEFAULT && + mobjinfo[target->type].infighting_group == mobjinfo[source->type].infighting_group; +} + void P_DamageMobj(mobj_t *target,mobj_t *inflictor, mobj_t *source, int damage) { player_t *player; @@ -1177,7 +1184,7 @@ void P_DamageMobj(mobj_t *target,mobj_t *inflictor, mobj_t *source, int damage) (!target->threshold || target->flags2 & MF2_NOTHRESHOLD) && ((source->flags ^ target->flags) & MF_FRIEND || monster_infighting || !mbf_features) && !(heretic && source->flags2 & MF2_BOSS) && - !(target->type == HERETIC_MT_SORCERER2 && source->type == HERETIC_MT_WIZARD) + !P_InfightingImmune(target, source) ) { /* if not intent on another player, chase after this one diff --git a/prboom2/src/p_map.c b/prboom2/src/p_map.c index 9ab90e6eb..194b41e44 100644 --- a/prboom2/src/p_map.c +++ b/prboom2/src/p_map.c @@ -510,6 +510,25 @@ dboolean PIT_CheckLine (line_t* ld) // PIT_CheckThing // +static dboolean P_ProjectileImmune(mobj_t *target, mobj_t *source) +{ + return + ( // PG_GROUPLESS means no immunity, even to own species + mobjinfo[target->type].projectile_group != PG_GROUPLESS || + target == source + ) && + ( + ( // target type has default behaviour, and things are the same type + mobjinfo[target->type].projectile_group == PG_DEFAULT && + source->type == target->type + ) || + ( // target type has special behaviour, and things have the same group + mobjinfo[target->type].projectile_group != PG_DEFAULT && + mobjinfo[target->type].projectile_group == mobjinfo[source->type].projectile_group + ) + ); +} + static dboolean PIT_CheckThing(mobj_t *thing) // killough 3/26/98: make static { fixed_t blockdist; @@ -624,17 +643,10 @@ static dboolean PIT_CheckThing(mobj_t *thing) // killough 3/26/98: make static if (tmthing->z + tmthing->height < thing->z) return true; // underneath - if ( - tmthing->target && - ( - tmthing->target->type == thing->type || - (tmthing->target->type == MT_KNIGHT && thing->type == MT_BRUISER) || - (tmthing->target->type == MT_BRUISER && thing->type == MT_KNIGHT) - ) - ) + if (tmthing->target && P_ProjectileImmune(thing, tmthing->target)) { if (thing == tmthing->target) - return true; // Don't hit same species as originator. + return true; // Don't hit self. else // e6y: Dehacked support - monsters infight if (thing->type != g_mt_player && !monsters_infight) // Explode, but do no damage.