mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-11 07:12:02 +00:00
- reworked the obituary system to use scripted virtual overrides. Let's hope this solves the problems with the original code, now that any actor needing special treatment can override it.
This commit is contained in:
parent
851984efe0
commit
fc125f7eaf
8 changed files with 73 additions and 99 deletions
|
@ -295,8 +295,6 @@ void PClassActor::DeriveData(PClass *newclass)
|
||||||
PClassActor *newa = static_cast<PClassActor *>(newclass);
|
PClassActor *newa = static_cast<PClassActor *>(newclass);
|
||||||
|
|
||||||
newa->DefaultStateUsage = DefaultStateUsage;
|
newa->DefaultStateUsage = DefaultStateUsage;
|
||||||
newa->Obituary = Obituary;
|
|
||||||
newa->HitObituary = HitObituary;
|
|
||||||
newa->BloodColor = BloodColor;
|
newa->BloodColor = BloodColor;
|
||||||
newa->distancecheck = distancecheck;
|
newa->distancecheck = distancecheck;
|
||||||
|
|
||||||
|
|
|
@ -290,8 +290,6 @@ public:
|
||||||
|
|
||||||
TArray<PClassActor *> VisibleToPlayerClass;
|
TArray<PClassActor *> VisibleToPlayerClass;
|
||||||
|
|
||||||
FString Obituary; // Player was killed by this actor
|
|
||||||
FString HitObituary; // Player was killed by this actor in melee
|
|
||||||
PalEntry BloodColor; // Colorized blood
|
PalEntry BloodColor; // Colorized blood
|
||||||
|
|
||||||
FDropItem *DropItems;
|
FDropItem *DropItems;
|
||||||
|
|
|
@ -62,7 +62,6 @@
|
||||||
#include "g_levellocals.h"
|
#include "g_levellocals.h"
|
||||||
#include "events.h"
|
#include "events.h"
|
||||||
|
|
||||||
static FRandom pr_obituary ("Obituary");
|
|
||||||
static FRandom pr_botrespawn ("BotRespawn");
|
static FRandom pr_botrespawn ("BotRespawn");
|
||||||
static FRandom pr_killmobj ("ActorDie");
|
static FRandom pr_killmobj ("ActorDie");
|
||||||
FRandom pr_damagemobj ("ActorTakeDamage");
|
FRandom pr_damagemobj ("ActorTakeDamage");
|
||||||
|
@ -186,14 +185,11 @@ void ClientObituary (AActor *self, AActor *inflictor, AActor *attacker, int dmgf
|
||||||
const char *message;
|
const char *message;
|
||||||
const char *messagename;
|
const char *messagename;
|
||||||
char gendermessage[1024];
|
char gendermessage[1024];
|
||||||
int gender;
|
|
||||||
|
|
||||||
// No obituaries for non-players, voodoo dolls or when not wanted
|
// No obituaries for non-players, voodoo dolls or when not wanted
|
||||||
if (self->player == NULL || self->player->mo != self || !show_obituaries)
|
if (self->player == NULL || self->player->mo != self || !show_obituaries)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
gender = self->player->userinfo.GetGender();
|
|
||||||
|
|
||||||
// Treat voodoo dolls as unknown deaths
|
// Treat voodoo dolls as unknown deaths
|
||||||
if (inflictor && inflictor->player && inflictor->player->mo != inflictor)
|
if (inflictor && inflictor->player && inflictor->player->mo != inflictor)
|
||||||
MeansOfDeath = NAME_None;
|
MeansOfDeath = NAME_None;
|
||||||
|
@ -217,93 +213,47 @@ void ClientObituary (AActor *self, AActor *inflictor, AActor *attacker, int dmgf
|
||||||
}
|
}
|
||||||
|
|
||||||
FString obit = DamageTypeDefinition::GetObituary(mod);
|
FString obit = DamageTypeDefinition::GetObituary(mod);
|
||||||
if (obit.IsNotEmpty()) messagename = obit;
|
if (attacker == nullptr) messagename = obit;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
switch (mod)
|
switch (mod)
|
||||||
{
|
{
|
||||||
case NAME_Suicide: messagename = "OB_SUICIDE"; break;
|
case NAME_Suicide: message = "$OB_SUICIDE"; break;
|
||||||
case NAME_Falling: messagename = "OB_FALLING"; break;
|
case NAME_Falling: message = "$OB_FALLING"; break;
|
||||||
case NAME_Crush: messagename = "OB_CRUSH"; break;
|
case NAME_Crush: message = "$OB_CRUSH"; break;
|
||||||
case NAME_Exit: messagename = "OB_EXIT"; break;
|
case NAME_Exit: message = "$OB_EXIT"; break;
|
||||||
case NAME_Drowning: messagename = "OB_WATER"; break;
|
case NAME_Drowning: message = "$OB_WATER"; break;
|
||||||
case NAME_Slime: messagename = "OB_SLIME"; break;
|
case NAME_Slime: message = "$OB_SLIME"; break;
|
||||||
case NAME_Fire: if (attacker == NULL) messagename = "OB_LAVA"; break;
|
case NAME_Fire: messagename = "$OB_LAVA"; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for being killed by a voodoo doll.
|
// Check for being killed by a voodoo doll.
|
||||||
if (inflictor && inflictor->player && inflictor->player->mo != inflictor)
|
if (inflictor && inflictor->player && inflictor->player->mo != inflictor)
|
||||||
{
|
{
|
||||||
messagename = "OB_VOODOO";
|
messagename = "$OB_VOODOO";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (messagename != NULL)
|
|
||||||
message = GStrings(messagename);
|
|
||||||
|
|
||||||
if (attacker != NULL && message == NULL)
|
if (attacker != NULL && message == NULL)
|
||||||
{
|
{
|
||||||
if (attacker == self)
|
if (attacker == self)
|
||||||
{
|
{
|
||||||
message = GStrings("OB_KILLEDSELF");
|
message = "$OB_KILLEDSELF";
|
||||||
}
|
|
||||||
else if (attacker->player == NULL)
|
|
||||||
{
|
|
||||||
if (mod == NAME_Telefrag)
|
|
||||||
{
|
|
||||||
message = GStrings("OB_MONTELEFRAG");
|
|
||||||
}
|
|
||||||
else if (mod == NAME_Melee && attacker->GetClass()->HitObituary.IsNotEmpty())
|
|
||||||
{
|
|
||||||
message = attacker->GetClass()->HitObituary;
|
|
||||||
}
|
|
||||||
else if (attacker->GetClass()->Obituary.IsNotEmpty())
|
|
||||||
{
|
|
||||||
message = attacker->GetClass()->Obituary;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (message == NULL && attacker != NULL && attacker->player != NULL)
|
|
||||||
{
|
|
||||||
if (self->player != attacker->player && self->IsTeammate(attacker))
|
|
||||||
{
|
|
||||||
self = attacker;
|
|
||||||
gender = self->player->userinfo.GetGender();
|
|
||||||
mysnprintf (gendermessage, countof(gendermessage), "OB_FRIENDLY%c", '1' + (pr_obituary() & 3));
|
|
||||||
message = GStrings(gendermessage);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (mod == NAME_Telefrag) message = GStrings("OB_MPTELEFRAG");
|
IFVIRTUALPTR(attacker, AActor, GetObituary)
|
||||||
if (message == NULL)
|
|
||||||
{
|
{
|
||||||
if (inflictor != NULL && inflictor->GetClass()->Obituary.IsNotEmpty())
|
VMValue params[] = { attacker, self, inflictor, mod.GetIndex(), !!(dmgflags & DMG_PLAYERATTACK) };
|
||||||
{
|
FString ret;
|
||||||
message = inflictor->GetClass()->Obituary;
|
VMReturn rett(&ret);
|
||||||
}
|
GlobalVMStack.Call(func, params, countof(params), &rett, 1);
|
||||||
if (message == NULL && (dmgflags & DMG_PLAYERATTACK) && attacker->player->ReadyWeapon != NULL)
|
if (ret.IsNotEmpty()) message = ret;
|
||||||
{
|
|
||||||
message = attacker->player->ReadyWeapon->GetClass()->Obituary;
|
|
||||||
}
|
|
||||||
if (message == NULL)
|
|
||||||
{
|
|
||||||
switch (mod)
|
|
||||||
{
|
|
||||||
case NAME_BFGSplash: messagename = "OB_MPBFG_SPLASH"; break;
|
|
||||||
case NAME_Railgun: messagename = "OB_RAILGUN"; break;
|
|
||||||
}
|
|
||||||
if (messagename != NULL)
|
|
||||||
message = GStrings(messagename);
|
|
||||||
}
|
|
||||||
if (message == NULL)
|
|
||||||
{
|
|
||||||
message = attacker->GetClass()->Obituary;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else attacker = self; // for the message creation
|
if (message == nullptr) message = messagename; // fallback to defaults if possible.
|
||||||
|
if (attacker->player == nullptr) attacker = self; // for the message creation
|
||||||
|
|
||||||
if (message != NULL && message[0] == '$')
|
if (message != NULL && message[0] == '$')
|
||||||
{
|
{
|
||||||
|
@ -319,7 +269,7 @@ void ClientObituary (AActor *self, AActor *inflictor, AActor *attacker, int dmgf
|
||||||
if (message == NULL || strlen(message) <= 0)
|
if (message == NULL || strlen(message) <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SexMessage (message, gendermessage, gender,
|
SexMessage (message, gendermessage, self->player->userinfo.GetGender(),
|
||||||
self->player->userinfo.GetName(), attacker->player->userinfo.GetName());
|
self->player->userinfo.GetName(), attacker->player->userinfo.GetName());
|
||||||
Printf (PRINT_MEDIUM, "%s\n", gendermessage);
|
Printf (PRINT_MEDIUM, "%s\n", gendermessage);
|
||||||
}
|
}
|
||||||
|
|
|
@ -317,8 +317,6 @@ DEFINE_FIELD(AActor, SelfDamageFactor)
|
||||||
DEFINE_FIELD(AActor, StealthAlpha)
|
DEFINE_FIELD(AActor, StealthAlpha)
|
||||||
DEFINE_FIELD(AActor, WoundHealth)
|
DEFINE_FIELD(AActor, WoundHealth)
|
||||||
|
|
||||||
DEFINE_FIELD(PClassActor, Obituary)
|
|
||||||
DEFINE_FIELD(PClassActor, HitObituary)
|
|
||||||
//DEFINE_FIELD(PClassActor, BloodColor)
|
//DEFINE_FIELD(PClassActor, BloodColor)
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
|
@ -960,26 +960,6 @@ DEFINE_PROPERTY(alpha, F, Actor)
|
||||||
defaults->Alpha = id;
|
defaults->Alpha = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
DEFINE_PROPERTY(obituary, S, Actor)
|
|
||||||
{
|
|
||||||
PROP_STRING_PARM(str, 0);
|
|
||||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
|
|
||||||
static_cast<PClassActor *>(info)->Obituary = str;
|
|
||||||
}
|
|
||||||
|
|
||||||
//==========================================================================
|
|
||||||
//
|
|
||||||
//==========================================================================
|
|
||||||
DEFINE_PROPERTY(hitobituary, S, Actor)
|
|
||||||
{
|
|
||||||
PROP_STRING_PARM(str, 0);
|
|
||||||
assert(info->IsKindOf(RUNTIME_CLASS(PClassActor)));
|
|
||||||
static_cast<PClassActor *>(info)->HitObituary = str;
|
|
||||||
}
|
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
|
@ -196,9 +196,8 @@ class Actor : Thinker native
|
||||||
native int WoundHealth; // Health needed to enter wound state
|
native int WoundHealth; // Health needed to enter wound state
|
||||||
//native color BloodColor; // won't be accessible for now because it needs refactoring to remove the 255-translations limit.
|
//native color BloodColor; // won't be accessible for now because it needs refactoring to remove the 255-translations limit.
|
||||||
|
|
||||||
native meta String Obituary; // Player was killed by this actor
|
meta String Obituary; // Player was killed by this actor
|
||||||
native meta String HitObituary; // Player was killed by this actor in melee
|
meta String HitObituary; // Player was killed by this actor in melee
|
||||||
|
|
||||||
meta double DeathHeight; // Height on normal death
|
meta double DeathHeight; // Height on normal death
|
||||||
meta double BurnHeight; // Height on burning death
|
meta double BurnHeight; // Height on burning death
|
||||||
meta int GibHealth; // Negative health below which this monster dies an extreme death
|
meta int GibHealth; // Negative health below which this monster dies an extreme death
|
||||||
|
@ -216,6 +215,8 @@ class Actor : Thinker native
|
||||||
meta double FastSpeed; // speed in fast mode
|
meta double FastSpeed; // speed in fast mode
|
||||||
|
|
||||||
Property prefix: none;
|
Property prefix: none;
|
||||||
|
Property Obituary: Obituary;
|
||||||
|
Property HitObituary: HitObituary;
|
||||||
Property MeleeDamage: MeleeDamage;
|
Property MeleeDamage: MeleeDamage;
|
||||||
Property MeleeSound: MeleeSound;
|
Property MeleeSound: MeleeSound;
|
||||||
Property MissileHeight: MissileHeight;
|
Property MissileHeight: MissileHeight;
|
||||||
|
@ -423,6 +424,19 @@ class Actor : Thinker native
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual String GetObituary(Actor victim, Actor inflictor, Name mod, bool playerattack)
|
||||||
|
{
|
||||||
|
if (mod == 'Telefrag')
|
||||||
|
{
|
||||||
|
return "$OB_MONTELEFRAG";
|
||||||
|
}
|
||||||
|
else if (mod == 'Melee' && HitObituary.Length() > 0)
|
||||||
|
{
|
||||||
|
return HitObituary;
|
||||||
|
}
|
||||||
|
return Obituary;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
native static class<Actor> GetReplacement(class<Actor> cls);
|
native static class<Actor> GetReplacement(class<Actor> cls);
|
||||||
native static class<Actor> GetReplacee(class<Actor> cls);
|
native static class<Actor> GetReplacee(class<Actor> cls);
|
||||||
|
|
|
@ -89,6 +89,12 @@ class Weapon : StateProvider native
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override String GetObituary(Actor victim, Actor inflictor, Name mod, bool playerattack)
|
||||||
|
{
|
||||||
|
// Weapons may never return HitObituary by default. Override this if it is needed.
|
||||||
|
return Obituary;
|
||||||
|
}
|
||||||
|
|
||||||
action void A_GunFlash(statelabel flashlabel = null, int flags = 0)
|
action void A_GunFlash(statelabel flashlabel = null, int flags = 0)
|
||||||
{
|
{
|
||||||
let player = player;
|
let player = player;
|
||||||
|
|
|
@ -119,6 +119,36 @@ class PlayerPawn : Actor native
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override String GetObituary(Actor victim, Actor inflictor, Name mod, bool playerattack)
|
||||||
|
{
|
||||||
|
if (victim.player != player && victim.IsTeammate(self))
|
||||||
|
{
|
||||||
|
victim = self;
|
||||||
|
return String.Format("$OB_FRIENDLY%c", random[Obituary](49, 53));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (mod == 'Telefrag') return "$OB_MPTELEFRAG";
|
||||||
|
|
||||||
|
String message;
|
||||||
|
if (inflictor != NULL)
|
||||||
|
{
|
||||||
|
message = inflictor.GetObituary(victim, inflictor, mod, playerattack);
|
||||||
|
}
|
||||||
|
if (message.Length() == 0 && playerattack && player.ReadyWeapon != NULL)
|
||||||
|
{
|
||||||
|
message = player.ReadyWeapon.GetObituary(victim, inflictor, mod, playerattack);
|
||||||
|
}
|
||||||
|
if (message.Length() == 0)
|
||||||
|
{
|
||||||
|
if (mod == 'BFGSplash') return "$OB_MPBFG_SPLASH";
|
||||||
|
if (mod == 'Railgun') return "$OB_RAILGUN";
|
||||||
|
message = Obituary;
|
||||||
|
}
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This is for SBARINFO.
|
// This is for SBARINFO.
|
||||||
int, int GetEffectTicsForItem(class<Inventory> item)
|
int, int GetEffectTicsForItem(class<Inventory> item)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue