diff --git a/src/actor.h b/src/actor.h index 7651c6ff60..16643ee4d4 100644 --- a/src/actor.h +++ b/src/actor.h @@ -983,6 +983,8 @@ public: FNameNoInit PainType; FNameNoInit DeathType; + const PClass *TeleFogSourceType; + const PClass *TeleFogDestType; FState *SpawnState; FState *SeeState; diff --git a/src/cocoa/i_joystick.cpp b/src/cocoa/i_joystick.cpp index 56db8f815d..9940c6ca8d 100644 --- a/src/cocoa/i_joystick.cpp +++ b/src/cocoa/i_joystick.cpp @@ -152,23 +152,33 @@ IOKitJoystick::IOKitJoystick( IOHIDDeviceRef device ) : m_device( device ) , m_sensitivity( DEFAULT_SENSITIVITY ) { - IOHIDElementRef element = HIDGetFirstDeviceElement( device, kHIDElementTypeInput ); - - while ( NULL != element ) + assert(NULL != device); + assert(IOHIDDeviceGetTypeID() == CFGetTypeID(device)); + + CFArrayRef elements = IOHIDDeviceCopyMatchingElements(device, NULL, kIOHIDOptionsTypeNone); + assert(NULL != elements); + assert(CFArrayGetTypeID() == CFGetTypeID(elements)); + + for (CFIndex i = 0, count = CFArrayGetCount(elements); i < count; ++i) { + const IOHIDElementRef element = + static_cast(const_cast(CFArrayGetValueAtIndex(elements, i))); + assert(NULL != element); + assert(IOHIDElementGetTypeID() == CFGetTypeID(element)); + const uint32_t usagePage = IOHIDElementGetUsagePage( element ); - + if ( kHIDPage_GenericDesktop == usagePage ) { const uint32_t usage = IOHIDElementGetUsage( element ); - - if ( kHIDUsage_GD_Slider == usage + + if ( kHIDUsage_GD_Slider == usage || kHIDUsage_GD_X == usage || kHIDUsage_GD_Y == usage || kHIDUsage_GD_Z == usage || kHIDUsage_GD_Rx == usage || kHIDUsage_GD_Ry == usage || kHIDUsage_GD_Rz == usage ) { AxisInfo axis; memset( &axis, 0, sizeof( axis ) ); - + if ( const CFStringRef name = IOHIDElementGetName( element ) ) { CFStringGetCString( name, axis.name, sizeof( axis.name ) - 1, kCFStringEncodingUTF8 ); @@ -177,22 +187,22 @@ IOKitJoystick::IOKitJoystick( IOHIDDeviceRef device ) { snprintf( axis.name, sizeof( axis.name ), "Axis %i", m_axes.Size() + 1 ); } - + axis.element = element; - + m_axes.Push( axis ); - + IOHIDElement_SetCalibrationMin( element, -1 ); IOHIDElement_SetCalibrationMax( element, 1 ); - + HIDQueueElement( m_device, element ); } else if ( kHIDUsage_GD_Hatswitch == usage && m_POVs.Size() < 4 ) { m_POVs.Push( element ); - + HIDQueueElement( m_device, element ); - } + } } else if ( kHIDPage_Button == usagePage ) { @@ -200,10 +210,10 @@ IOKitJoystick::IOKitJoystick( IOHIDDeviceRef device ) HIDQueueElement( m_device, element ); } - - element = HIDGetNextDeviceElement( element, kHIDElementTypeInput ); } + CFRelease(elements); + SetDefaultConfig(); } diff --git a/src/g_doom/a_doomweaps.cpp b/src/g_doom/a_doomweaps.cpp index 976ffbfc4d..898bf7c5b3 100644 --- a/src/g_doom/a_doomweaps.cpp +++ b/src/g_doom/a_doomweaps.cpp @@ -109,6 +109,7 @@ enum SAW_Flags SF_NOUSEAMMO = 16, SF_NOPULLIN = 32, SF_NOTURN = 64, + SF_STEALARMOR = 128, }; DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Saw) @@ -119,7 +120,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Saw) AActor *linetarget; int actualdamage; - ACTION_PARAM_START(9); + ACTION_PARAM_START(11); ACTION_PARAM_SOUND(fullsound, 0); ACTION_PARAM_SOUND(hitsound, 1); ACTION_PARAM_INT(damage, 2); @@ -129,6 +130,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Saw) ACTION_PARAM_ANGLE(Spread_XY, 6); ACTION_PARAM_ANGLE(Spread_Z, 7); ACTION_PARAM_FIXED(LifeSteal, 8); + ACTION_PARAM_INT(lifestealmax, 9); + ACTION_PARAM_CLASS(armorbonustype, 10); if (NULL == (player = self->player)) { @@ -184,7 +187,31 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Saw) } if (LifeSteal && !(linetarget->flags5 & MF5_DONTDRAIN)) - P_GiveBody (self, (actualdamage * LifeSteal) >> FRACBITS); + { + if (Flags & SF_STEALARMOR) + { + if (!armorbonustype) armorbonustype = PClass::FindClass("ArmorBonus"); + + if (armorbonustype->IsDescendantOf (RUNTIME_CLASS(ABasicArmorBonus))) + { + ABasicArmorBonus *armorbonus = static_cast(Spawn (armorbonustype, 0,0,0, NO_REPLACE)); + armorbonus->SaveAmount *= (actualdamage * LifeSteal) >> FRACBITS; + armorbonus->MaxSaveAmount = lifestealmax <= 0 ? armorbonus->MaxSaveAmount : lifestealmax; + armorbonus->flags |= MF_DROPPED; + armorbonus->ClearCounters(); + + if (!armorbonus->CallTryPickup (self)) + { + armorbonus->Destroy (); + } + } + } + + else + { + P_GiveBody (self, (actualdamage * LifeSteal) >> FRACBITS, lifestealmax); + } + } S_Sound (self, CHAN_WEAPON, hitsound, 1, ATTN_NORM); diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 8660876888..e005c3c674 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -4438,6 +4438,8 @@ enum EACSFunctions ACSF_PickActor, ACSF_IsPointerEqual, ACSF_CanRaiseActor, + ACSF_SetActorTeleFog, // 86 + ACSF_SwapActorTeleFog, /* Zandronum's - these must be skipped when we reach 99! -100:ResetMap(0), @@ -4749,6 +4751,82 @@ static void SetActorPitch(AActor *activator, int tid, int angle, bool interpolat } } +static void SetActorTeleFog(AActor *activator, int tid, FName telefogsrc, FName telefogdest) +{ + //Simply put, if it doesn't exist, it won't change. One can use "" in this scenario. + const PClass *check; + if (tid == 0) + { + if (activator != NULL) + { + check = PClass::FindClass(telefogsrc); + if (check == NULL || !stricmp(telefogsrc, "none") || !stricmp(telefogsrc, "null")) + activator->TeleFogSourceType = NULL; + else + activator->TeleFogSourceType = check; + + check = PClass::FindClass(telefogdest); + if (check == NULL || !stricmp(telefogdest, "none") || !stricmp(telefogdest, "null")) + activator->TeleFogDestType = NULL; + else + activator->TeleFogDestType = check; + } + } + else + { + FActorIterator iterator(tid); + AActor *actor; + + while ((actor = iterator.Next())) + { + check = PClass::FindClass(telefogsrc); + if (check == NULL || !stricmp(telefogsrc, "none") || !stricmp(telefogsrc, "null")) + actor->TeleFogSourceType = NULL; + else + actor->TeleFogSourceType = check; + + check = PClass::FindClass(telefogdest); + if (check == NULL || !stricmp(telefogdest, "none") || !stricmp(telefogdest, "null")) + actor->TeleFogDestType = NULL; + else + actor->TeleFogDestType = check; + } + } +} + +static int SwapActorTeleFog(AActor *activator, int tid) +{ + int count = 0; + if (tid == 0) + { + if ((activator == NULL) || (activator->TeleFogSourceType = activator->TeleFogDestType)) + return 0; //Does nothing if they're the same. + else + { + const PClass *temp = activator->TeleFogSourceType; + activator->TeleFogSourceType = activator->TeleFogDestType; + activator->TeleFogDestType = temp; + return 1; + } + } + else + { + FActorIterator iterator(tid); + AActor *actor; + + while ((actor = iterator.Next())) + { + if (actor->TeleFogSourceType == actor->TeleFogDestType) + continue; //They're the same. Save the effort. + const PClass *temp = actor->TeleFogSourceType; + actor->TeleFogSourceType = actor->TeleFogDestType; + actor->TeleFogDestType = temp; + count++; + } + } + return count; +} + int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args, const SDWORD *stack, int stackdepth) @@ -5662,7 +5740,18 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) SetActorPitch(activator, args[0], args[1], argCount > 2 ? !!args[2] : false); } break; - + case ACSF_SetActorTeleFog: + if (argCount >= 3) + { + SetActorTeleFog(activator, args[0], FBehavior::StaticLookupString(args[1]), FBehavior::StaticLookupString(args[2])); + } + break; + case ACSF_SwapActorTeleFog: + if (argCount >= 1) + { + return SwapActorTeleFog(activator, args[0]); + } + break; case ACSF_PickActor: if (argCount >= 5) { diff --git a/src/p_map.cpp b/src/p_map.cpp index 8575970891..496abbf0d9 100644 --- a/src/p_map.cpp +++ b/src/p_map.cpp @@ -3003,6 +3003,10 @@ bool P_BounceActor(AActor *mo, AActor *BlockingMobj, bool ontop) { if (mo->bouncecount > 0 && --mo->bouncecount == 0) return false; + if (mo->flags7 & MF7_HITTARGET) mo->target = BlockingMobj; + if (mo->flags7 & MF7_HITMASTER) mo->master = BlockingMobj; + if (mo->flags7 & MF7_HITTRACER) mo->tracer = BlockingMobj; + if (!ontop) { fixed_t speed; @@ -3746,6 +3750,8 @@ AActor *P_LineAttack(AActor *t1, angle_t angle, fixed_t distance, hity = t1->y + FixedMul(vy, dist); hitz = shootz + FixedMul(vz, dist); + + // Spawn bullet puffs or blood spots, depending on target type. if ((puffDefaults != NULL && puffDefaults->flags3 & MF3_PUFFONACTORS) || (trace.Actor->flags & MF_NOBLOOD) || @@ -3758,6 +3764,13 @@ AActor *P_LineAttack(AActor *t1, angle_t angle, fixed_t distance, puff = P_SpawnPuff(t1, pufftype, hitx, hity, hitz, angle - ANG180, 2, puffFlags | PF_HITTHING); } + if (puffDefaults != NULL && trace.Actor != NULL && puff != NULL) + { + if (puffDefaults->flags7 && MF7_HITTARGET) puff->target = trace.Actor; + if (puffDefaults->flags7 && MF7_HITMASTER) puff->master = trace.Actor; + if (puffDefaults->flags7 && MF7_HITTRACER) puff->tracer = trace.Actor; + } + // Allow puffs to inflict poison damage, so that hitscans can poison, too. if (puffDefaults != NULL && puffDefaults->PoisonDamage > 0 && puffDefaults->PoisonDuration != INT_MIN) { @@ -3776,7 +3789,7 @@ AActor *P_LineAttack(AActor *t1, angle_t angle, fixed_t distance, { dmgflags |= DMG_NO_ARMOR; } - + if (puff == NULL) { // Since the puff is the damage inflictor we need it here @@ -4150,7 +4163,7 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i int flags; assert(puffclass != NULL); // Because we set it to a default above - AActor *puffDefaults = GetDefaultByType(puffclass->GetReplacement()); + AActor *puffDefaults = GetDefaultByType(puffclass->GetReplacement()); //Contains all the flags such as FOILINVUL, etc. flags = (puffDefaults->flags6 & MF6_NOTRIGGER) ? 0 : TRACE_PCross | TRACE_Impact; rail_data.StopAtInvul = (puffDefaults->flags3 & MF3_FOILINVUL) ? false : true; @@ -4200,6 +4213,12 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i { P_SpawnPuff(source, puffclass, x, y, z, (source->angle + angleoffset) - ANG90, 1, puffflags); } + if (hitactor != NULL && puffDefaults != NULL && thepuff != NULL) + { + if (puffDefaults->flags7 & MF7_HITTARGET) thepuff->target = hitactor; + if (puffDefaults->flags7 & MF7_HITMASTER) thepuff->master = hitactor; + if (puffDefaults->flags7 & MF7_HITTRACER) thepuff->tracer = hitactor; + } if (puffDefaults && puffDefaults->PoisonDamage > 0 && puffDefaults->PoisonDuration != INT_MIN) { P_PoisonMobj(hitactor, thepuff ? thepuff : source, source, puffDefaults->PoisonDamage, puffDefaults->PoisonDuration, puffDefaults->PoisonPeriod, puffDefaults->PoisonDamageType); @@ -4208,6 +4227,7 @@ void P_RailAttack(AActor *source, int damage, int offset_xy, fixed_t offset_z, i dmgFlagPass += (puffDefaults->flags3 & MF3_FOILINVUL) ? DMG_FOILINVUL : 0; //[MC]Because the original foilinvul check wasn't working. dmgFlagPass += (puffDefaults->flags7 & MF7_FOILBUDDHA) ? DMG_FOILBUDDHA : 0; int newdam = P_DamageMobj(hitactor, thepuff ? thepuff : source, source, damage, damagetype, dmgFlagPass); + if (bleed) { P_SpawnBlood(x, y, z, (source->angle + angleoffset) - ANG180, newdam > 0 ? newdam : damage, hitactor); diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 49b4b983fd..8c76d793e8 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -333,7 +333,11 @@ void AActor::Serialize (FArchive &arc) { arc << FriendPlayer; } - + if (SaveVersion >= 4517) + { + arc << TeleFogSourceType + << TeleFogDestType; + } { FString tagstr; if (arc.IsStoring() && Tag != NULL && Tag->Len() > 0) tagstr = *Tag; @@ -2680,18 +2684,10 @@ void P_NightmareRespawn (AActor *mobj) mo->PrevZ = z; // Do not interpolate Z position if we changed it since spawning. // spawn a teleport fog at old spot because of removal of the body? - mo = Spawn ("TeleportFog", mobj->x, mobj->y, mobj->z, ALLOW_REPLACE); - if (mo != NULL) - { - mo->z += TELEFOGHEIGHT; - } + P_SpawnTeleportFog(mobj, mobj->x, mobj->y, mobj->z + TELEFOGHEIGHT, true); // spawn a teleport fog at the new spot - mo = Spawn ("TeleportFog", x, y, z, ALLOW_REPLACE); - if (mo != NULL) - { - mo->z += TELEFOGHEIGHT; - } + P_SpawnTeleportFog(mobj, x, y, z + TELEFOGHEIGHT, false); // remove the old monster mobj->Destroy (); diff --git a/src/p_spec.h b/src/p_spec.h index 906a38a8c2..a225d2379f 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -903,6 +903,7 @@ bool EV_DoChange (line_t *line, EChange changetype, int tag); // // P_TELEPT // +void P_SpawnTeleportFog(AActor *mobj, fixed_t x, fixed_t y, fixed_t z, bool beforeTele = true, bool setTarget = false); //Spawns teleport fog. Pass the actor to pluck TeleFogFromType and TeleFogToType. 'from' determines if this is the fog to spawn at the old position (true) or new (false). bool P_Teleport (AActor *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle, bool useFog, bool sourceFog, bool keepOrientation, bool haltVelocity = true, bool keepHeight = false); bool EV_Teleport (int tid, int tag, line_t *line, int side, AActor *thing, bool fog, bool sourceFog, bool keepOrientation, bool haltVelocity = true, bool keepHeight = false); bool EV_SilentLineTeleport (line_t *line, int side, AActor *thing, int id, INTBOOL reverse); diff --git a/src/p_teleport.cpp b/src/p_teleport.cpp index 60308d8ed7..40e432af02 100644 --- a/src/p_teleport.cpp +++ b/src/p_teleport.cpp @@ -74,19 +74,22 @@ void ATeleportFog::PostBeginPlay () // //========================================================================== -void P_SpawnTeleportFog(fixed_t x, fixed_t y, fixed_t z, int spawnid) +void P_SpawnTeleportFog(AActor *mobj, fixed_t x, fixed_t y, fixed_t z, bool beforeTele, bool setTarget) { - const PClass *fog = P_GetSpawnableType(spawnid); - - if (fog == NULL) + AActor *mo; + if ((beforeTele ? mobj->TeleFogSourceType : mobj->TeleFogDestType) == NULL) { - AActor *mo = Spawn ("TeleportFog", x, y, z + TELEFOGHEIGHT, ALLOW_REPLACE); + //Do nothing. + mo = NULL; } else { - AActor *mo = Spawn (fog, x, y, z, ALLOW_REPLACE); - if (mo != NULL) S_Sound(mo, CHAN_BODY, mo->SeeSound, 1.f, ATTN_NORM); + mo = Spawn((beforeTele ? mobj->TeleFogSourceType : mobj->TeleFogDestType), x, y, z, ALLOW_REPLACE); } + + if (mo != NULL && setTarget) + mo->target = mobj; + } // @@ -186,8 +189,7 @@ bool P_Teleport (AActor *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle, if (sourceFog && !predicting) { fixed_t fogDelta = thing->flags & MF_MISSILE ? 0 : TELEFOGHEIGHT; - AActor *fog = Spawn (oldx, oldy, oldz + fogDelta, ALLOW_REPLACE); - fog->target = thing; + P_SpawnTeleportFog(thing, oldx, oldy, oldz, true, true); //Passes the actor through which then pulls the TeleFog metadate types based on properties. } if (useFog) { @@ -195,9 +197,8 @@ bool P_Teleport (AActor *thing, fixed_t x, fixed_t y, fixed_t z, angle_t angle, { fixed_t fogDelta = thing->flags & MF_MISSILE ? 0 : TELEFOGHEIGHT; an = angle >> ANGLETOFINESHIFT; - AActor *fog = Spawn(x + 20 * finecosine[an], - y + 20 * finesine[an], thing->z + fogDelta, ALLOW_REPLACE); - fog->target = thing; + P_SpawnTeleportFog(thing, x + 20 * finecosine[an], y + 20 * finesine[an], thing->z + fogDelta, false, true); + } if (thing->player) { diff --git a/src/p_things.cpp b/src/p_things.cpp index 63173564c3..a8a34c384c 100644 --- a/src/p_things.cpp +++ b/src/p_things.cpp @@ -92,7 +92,7 @@ bool P_Thing_Spawn (int tid, AActor *source, int type, angle_t angle, bool fog, mobj->angle = (angle != ANGLE_MAX ? angle : spot->angle); if (fog) { - Spawn (spot->x, spot->y, spot->z + TELEFOGHEIGHT, ALLOW_REPLACE); + P_SpawnTeleportFog(mobj, spot->x, spot->y, spot->z + TELEFOGHEIGHT, false); } if (mobj->flags & MF_SPECIAL) mobj->flags |= MF_DROPPED; // Don't respawn @@ -130,8 +130,8 @@ bool P_MoveThing(AActor *source, fixed_t x, fixed_t y, fixed_t z, bool fog) { if (fog) { - Spawn (x, y, z + TELEFOGHEIGHT, ALLOW_REPLACE); - Spawn (oldx, oldy, oldz + TELEFOGHEIGHT, ALLOW_REPLACE); + P_SpawnTeleportFog(source, x, y, z); + P_SpawnTeleportFog(source, oldx, oldy, oldz, false); } source->PrevX = x; source->PrevY = y; diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index 2a2da343e7..98451795b0 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -1385,17 +1385,20 @@ enum CPF_PULLIN = 4, CPF_NORANDOMPUFFZ = 8, CPF_NOTURN = 16, + CPF_STEALARMOR = 32, }; DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) { - ACTION_PARAM_START(5); + ACTION_PARAM_START(8); ACTION_PARAM_INT(Damage, 0); ACTION_PARAM_BOOL(norandom, 1); ACTION_PARAM_INT(flags, 2); ACTION_PARAM_CLASS(PuffType, 3); ACTION_PARAM_FIXED(Range, 4); ACTION_PARAM_FIXED(LifeSteal, 5); + ACTION_PARAM_INT(lifestealmax, 6); + ACTION_PARAM_CLASS(armorbonustype, 7); if (!self->player) return; @@ -1428,7 +1431,31 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CustomPunch) if (linetarget) { if (LifeSteal && !(linetarget->flags5 & MF5_DONTDRAIN)) - P_GiveBody (self, (actualdamage * LifeSteal) >> FRACBITS); + { + if (flags & CPF_STEALARMOR) + { + if (!armorbonustype) armorbonustype = PClass::FindClass("ArmorBonus"); + + if (armorbonustype->IsDescendantOf (RUNTIME_CLASS(ABasicArmorBonus))) + { + ABasicArmorBonus *armorbonus = static_cast(Spawn (armorbonustype, 0,0,0, NO_REPLACE)); + armorbonus->SaveAmount *= (actualdamage * LifeSteal) >> FRACBITS; + armorbonus->MaxSaveAmount = lifestealmax <= 0 ? armorbonus->MaxSaveAmount : lifestealmax; + armorbonus->flags |= MF_DROPPED; + armorbonus->ClearCounters(); + + if (!armorbonus->CallTryPickup (self)) + { + armorbonus->Destroy (); + } + } + } + + else + { + P_GiveBody (self, (actualdamage * LifeSteal) >> FRACBITS, lifestealmax); + } + } if (weapon != NULL) { @@ -2938,9 +2965,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Respawn) { ACTION_PARAM_START(1); ACTION_PARAM_INT(flags, 0); - bool oktorespawn = false; - + fixed_t oldx = self->x; + fixed_t oldy = self->y; + fixed_t oldz = self->z; self->flags |= MF_SOLID; self->height = self->GetDefault()->height; CALL_ACTION(A_RestoreSpecialPosition, self); @@ -2998,7 +3026,8 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Respawn) if (flags & RSF_FOG) { - Spawn (self->x, self->y, self->z + TELEFOGHEIGHT, ALLOW_REPLACE); + P_SpawnTeleportFog(self, oldx, oldy, oldz, true); + P_SpawnTeleportFog(self, self->x, self->y, self->z, false); } if (self->CountsAsKill()) { @@ -4119,9 +4148,16 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetUserArray) //=========================================================================== enum T_Flags { - TF_TELEFRAG = 1, // Allow telefrag in order to teleport. - TF_RANDOMDECIDE = 2, // Randomly fail based on health. (A_Srcr2Decide) - TF_FORCED = 4, // Forget what's in the way. TF_Telefrag takes precedence though. + TF_TELEFRAG = 0x00000001, // Allow telefrag in order to teleport. + TF_RANDOMDECIDE = 0x00000002, // Randomly fail based on health. (A_Srcr2Decide) + TF_FORCED = 0x00000004, // Forget what's in the way. TF_Telefrag takes precedence though. + TF_KEEPVELOCITY = 0x00000008, // Preserve velocity. + TF_KEEPANGLE = 0x00000010, // Keep angle. + TF_USESPOTZ = 0x00000020, // Set the z to the spot's z, instead of the floor. + TF_NOSRCFOG = 0x00000040, // Don't leave any fog behind when teleporting. + TF_NODESTFOG = 0x00000080, // Don't spawn any fog at the arrival position. + TF_USEACTORFOG = 0x00000100, // Use the actor's TeleFogSourceType and TeleFogDestType fogs. + TF_NOJUMP = 0x00000200, // Don't jump after teleporting. }; DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Teleport) @@ -4152,14 +4188,6 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Teleport) if (pr_teleport() >= chance[chanceindex]) return; } - if (TeleportState == NULL) - { - // Default to Teleport. - TeleportState = self->FindState("Teleport"); - // If still nothing, then return. - if (!TeleportState) return; - } - DSpotState *state = DSpotState::GetSpotState(); if (state == NULL) return; @@ -4171,34 +4199,66 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Teleport) fixed_t prevX = self->x; fixed_t prevY = self->y; fixed_t prevZ = self->z; - bool teleResult = false; //Take precedence and cooperate with telefragging first. - if (P_TeleportMove(self, spot->x, spot->y, spot->z, Flags & TF_TELEFRAG)) - teleResult = true; + bool teleResult = P_TeleportMove(self, spot->x, spot->y, spot->z, Flags & TF_TELEFRAG); if ((!(teleResult)) && (Flags & TF_FORCED)) { //If for some reason the original move didn't work, regardless of telefrag, force it to move. self->SetOrigin(spot->x, spot->y, spot->z); teleResult = true; + } if (teleResult) { - ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! - - if (FogType) - { - Spawn(FogType, prevX, prevY, prevZ, ALLOW_REPLACE); + //If a fog type is defined in the parameter, or the user wants to use the actor's predefined fogs, + //and if there's no desire to be fogless, spawn a fog based upon settings. + if (FogType || (Flags & TF_USEACTORFOG)) + { + if (!(Flags & TF_NOSRCFOG)) + { + if (Flags & TF_USEACTORFOG) + P_SpawnTeleportFog(self, prevX, prevY, prevZ, true); + else + Spawn(FogType, prevX, prevY, prevZ, ALLOW_REPLACE); + } + if (!(Flags & TF_NODESTFOG)) + { + if (Flags & TF_USEACTORFOG) + P_SpawnTeleportFog(self, self->x, self->y, self->z, false); + else + Spawn(FogType, self->x, self->y, self->z, ALLOW_REPLACE); + } } + + if (Flags & TF_USESPOTZ) + self->z = spot->z; + else + self->z = self->floorz; - ACTION_JUMP(TeleportState); + if (!(Flags & TF_KEEPANGLE)) + self->angle = spot->angle; - self->z = self->floorz; - self->angle = spot->angle; - self->velx = self->vely = self->velz = 0; + if (!(Flags & TF_KEEPVELOCITY)) + self->velx = self->vely = self->velz = 0; + + if (!(Flags & TF_NOJUMP)) + { + ACTION_SET_RESULT(false); // Jumps should never set the result for inventory state chains! + if (TeleportState == NULL) + { + // Default to Teleport. + TeleportState = self->FindState("Teleport"); + // If still nothing, then return. + if (!TeleportState) return; + } + ACTION_JUMP(TeleportState); + return; + } } + ACTION_SET_RESULT(teleResult); } //=========================================================================== @@ -5377,3 +5437,53 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_Remove) } } +//=========================================================================== +// +// A_SetTeleFog +// +// Sets the teleport fog(s) for the calling actor. +// Takes a name of the classes for te source and destination. +// Can set both at the same time. Use "" to retain the previous fog without +// changing it. +//=========================================================================== + +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetTeleFog) +{ + ACTION_PARAM_START(2); + ACTION_PARAM_NAME(oldpos, 0); + ACTION_PARAM_NAME(newpos, 1); + const PClass *check = PClass::FindClass(oldpos); + if (check == NULL || !stricmp(oldpos, "none") || !stricmp(oldpos, "null")) + self->TeleFogSourceType = NULL; + else if (!stricmp(oldpos, "")) + { //Don't change it if it's just "" + } + else + self->TeleFogSourceType = check; + + check = PClass::FindClass(newpos); + if (check == NULL || !stricmp(newpos, "none") || !stricmp(newpos, "null")) + self->TeleFogDestType = NULL; + else if (!stricmp(newpos, "")) + { //Don't change it if it's just "" + } + else + self->TeleFogDestType = check; +} + +//=========================================================================== +// +// A_SwapTeleFog +// +// Switches the source and dest telefogs around. +//=========================================================================== + +DEFINE_ACTION_FUNCTION(AActor, A_SwapTeleFog) +{ + if ((self->TeleFogSourceType != self->TeleFogDestType)) //Does nothing if they're the same. + { + const PClass *temp = self->TeleFogSourceType; + self->TeleFogSourceType = self->TeleFogDestType; + self->TeleFogDestType = temp; + } +} diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index b548d4ef69..b6a2937ae2 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -1416,6 +1416,26 @@ DEFINE_PROPERTY(stamina, I, Actor) defaults->stamina = i; } +//========================================================================== +// +//========================================================================== +DEFINE_PROPERTY(telefogsourcetype, S, Actor) +{ + PROP_STRING_PARM(str, 0); + if (!stricmp(str, "") || (!stricmp(str, "none")) || (!stricmp(str, "null")) || *str == 0) defaults->TeleFogSourceType = NULL; + else defaults->TeleFogSourceType = FindClassTentative(str,"TeleportFog"); +} + +//========================================================================== +// +//========================================================================== +DEFINE_PROPERTY(telefogdesttype, S, Actor) +{ + PROP_STRING_PARM(str, 0); + if (!stricmp(str, "") || (!stricmp(str, "none")) || (!stricmp(str, "null")) || *str == 0) defaults->TeleFogDestType = NULL; + else defaults->TeleFogDestType = FindClassTentative(str, "TeleportFog"); +} + //========================================================================== // // Special inventory properties diff --git a/src/version.h b/src/version.h index 158d78486c..b0e69bb5d1 100644 --- a/src/version.h +++ b/src/version.h @@ -76,7 +76,7 @@ const char *GetVersionString(); // Use 4500 as the base git save version, since it's higher than the // SVN revision ever got. -#define SAVEVER 4516 +#define SAVEVER 4517 #define SAVEVERSTRINGIFY2(x) #x #define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x) diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 2f97c2a71b..cd718b1c0d 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -26,6 +26,8 @@ ACTOR Actor native //: Thinker DesignatedTeam 255 PainType Normal DeathType Normal + TeleFogSourceType "TeleportFog" + TeleFogDestType "TeleportFog" // Variables for the expression evaluator // NOTE: fixed_t and angle_t are only used here to ensure proper conversion @@ -317,6 +319,8 @@ ACTOR Actor native //: Thinker action native A_GiveToSiblings(class itemtype, int amount = 0); action native A_TakeFromChildren(class itemtype, int amount = 0); action native A_TakeFromSiblings(class itemtype, int amount = 0); + action native A_SetTeleFog(name oldpos, name newpos); + action native A_SwapTeleFog(); action native A_CheckSightOrRange(float distance, state label); action native A_CheckRange(float distance, state label); diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index 8695c9c199..756fae9814 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -16,6 +16,7 @@ const int SF_NOUSEAMMOMISS = 8; const int SF_NOUSEAMMO = 16; const int SF_NOPULLIN = 32; const int SF_NOTURN = 64; +const int SF_STEALARMOR = 128; // Flags for A_CustomMissile const int CMF_AIMOFFSET = 1; @@ -176,15 +177,29 @@ const int CPF_DAGGER = 2; const int CPF_PULLIN = 4; const int CPF_NORANDOMPUFFZ = 8; const int CPF_NOTURN = 16; +const int CPF_STEALARMOR = 32; // Flags for A_CustomMissile const int FPF_AIMATANGLE = 1; const int FPF_TRANSFERTRANSLATION = 2; // Flags for A_Teleport -const int TF_TELEFRAG = 1; -const int TF_RANDOMDECIDE = 2; -const int TF_FORCED = 4; +enum +{ + TF_TELEFRAG = 0x00000001, // Allow telefrag in order to teleport. + TF_RANDOMDECIDE = 0x00000002, // Randomly fail based on health. (A_Srcr2Decide) + TF_FORCED = 0x00000004, // Forget what's in the way. TF_Telefrag takes precedence though. + TF_KEEPVELOCITY = 0x00000008, // Preserve velocity. + TF_KEEPANGLE = 0x00000010, // Keep angle. + TF_USESPOTZ = 0x00000020, // Set the z to the spot's z, instead of the floor. + TF_NOSRCFOG = 0x00000040, // Don't leave any fog behind when teleporting. + TF_NODESTFOG = 0x00000080, // Don't spawn any fog at the arrival position. + TF_USEACTORFOG = 0x00000100, // Use the actor's TeleFogSourceType and TeleFogDestType fogs. + TF_NOJUMP = 0x00000200, // Don't jump after teleporting. + + TF_KEEPORIENTATION = TF_KEEPVELOCITY|TF_KEEPANGLE, + TF_NOFOG = TF_NOSRCFOG|TF_NODESTFOG, +}; // Flags for A_WolfAttack const int WAF_NORANDOM = 1; diff --git a/wadsrc/static/actors/shared/inventory.txt b/wadsrc/static/actors/shared/inventory.txt index e9f57a607d..7860b93876 100644 --- a/wadsrc/static/actors/shared/inventory.txt +++ b/wadsrc/static/actors/shared/inventory.txt @@ -8,7 +8,7 @@ ACTOR Inventory native Inventory.PickupMessage "$TXT_DEFAULTPICKUPMSG" action native A_JumpIfNoAmmo(state label); - action native A_CustomPunch(int damage, bool norandom = false, int flags = CPF_USEAMMO, class pufftype = "BulletPuff", float range = 0, float lifesteal = 0); + action native A_CustomPunch(int damage, bool norandom = false, int flags = CPF_USEAMMO, class pufftype = "BulletPuff", float range = 0, float lifesteal = 0, int lifestealmax = 0, class armorbonustype = "ArmorBonus"); action native A_FireBullets(float spread_xy, float spread_z, int numbullets, int damageperbullet, class pufftype = "BulletPuff", int flags = 1, float range = 0); action native A_FireCustomMissile(class missiletype, float angle = 0, bool useammo = true, int spawnofs_xy = 0, float spawnheight = 0, bool aimatangle = false, float pitch = 0); action native A_RailAttack(int damage, int spawnofs_xy = 0, int useammo = true, color color1 = "", color color2 = "", int flags = 0, float maxdiff = 0, class pufftype = "BulletPuff", float spread_xy = 0, float spread_z = 0, float range = 0, int duration = 0, float sparsity = 1.0, float driftspeed = 1.0, class spawnclass = "none", float spawnofs_z = 0); @@ -41,7 +41,7 @@ ACTOR Inventory native action native A_ClearReFire(); action native A_CheckReload(); action native A_GunFlash(state flash = "", int flags = 0); - action native A_Saw(sound fullsound = "weapons/sawfull", sound hitsound = "weapons/sawhit", int damage = 2, class pufftype = "BulletPuff", int flags = 0, float range = 0, float spread_xy = 2.8125, float spread_z = 0, float lifesteal = 0); + action native A_Saw(sound fullsound = "weapons/sawfull", sound hitsound = "weapons/sawhit", int damage = 2, class pufftype = "BulletPuff", int flags = 0, float range = 0, float spread_xy = 2.8125, float spread_z = 0, float lifesteal = 0, int lifestealmax = 0, class armorbonustype = "ArmorBonus"); action native A_CheckForReload(int counter, state label, bool dontincrement = false); action native A_ResetReloadCounter(); action native A_RestoreSpecialPosition(); diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index abc654252c..4e33029b47 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -665,6 +665,7 @@ OptionMenu "VideoOptions" Slider "Screen size", "screenblocks", 3.0, 12.0, 1.0, 0 Slider "Brightness", "Gamma", 0.75, 3.0, 0.05, 2 Option "Vertical Sync", "vid_vsync", "OnOff" + Option "Rendering Interpolation", "cl_capfps", "OffOn" Option "Column render mode", "r_columnmethod", "ColumnMethods" StaticText " " @@ -685,6 +686,7 @@ OptionMenu "VideoOptions" Option "Blood Type", "cl_bloodtype", "BloodTypes" Option "Bullet Puff Type", "cl_pufftype", "PuffTypes" Slider "Number of particles", "r_maxparticles", 100, 10000, 100, 0 + Slider "Number of decals", "cl_maxdecals", 0, 10000, 100, 0 Option "Show player sprites", "r_drawplayersprites", "OnOff" Option "Death camera", "r_deathcamera", "OnOff" Option "Teleporter zoom", "telezoom", "OnOff"