- 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:
Christoph Oelckers 2017-02-28 14:30:14 +01:00
parent 851984efe0
commit fc125f7eaf
8 changed files with 73 additions and 99 deletions

View file

@ -295,8 +295,6 @@ void PClassActor::DeriveData(PClass *newclass)
PClassActor *newa = static_cast<PClassActor *>(newclass);
newa->DefaultStateUsage = DefaultStateUsage;
newa->Obituary = Obituary;
newa->HitObituary = HitObituary;
newa->BloodColor = BloodColor;
newa->distancecheck = distancecheck;

View file

@ -290,8 +290,6 @@ public:
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
FDropItem *DropItems;

View file

@ -62,7 +62,6 @@
#include "g_levellocals.h"
#include "events.h"
static FRandom pr_obituary ("Obituary");
static FRandom pr_botrespawn ("BotRespawn");
static FRandom pr_killmobj ("ActorDie");
FRandom pr_damagemobj ("ActorTakeDamage");
@ -186,14 +185,11 @@ void ClientObituary (AActor *self, AActor *inflictor, AActor *attacker, int dmgf
const char *message;
const char *messagename;
char gendermessage[1024];
int gender;
// No obituaries for non-players, voodoo dolls or when not wanted
if (self->player == NULL || self->player->mo != self || !show_obituaries)
return;
gender = self->player->userinfo.GetGender();
// Treat voodoo dolls as unknown deaths
if (inflictor && inflictor->player && inflictor->player->mo != inflictor)
MeansOfDeath = NAME_None;
@ -217,93 +213,47 @@ void ClientObituary (AActor *self, AActor *inflictor, AActor *attacker, int dmgf
}
FString obit = DamageTypeDefinition::GetObituary(mod);
if (obit.IsNotEmpty()) messagename = obit;
if (attacker == nullptr) messagename = obit;
else
{
switch (mod)
{
case NAME_Suicide: messagename = "OB_SUICIDE"; break;
case NAME_Falling: messagename = "OB_FALLING"; break;
case NAME_Crush: messagename = "OB_CRUSH"; break;
case NAME_Exit: messagename = "OB_EXIT"; break;
case NAME_Drowning: messagename = "OB_WATER"; break;
case NAME_Slime: messagename = "OB_SLIME"; break;
case NAME_Fire: if (attacker == NULL) messagename = "OB_LAVA"; break;
case NAME_Suicide: message = "$OB_SUICIDE"; break;
case NAME_Falling: message = "$OB_FALLING"; break;
case NAME_Crush: message = "$OB_CRUSH"; break;
case NAME_Exit: message = "$OB_EXIT"; break;
case NAME_Drowning: message = "$OB_WATER"; break;
case NAME_Slime: message = "$OB_SLIME"; break;
case NAME_Fire: messagename = "$OB_LAVA"; break;
}
}
// Check for being killed by a voodoo doll.
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 == self)
{
message = GStrings("OB_KILLEDSELF");
message = "$OB_KILLEDSELF";
}
else if (attacker->player == NULL)
else
{
if (mod == NAME_Telefrag)
IFVIRTUALPTR(attacker, AActor, GetObituary)
{
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;
VMValue params[] = { attacker, self, inflictor, mod.GetIndex(), !!(dmgflags & DMG_PLAYERATTACK) };
FString ret;
VMReturn rett(&ret);
GlobalVMStack.Call(func, params, countof(params), &rett, 1);
if (ret.IsNotEmpty()) message = ret;
}
}
}
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
{
if (mod == NAME_Telefrag) message = GStrings("OB_MPTELEFRAG");
if (message == NULL)
{
if (inflictor != NULL && inflictor->GetClass()->Obituary.IsNotEmpty())
{
message = inflictor->GetClass()->Obituary;
}
if (message == NULL && (dmgflags & DMG_PLAYERATTACK) && attacker->player->ReadyWeapon != NULL)
{
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] == '$')
{
@ -319,7 +269,7 @@ void ClientObituary (AActor *self, AActor *inflictor, AActor *attacker, int dmgf
if (message == NULL || strlen(message) <= 0)
return;
SexMessage (message, gendermessage, gender,
SexMessage (message, gendermessage, self->player->userinfo.GetGender(),
self->player->userinfo.GetName(), attacker->player->userinfo.GetName());
Printf (PRINT_MEDIUM, "%s\n", gendermessage);
}

View file

@ -317,8 +317,6 @@ DEFINE_FIELD(AActor, SelfDamageFactor)
DEFINE_FIELD(AActor, StealthAlpha)
DEFINE_FIELD(AActor, WoundHealth)
DEFINE_FIELD(PClassActor, Obituary)
DEFINE_FIELD(PClassActor, HitObituary)
//DEFINE_FIELD(PClassActor, BloodColor)
//==========================================================================

View file

@ -960,26 +960,6 @@ DEFINE_PROPERTY(alpha, F, Actor)
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;
}
//==========================================================================
//
//==========================================================================

View file

@ -196,9 +196,8 @@ class Actor : Thinker native
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 meta String Obituary; // Player was killed by this actor
native meta String HitObituary; // Player was killed by this actor in melee
meta String Obituary; // Player was killed by this actor
meta String HitObituary; // Player was killed by this actor in melee
meta double DeathHeight; // Height on normal death
meta double BurnHeight; // Height on burning 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
Property prefix: none;
Property Obituary: Obituary;
Property HitObituary: HitObituary;
Property MeleeDamage: MeleeDamage;
Property MeleeSound: MeleeSound;
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> GetReplacee(class<Actor> cls);

View file

@ -89,6 +89,12 @@ class Weapon : StateProvider native
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)
{
let player = player;

View file

@ -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.
int, int GetEffectTicsForItem(class<Inventory> item)
{