diff --git a/src/c_cvars.cpp b/src/c_cvars.cpp index 36e3d576b..c8f1ee4c6 100644 --- a/src/c_cvars.cpp +++ b/src/c_cvars.cpp @@ -1488,6 +1488,44 @@ FBaseCVar *FindCVarSub (const char *var_name, int namelen) return var; } +FBaseCVar *GetCVar(AActor *activator, const char *cvarname) +{ + FBaseCVar *cvar = FindCVar(cvarname, nullptr); + // Either the cvar doesn't exist, or it's for a mod that isn't loaded, so return nullptr. + if (cvar == nullptr || (cvar->GetFlags() & CVAR_IGNORE)) + { + return nullptr; + } + else + { + // For userinfo cvars, redirect to GetUserCVar + if (cvar->GetFlags() & CVAR_USERINFO) + { + if (activator == nullptr || activator->player == nullptr) + { + return nullptr; + } + return GetUserCVar(int(activator->player - players), cvarname); + } + return cvar; + } +} + +FBaseCVar *GetUserCVar(int playernum, const char *cvarname) +{ + if ((unsigned)playernum >= MAXPLAYERS || !playeringame[playernum]) + { + return nullptr; + } + FBaseCVar **cvar_p = players[playernum].userinfo.CheckKey(FName(cvarname, true)); + FBaseCVar *cvar; + if (cvar_p == nullptr || (cvar = *cvar_p) == nullptr || (cvar->GetFlags() & CVAR_IGNORE)) + { + return nullptr; + } + return cvar; +} + //=========================================================================== // // C_CreateCVar diff --git a/src/c_cvars.h b/src/c_cvars.h index 59a3208d1..be7676e89 100644 --- a/src/c_cvars.h +++ b/src/c_cvars.h @@ -186,6 +186,10 @@ void C_BackupCVars (void); FBaseCVar *FindCVar (const char *var_name, FBaseCVar **prev); FBaseCVar *FindCVarSub (const char *var_name, int namelen); +// Used for ACS and DECORATE. +FBaseCVar *GetCVar(AActor *activator, const char *cvarname); +FBaseCVar *GetUserCVar(int playernum, const char *cvarname); + // Create a new cvar with the specified name and type FBaseCVar *C_CreateCVar(const char *var_name, ECVarType var_type, DWORD flags); diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 7c031d243..29c9fe8fe 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -4657,7 +4657,11 @@ static int DoGetCVar(FBaseCVar *cvar, bool is_string) { UCVarValue val; - if (is_string) + if (cvar == nullptr) + { + return 0; + } + else if (is_string) { val = cvar->GetGenericRep(CVAR_String); return GlobalACSStrings.AddString(val.String); @@ -4674,44 +4678,6 @@ static int DoGetCVar(FBaseCVar *cvar, bool is_string) } } -static int GetUserCVar(int playernum, const char *cvarname, bool is_string) -{ - if ((unsigned)playernum >= MAXPLAYERS || !playeringame[playernum]) - { - return 0; - } - FBaseCVar **cvar_p = players[playernum].userinfo.CheckKey(FName(cvarname, true)); - FBaseCVar *cvar; - if (cvar_p == NULL || (cvar = *cvar_p) == NULL || (cvar->GetFlags() & CVAR_IGNORE)) - { - return 0; - } - return DoGetCVar(cvar, is_string); -} - -static int GetCVar(AActor *activator, const char *cvarname, bool is_string) -{ - FBaseCVar *cvar = FindCVar(cvarname, NULL); - // Either the cvar doesn't exist, or it's for a mod that isn't loaded, so return 0. - if (cvar == NULL || (cvar->GetFlags() & CVAR_IGNORE)) - { - return 0; - } - else - { - // For userinfo cvars, redirect to GetUserCVar - if (cvar->GetFlags() & CVAR_USERINFO) - { - if (activator == NULL || activator->player == NULL) - { - return 0; - } - return GetUserCVar(int(activator->player - players), cvarname, is_string); - } - return DoGetCVar(cvar, is_string); - } -} - static int SetUserCVar(int playernum, const char *cvarname, int value, bool is_string) { if ((unsigned)playernum >= MAXPLAYERS || !playeringame[playernum]) @@ -5396,7 +5362,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args) case ACSF_GetCVarString: if (argCount == 1) { - return GetCVar(activator, FBehavior::StaticLookupString(args[0]), true); + return DoGetCVar(GetCVar(activator, FBehavior::StaticLookupString(args[0])), true); } break; @@ -5417,14 +5383,14 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args) case ACSF_GetUserCVar: if (argCount == 2) { - return GetUserCVar(args[0], FBehavior::StaticLookupString(args[1]), false); + return DoGetCVar(GetUserCVar(args[0], FBehavior::StaticLookupString(args[1])), false); } break; case ACSF_GetUserCVarString: if (argCount == 2) { - return GetUserCVar(args[0], FBehavior::StaticLookupString(args[1]), true); + return DoGetCVar(GetUserCVar(args[0], FBehavior::StaticLookupString(args[1])), true); } break; @@ -6048,7 +6014,7 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) PalEntry color = args[0]; bool fullbright = argCount > 1 ? !!args[1] : false; int lifetime = argCount > 2 ? args[2] : 35; - int size = argCount > 3 ? args[3] : 1; + double size = argCount > 3 ? args[3] : 1.; int x = argCount > 4 ? args[4] : 0; int y = argCount > 5 ? args[5] : 0; int z = argCount > 6 ? args[6] : 0; @@ -6060,17 +6026,18 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) int accelz = argCount > 12 ? args[12] : 0; int startalpha = argCount > 13 ? args[13] : 0xFF; // Byte trans int fadestep = argCount > 14 ? args[14] : -1; + double endsize = argCount > 15 ? args[15] : -1.; startalpha = clamp(startalpha, 0, 255); // Clamp to byte lifetime = clamp(lifetime, 0, 255); // Clamp to byte fadestep = clamp(fadestep, -1, 255); // Clamp to byte inc. -1 (indicating automatic) - size = clamp(size, 0, 65535); // Clamp to word + size = fabs(size); if (lifetime != 0) P_SpawnParticle(DVector3(ACSToDouble(x), ACSToDouble(y), ACSToDouble(z)), DVector3(ACSToDouble(xvel), ACSToDouble(yvel), ACSToDouble(zvel)), DVector3(ACSToDouble(accelx), ACSToDouble(accely), ACSToDouble(accelz)), - color, fullbright, startalpha/255., lifetime, size, fadestep/255.); + color, startalpha/255., lifetime, size, endsize, fadestep/255., fullbright); } break; @@ -9131,7 +9098,7 @@ scriptwait: break; case PCD_GETCVAR: - STACK(1) = GetCVar(activator, FBehavior::StaticLookupString(STACK(1)), false); + STACK(1) = DoGetCVar(GetCVar(activator, FBehavior::StaticLookupString(STACK(1))), false); break; case PCD_SETHUDSIZE: diff --git a/src/p_effect.cpp b/src/p_effect.cpp index 25838459d..ec051c299 100644 --- a/src/p_effect.cpp +++ b/src/p_effect.cpp @@ -252,7 +252,6 @@ void P_InitEffects () blood2 = ParticleColor(RPART(kind)/3, GPART(kind)/3, BPART(kind)/3); } - void P_ThinkParticles () { int i; @@ -262,13 +261,19 @@ void P_ThinkParticles () prev = NULL; while (i != NO_PARTICLE) { - BYTE oldtrans; - particle = Particles + i; i = particle->tnext; + if (!particle->notimefreeze && ((bglobal.freeze) || (level.flags2 & LEVEL2_FROZEN))) + { + prev = particle; + continue; + } + + BYTE oldtrans; oldtrans = particle->trans; particle->trans -= particle->fade; - if (oldtrans < particle->trans || --particle->ttl == 0) + particle->size += particle->sizestep; + if (oldtrans < particle->trans || --particle->ttl <= 0 || (particle->size <= 0)) { // The particle has expired, so free it memset (particle, 0, sizeof(particle_t)); if (prev) @@ -309,8 +314,14 @@ void P_ThinkParticles () } } +enum PSFlag +{ + PS_FULLBRIGHT = 1, + PS_NOTIMEFREEZE = 1 << 5, +}; -void P_SpawnParticle(const DVector3 &pos, const DVector3 &vel, const DVector3 &accel, PalEntry color, bool fullbright, double startalpha, int lifetime, WORD size, double fadestep) +void P_SpawnParticle(const DVector3 &pos, const DVector3 &vel, const DVector3 &accel, PalEntry color, double startalpha, int lifetime, double size, + double fadestep, double sizestep, int flags) { particle_t *particle = NewParticle(); @@ -324,8 +335,10 @@ void P_SpawnParticle(const DVector3 &pos, const DVector3 &vel, const DVector3 &a if (fadestep < 0) particle->fade = FADEFROMTTL(lifetime); else particle->fade = int(fadestep * 255); particle->ttl = lifetime; - particle->bright = fullbright; - particle->size = (WORD)size; + particle->bright = !!(flags & PS_FULLBRIGHT); + particle->size = size; + particle->sizestep = sizestep; + particle->notimefreeze = !!(flags & PS_NOTIMEFREEZE); } } @@ -462,8 +475,8 @@ void P_RunEffect (AActor *actor, int effects) speed = (M_Random () - 128) * (1./200); particle->Vel.X += speed * an.Cos(); particle->Vel.Y += speed * an.Sin(); - particle->Vel.Z -= 1. / 80; - particle->Acc.Z -= 1. / 40; + particle->Vel.Z += 1. / 80; + particle->Acc.Z += 1. / 40; if (M_Random () & 7) particle->color = grey2; else diff --git a/src/p_effect.h b/src/p_effect.h index 033bf042c..614702a49 100644 --- a/src/p_effect.h +++ b/src/p_effect.h @@ -59,13 +59,15 @@ struct particle_t DVector3 Acc; BYTE ttl; BYTE trans; - WORD size; + double size; + double sizestep; BYTE bright; BYTE fade; int color; WORD tnext; WORD snext; subsector_t * subsector; + bool notimefreeze; }; extern particle_t *Particles; @@ -83,7 +85,7 @@ particle_t *JitterParticle (int ttl); particle_t *JitterParticle (int ttl, double drift); void P_ThinkParticles (void); -void P_SpawnParticle(const DVector3 &pos, const DVector3 &vel, const DVector3 &accel, PalEntry color, bool fullbright, double startalpha, int lifetime, WORD size, double fadestep); +void P_SpawnParticle(const DVector3 &pos, const DVector3 &vel, const DVector3 &accel, PalEntry color, double startalpha, int lifetime, double size, double fadestep, double sizestep, int flags = 0); void P_InitEffects (void); void P_RunEffects (void); diff --git a/src/p_tick.cpp b/src/p_tick.cpp index 032aa8bf5..f0f1e2ea8 100644 --- a/src/p_tick.cpp +++ b/src/p_tick.cpp @@ -117,10 +117,7 @@ void P_Ticker (void) // Since things will be moving, it's okay to interpolate them in the renderer. r_NoInterpolate = false; - if (!bglobal.freeze && !(level.flags2 & LEVEL2_FROZEN)) - { - P_ThinkParticles (); // [RH] make the particles think - } + P_ThinkParticles(); // [RH] make the particles think for (i = 0; iPos.Z - ViewPos.Z); + ty = particle->Pos.Z - ViewPos.Z; y1 = xs_RoundToInt(CenterY - (ty + psize) * yscale); y2 = xs_RoundToInt(CenterY - (ty - psize) * yscale); diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index f171edaeb..4d88a56fc 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -513,6 +513,36 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetCrouchFactor) return 0; } +//========================================================================== +// +// GetCVar +// +// NON-ACTION function that works like ACS's GetCVar. +// +//========================================================================== + +DEFINE_ACTION_FUNCTION_PARAMS(AActor, GetCVar) +{ + if (numret > 0) + { + assert(ret != nullptr); + PARAM_SELF_PROLOGUE(AActor); + PARAM_STRING(cvarname); + + FBaseCVar *cvar = GetCVar(self, cvarname); + if (cvar == nullptr) + { + ret->SetFloat(0); + } + else + { + ret->SetFloat(cvar->GetGenericRep(CVAR_Float).Float); + } + return 1; + } + return 0; +} + //=========================================================================== // // __decorate_internal_state__ @@ -3147,6 +3177,7 @@ enum SPFflag SPF_RELVEL = 1 << 2, SPF_RELACCEL = 1 << 3, SPF_RELANG = 1 << 4, + SPF_NOTIMEFREEZE = 1 << 5, }; DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnParticle) @@ -3155,7 +3186,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnParticle) PARAM_COLOR (color); PARAM_INT_OPT (flags) { flags = 0; } PARAM_INT_OPT (lifetime) { lifetime = 35; } - PARAM_INT_OPT (size) { size = 1; } + PARAM_FLOAT_OPT (size) { size = 1.; } PARAM_ANGLE_OPT (angle) { angle = 0.; } PARAM_FLOAT_OPT (xoff) { xoff = 0; } PARAM_FLOAT_OPT (yoff) { yoff = 0; } @@ -3168,11 +3199,11 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnParticle) PARAM_FLOAT_OPT (accelz) { accelz = 0; } PARAM_FLOAT_OPT (startalpha) { startalpha = 1.; } PARAM_FLOAT_OPT (fadestep) { fadestep = -1.; } + PARAM_FLOAT_OPT (sizestep) { sizestep = 0.; } startalpha = clamp(startalpha, 0., 1.); if (fadestep > 0) fadestep = clamp(fadestep, 0., 1.); - size = clamp(size, 0, 65535); // Clamp to word - + size = fabs(size); if (lifetime != 0) { if (flags & SPF_RELANG) angle += self->Angles.Yaw; @@ -3199,7 +3230,7 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SpawnParticle) acc.X = accelx * c + accely * s; acc.Y = accelx * s - accely * c; } - P_SpawnParticle(self->Vec3Offset(pos), vel, acc, color, !!(flags & SPF_FULLBRIGHT), startalpha, lifetime, size, fadestep); + P_SpawnParticle(self->Vec3Offset(pos), vel, acc, color, startalpha, lifetime, size, fadestep, sizestep, flags); } return 0; } @@ -6900,10 +6931,10 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_FaceMovementDirection) { DAngle current = mobj->Angles.Pitch; const DVector2 velocity = mobj->Vel.XY(); - DAngle pitch = VecToAngle(velocity.Length(), -mobj->Vel.Z); + DAngle pitch = VecToAngle(velocity.Length(), mobj->Vel.Z); if (pitchlimit > 0) { - DAngle pdelta = deltaangle(current, pitch); + DAngle pdelta = deltaangle(-current, pitch); if (fabs(pdelta) > pitchlimit) { diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index cc0569fff..2ce48b036 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -47,6 +47,7 @@ ACTOR Actor native //: Thinker native int GetSpawnHealth(); native int GetGibHealth(); native float GetCrouchFactor(int ptr = AAPTR_PLAYER1); + native float GetCVar(string cvar); // Action functions // Meh, MBF redundant functions. Only for DeHackEd support. @@ -214,7 +215,7 @@ ACTOR Actor native //: Thinker native void A_SetScale(float scalex, float scaley = 0, int ptr = AAPTR_DEFAULT, bool usezero = false); native void A_SetMass(int mass); native void A_SpawnDebris(class spawntype, bool transfer_translation = false, float mult_h = 1, float mult_v = 1); - native void A_SpawnParticle(color color1, int flags = 0, int lifetime = 35, int size = 1, float angle = 0, float xoff = 0, float yoff = 0, float zoff = 0, float velx = 0, float vely = 0, float velz = 0, float accelx = 0, float accely = 0, float accelz = 0, float startalphaf = 1, float fadestepf = -1); + native void A_SpawnParticle(color color1, int flags = 0, int lifetime = 35, float size = 1, float angle = 0, float xoff = 0, float yoff = 0, float zoff = 0, float velx = 0, float vely = 0, float velz = 0, float accelx = 0, float accely = 0, float accelz = 0, float startalphaf = 1, float fadestepf = -1, float sizestep = 0); native state A_CheckSight(state label); native void A_ExtChase(bool usemelee, bool usemissile, bool playactive = true, bool nightmarefast = false); native void A_DropInventory(class itemtype); diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index 911e1036b..f5072d55e 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -539,6 +539,7 @@ enum SPF_RELVEL = 1 << 2, SPF_RELACCEL = 1 << 3, SPF_RELANG = 1 << 4, + SPF_NOTIMEFREEZE = 1 << 5, SPF_RELATIVE = SPF_RELPOS|SPF_RELVEL|SPF_RELACCEL|SPF_RELANG };