diff --git a/docs/rh-log.txt b/docs/rh-log.txt index e6954d8e69..6cbda931d0 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -1,3 +1,10 @@ +December 16, 2006 (Changes by Graf Zahl) +- Merged the fallingdamage setting into one menu item and added Strife damage to it. +- Moved deathmatch options into their own category in the gameplay options menu. +- Added the sv_smartaim code from GZDoom which tries to avoid autoaiming + at friendlies or shootable decorations if there are monsters that can be shot. +- Added: SetThingSpecial treats a tid of 0 as the activator. + December 13, 2006 (Changes by Graf Zahl) - Fixed: The particle fountains' names were different than before - Fixed: FTexture::CheckForTexture should return NULL if the texture it diff --git a/src/m_menu.h b/src/m_menu.h index 56499fb56b..76e1132ddf 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -100,6 +100,7 @@ typedef enum { control, screenres, bitflag, + bitmask, listelement, nochoice, numberedmore, diff --git a/src/m_options.cpp b/src/m_options.cpp index 4d4f3dbed7..097f68672d 100644 --- a/src/m_options.cpp +++ b/src/m_options.cpp @@ -98,6 +98,7 @@ EXTERN_CVAR (Int, snd_buffersize) EXTERN_CVAR (Int, snd_samplerate) EXTERN_CVAR (Bool, snd_3d) EXTERN_CVAR (Bool, snd_waterreverb) +EXTERN_CVAR (Int, sv_smartaim) static void CalcIndent (menu_t *menu); @@ -924,29 +925,35 @@ CUSTOM_CVAR (Bool, vid_tft, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG) * Gameplay Options (dmflags) Menu * *=======================================*/ +value_t SmartAim[3] = { + { 0.0, "Off" }, + { 1.0, "On" }, + { 2.0, "Never friends" } +}; + +value_t FallingDM[4] = { + { 0, "Off" }, + { DF_FORCE_FALLINGZD, "Old" }, + { DF_FORCE_FALLINGHX, "Hexen" }, + { DF_FORCE_FALLINGZD|DF_FORCE_FALLINGHX, "Strife" } +}; + static menuitem_t DMFlagsItems[] = { { discrete, "Teamplay", {&teamplay}, {2.0}, {0.0}, {0.0}, {OnOff} }, { slider, "Team damage scalar", {&teamdamage}, {0.0}, {1.0}, {0.05},{NULL} }, { redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} }, - { bitflag, "Falling damage (old)", {&dmflags}, {0}, {0}, {0}, {(value_t *)DF_FORCE_FALLINGZD} }, - { bitflag, "Falling damage (Hexen)",{&dmflags}, {0}, {0}, {0}, {(value_t *)DF_FORCE_FALLINGHX} }, - { bitflag, "Weapons stay (DM)", {&dmflags}, {0}, {0}, {0}, {(value_t *)DF_WEAPONS_STAY} }, - { bitflag, "Allow powerups (DM)", {&dmflags}, {1}, {0}, {0}, {(value_t *)DF_NO_ITEMS} }, - { bitflag, "Allow health (DM)", {&dmflags}, {1}, {0}, {0}, {(value_t *)DF_NO_HEALTH} }, - { bitflag, "Allow armor (DM)", {&dmflags}, {1}, {0}, {0}, {(value_t *)DF_NO_ARMOR} }, - { bitflag, "Spawn farthest (DM)", {&dmflags}, {0}, {0}, {0}, {(value_t *)DF_SPAWN_FARTHEST} }, - { bitflag, "Same map (DM)", {&dmflags}, {0}, {0}, {0}, {(value_t *)DF_SAME_LEVEL} }, - { bitflag, "Force respawn (DM)", {&dmflags}, {0}, {0}, {0}, {(value_t *)DF_FORCE_RESPAWN} }, - { bitflag, "Allow exit (DM)", {&dmflags}, {1}, {0}, {0}, {(value_t *)DF_NO_EXIT} }, - { bitflag, "Barrels respawn (DM)", {&dmflags2}, {0}, {0}, {0}, {(value_t *)DF2_BARRELS_RESPAWN} }, - { bitflag, "Respawn protection (DM)",{&dmflags2}, {0}, {0}, {0}, {(value_t *)DF2_YES_INVUL} }, + { discrete, "Smart Autoaim", {&sv_smartaim}, {3.0}, {0.0}, {0.0}, {SmartAim} }, + { redtext, " ", {NULL}, {0.0}, {0.0}, {0.0}, {NULL} }, + { bitmask, "Falling damage", {&dmflags}, {4.0}, {DF_FORCE_FALLINGZD|DF_FORCE_FALLINGHX}, {0}, {FallingDM} }, +// { bitflag, "Falling damage (old)", {&dmflags}, {0}, {0}, {0}, {(value_t *)DF_FORCE_FALLINGZD} }, +// { bitflag, "Falling damage (Hexen)",{&dmflags}, {0}, {0}, {0}, {(value_t *)DF_FORCE_FALLINGHX} }, { bitflag, "Drop weapon", {&dmflags2}, {0}, {0}, {0}, {(value_t *)DF2_YES_WEAPONDROP} }, { bitflag, "Infinite ammo", {&dmflags}, {0}, {0}, {0}, {(value_t *)DF_INFINITE_AMMO} }, { bitflag, "No monsters", {&dmflags}, {0}, {0}, {0}, {(value_t *)DF_NO_MONSTERS} }, { bitflag, "Monsters respawn", {&dmflags}, {0}, {0}, {0}, {(value_t *)DF_MONSTERS_RESPAWN} }, { bitflag, "Items respawn", {&dmflags}, {0}, {0}, {0}, {(value_t *)DF_ITEMS_RESPAWN} }, - { bitflag, "Mega powerups respawn",{&dmflags}, {0}, {0}, {0}, {(value_t *)DF_RESPAWN_SUPER} }, + { bitflag, "Big powerups respawn", {&dmflags}, {0}, {0}, {0}, {(value_t *)DF_RESPAWN_SUPER} }, { bitflag, "Fast monsters", {&dmflags}, {0}, {0}, {0}, {(value_t *)DF_FAST_MONSTERS} }, { bitflag, "Allow jump", {&dmflags}, {1}, {0}, {0}, {(value_t *)DF_NO_JUMP} }, { bitflag, "Allow crouch", {&dmflags}, {1}, {0}, {0}, {(value_t *)DF_NO_CROUCH} }, @@ -954,6 +961,18 @@ static menuitem_t DMFlagsItems[] = { { bitflag, "Allow FOV", {&dmflags}, {1}, {0}, {0}, {(value_t *)DF_NO_FOV} }, { bitflag, "Allow BFG aiming", {&dmflags2}, {1}, {0}, {0}, {(value_t *)DF2_NO_FREEAIMBFG} }, { redtext, " ", {NULL}, {0}, {0}, {0}, {NULL} }, + { whitetext,"Deathmatch Settings", {NULL}, {0}, {0}, {0}, {NULL} }, + { bitflag, "Weapons stay", {&dmflags}, {0}, {0}, {0}, {(value_t *)DF_WEAPONS_STAY} }, + { bitflag, "Allow powerups", {&dmflags}, {1}, {0}, {0}, {(value_t *)DF_NO_ITEMS} }, + { bitflag, "Allow health", {&dmflags}, {1}, {0}, {0}, {(value_t *)DF_NO_HEALTH} }, + { bitflag, "Allow armor", {&dmflags}, {1}, {0}, {0}, {(value_t *)DF_NO_ARMOR} }, + { bitflag, "Spawn farthest", {&dmflags}, {0}, {0}, {0}, {(value_t *)DF_SPAWN_FARTHEST} }, + { bitflag, "Same map", {&dmflags}, {0}, {0}, {0}, {(value_t *)DF_SAME_LEVEL} }, + { bitflag, "Force respawn", {&dmflags}, {0}, {0}, {0}, {(value_t *)DF_FORCE_RESPAWN} }, + { bitflag, "Allow exit", {&dmflags}, {1}, {0}, {0}, {(value_t *)DF_NO_EXIT} }, + { bitflag, "Barrels respawn", {&dmflags2}, {0}, {0}, {0}, {(value_t *)DF2_BARRELS_RESPAWN} }, + { bitflag, "Respawn protection", {&dmflags2}, {0}, {0}, {0}, {(value_t *)DF2_YES_INVUL} }, + { redtext, " ", {NULL}, {0}, {0}, {0}, {NULL} }, { whitetext,"Cooperative Settings", {NULL}, {0}, {0}, {0}, {NULL} }, { bitflag, "Spawn multi. weapons", {&dmflags}, {1}, {0}, {0}, {(value_t *)DF_NO_COOP_WEAPON_SPAWN} }, { bitflag, "Lose entire inventory",{&dmflags}, {0}, {0}, {0}, {(value_t *)DF_COOP_LOSE_INVENTORY} }, @@ -1500,6 +1519,31 @@ void M_OptDrawer () } break; + case bitmask: + { + int v, vals; + + value = item->a.cvar->GetGenericRep (CVAR_Int); + value.Float = value.Int & int(item->c.max); + vals = (int)item->b.numvalues; + + v = M_FindCurVal (value.Float, item->e.values, vals); + + if (v == vals) + { + screen->DrawText (ValueColor, CurrentMenu->indent + 14, y, "Unknown", + DTA_Clean, true, TAG_DONE); + } + else + { + screen->DrawText (item->type == cdiscrete ? v : ValueColor, + CurrentMenu->indent + 14, y, item->e.values[v].name, + DTA_Clean, true, TAG_DONE); + } + + } + break; + case discrete: case cdiscrete: case inverter: @@ -2014,6 +2058,25 @@ void M_OptResponder (event_t *ev) S_Sound (CHAN_VOICE, "menu/change", 1, ATTN_NONE); break; + case bitmask: + { + int cur; + int numvals; + int bmask = int(item->c.max); + + numvals = (int)item->b.min; + value = item->a.cvar->GetGenericRep (CVAR_Int); + + cur = M_FindCurVal (value.Int & bmask, item->e.values, numvals); + if (--cur < 0) + cur = numvals - 1; + + value.Int = (value.Int & ~bmask) | int(item->e.values[cur].value); + item->a.cvar->SetGenericRep (value, CVAR_Int); + } + S_Sound (CHAN_VOICE, "menu/change", 1, ATTN_NONE); + break; + case discrete_guid: { int cur; @@ -2129,6 +2192,25 @@ void M_OptResponder (event_t *ev) S_Sound (CHAN_VOICE, "menu/change", 1, ATTN_NONE); break; + case bitmask: + { + int cur; + int numvals; + int bmask = int(item->c.max); + + numvals = (int)item->b.min; + value = item->a.cvar->GetGenericRep (CVAR_Int); + + cur = M_FindCurVal (value.Int & bmask, item->e.values, numvals); + if (++cur >= numvals) + cur = 0; + + value.Int = (value.Int & ~bmask) | int(item->e.values[cur].value); + item->a.cvar->SetGenericRep (value, CVAR_Int); + } + S_Sound (CHAN_VOICE, "menu/change", 1, ATTN_NONE); + break; + case discrete_guid: { int cur; diff --git a/src/p_acs.cpp b/src/p_acs.cpp index f15b21ca5d..11fb96c43b 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -4088,17 +4088,29 @@ int DLevelScript::RunScript () case PCD_SETTHINGSPECIAL: { - FActorIterator iterator (STACK(7)); - AActor *actor; - - while ( (actor = iterator.Next ()) ) + if (STACK(7) != 0) { - actor->special = STACK(6); - actor->args[0] = STACK(5); - actor->args[1] = STACK(4); - actor->args[2] = STACK(3); - actor->args[3] = STACK(2); - actor->args[4] = STACK(1); + FActorIterator iterator (STACK(7)); + AActor *actor; + + while ( (actor = iterator.Next ()) ) + { + actor->special = STACK(6); + actor->args[0] = STACK(5); + actor->args[1] = STACK(4); + actor->args[2] = STACK(3); + actor->args[3] = STACK(2); + actor->args[4] = STACK(1); + } + } + else if (activator != NULL) + { + activator->special = STACK(6); + activator->args[0] = STACK(5); + activator->args[1] = STACK(4); + activator->args[2] = STACK(3); + activator->args[3] = STACK(2); + activator->args[4] = STACK(1); } sp -= 7; } diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index e96344622e..ed62cfd905 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -352,7 +352,7 @@ bool P_HitFriend(AActor * self) { angle_t angle = R_PointToAngle2 (self->x, self->y, self->target->x, self->target->y); fixed_t dist = P_AproxDistance (self->x-self->target->x, self->y-self->target->y); - P_AimLineAttack (self, angle, dist, 0); + P_AimLineAttack (self, angle, dist, 0, true); if (linetarget != NULL && linetarget != self->target) { return self->IsFriend (linetarget); diff --git a/src/p_local.h b/src/p_local.h index efad753ef9..ab675d8541 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -298,7 +298,7 @@ bool P_ChangeSector (sector_t* sector, int crunch, int amt, int floorOrCeil); extern AActor* linetarget; // who got hit (or NULL) extern AActor *PuffSpawned; // points to last puff spawned -fixed_t P_AimLineAttack (AActor *t1, angle_t angle, fixed_t distance, fixed_t vrange=0); +fixed_t P_AimLineAttack (AActor *t1, angle_t angle, fixed_t distance, fixed_t vrange=0, bool forcenosmart=false); void P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, const PClass *pufftype); void P_LineAttack (AActor *t1, angle_t angle, fixed_t distance, int pitch, int damage, FName damageType, FName pufftype); void P_TraceBleed (int damage, fixed_t x, fixed_t y, fixed_t z, AActor *target, angle_t angle, int pitch); diff --git a/src/p_map.cpp b/src/p_map.cpp index e0386f5622..d893217dd2 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -62,6 +62,7 @@ CVAR (Bool, cl_bloodsplats, true, CVAR_ARCHIVE) +CVAR (Int, sv_smartaim, 0, CVAR_ARCHIVE|CVAR_SERVERINFO) static void CheckForPushSpecial (line_t *line, int side, AActor *mobj); static void SpawnShootDecal (AActor *t1, const FTraceResults &trace); @@ -2487,42 +2488,53 @@ bool P_BounceWall (AActor *mo) } +//============================================================================ // -// P_LineAttack +// Aiming // -AActor* linetarget; // who got hit (or NULL) -AActor* shootthing; +//============================================================================ +AActor* linetarget; // who got hit (or NULL) +AActor* shootthing; +fixed_t shootz; // Height if not aiming up or down +fixed_t attackrange; +fixed_t aimpitch; -// Height if not aiming up or down -// ???: use slope for monsters? -fixed_t shootz; - -fixed_t attackrange; - -fixed_t aimpitch; - -// slopes to top and bottom of target -// killough 4/20/98: make static instead of using ones in p_sight.c -// [RH] made these angles instead of slopes - -static fixed_t toppitch; -static fixed_t bottompitch; +struct aim_t +{ + fixed_t toppitch, bottompitch; + AActor * thing_friend, * thing_other; + angle_t pitch_friend, pitch_other; + bool notsmart; + +}; + +aim_t aim; + + + +//============================================================================ // // PTR_AimTraverse // Sets linetaget and aimpitch when a target is aimed at. // +//============================================================================ + bool PTR_AimTraverse (intercept_t* in) { + fixed_t & toppitch=aim.toppitch; + fixed_t & bottompitch=aim.bottompitch; + line_t* li; AActor* th; fixed_t pitch; fixed_t thingtoppitch; fixed_t thingbottompitch; fixed_t dist; + int thingpitch; - if (in->isaline) + if (in->isaline) { li = in->d.line; @@ -2569,9 +2581,9 @@ bool PTR_AimTraverse (intercept_t* in) { return true; } - - // check angles to see if the thing can be aimed at + dist = FixedMul (attackrange, in->frac); + // check angles to see if the thing can be aimed at thingtoppitch = -(int)R_PointToAngle2 (0, shootz, dist, th->z + th->height); @@ -2589,18 +2601,47 @@ bool PTR_AimTraverse (intercept_t* in) if (thingbottompitch > bottompitch) thingbottompitch = bottompitch; + + thingpitch = thingtoppitch/2 + thingbottompitch/2; - aimpitch = thingtoppitch/2 + thingbottompitch/2; - linetarget = th; - - return false; // don't go any farther + if (sv_smartaim && !aim.notsmart) + { + // try to be a little smarter about what to aim at! + // In particular avoid autoaiming at friends amd barrels. + if (th->IsFriend(shootthing) && sv_smartaim != 2) + { + // friends don't aim at friends (except players), at least not first + aim.thing_friend=th; + aim.pitch_friend=thingpitch; + } + else if (!(th->flags3&MF3_ISMONSTER) ) + { + // don't autoaim at barrels and other shootable stuff unless no monsters have been found + aim.thing_other=th; + aim.pitch_other=thingpitch; + } + else + { + linetarget=th; + aimpitch=thingpitch; + return false; + } + } + else + { + linetarget=th; + aimpitch=thingpitch; + return false; + } + return true; } - +//============================================================================ // // P_AimLineAttack // -fixed_t P_AimLineAttack (AActor *t1, angle_t angle, fixed_t distance, fixed_t vrange) +//============================================================================ +fixed_t P_AimLineAttack (AActor *t1, angle_t angle, fixed_t distance, fixed_t vrange, bool forcenosmart) { fixed_t x2; fixed_t y2; @@ -2628,20 +2669,36 @@ fixed_t P_AimLineAttack (AActor *t1, angle_t angle, fixed_t distance, fixed_t vr vrange = clamp (t1->player->userinfo.aimdist, ANGLE_1/2, ANGLE_1*35); } } - toppitch = t1->pitch - vrange; - bottompitch = t1->pitch + vrange; + aim.toppitch = t1->pitch - vrange; + aim.bottompitch = t1->pitch + vrange; + aim.notsmart = forcenosmart; attackrange = distance; linetarget = NULL; + // for smart aiming + aim.thing_friend=aim.thing_other=NULL; + + // Information for tracking crossed 3D floors + aimpitch=t1->pitch; P_PathTraverse (t1->x, t1->y, x2, y2, PT_ADDLINES|PT_ADDTHINGS, PTR_AimTraverse); - if (linetarget) - return aimpitch; - - return t1->pitch; + if (!linetarget) + { + if (aim.thing_other) + { + linetarget=aim.thing_other; + aimpitch=aim.pitch_other; + } + else if (aim.thing_friend) + { + linetarget=aim.thing_friend; + aimpitch=aim.pitch_friend; + } + } + return linetarget ? aimpitch : t1->pitch; } - + /* =================