6682f2282f0e0

6682f2282f712
1 Guest is here.
 

Topic: Damage numbers test Read 445 times  

6682f228300ccZylonBane

6682f22830133
Here's an experiment with adding damage numbers to SS2. Hey, Prey did it!
https://www.youtube.com/watch?v=-GHISGkGy6c

Can optionally combine consecutive damage received within a certain time window into a single popup, which is enabled in the above video.

Not sure if the numbers are big enough. Since they're HUD overlays, the size of the numbers is dependent on the HUD scale. Making them bigger would require a custom font, though it would be a font with only ten characters, so not much work to make.

One issue is that the numbers render behind the health bars, but that's just how custom overlays work, nothing we can do about it.

Code: [Select]
// Script configuration
const COMBINE_THRESHOLD = 250; // 250 works well for damage combining
const DMG_ANIM_TIME = 500;
const DMG_MAX_NUMS = 8;
const DMG_HUD_CON = "zbDmgCon";

// working variables
local _numList = [];
local xRef = int_ref();
local yRef = int_ref();
local xNum = 0;
local yNum = 0;
local t = 0;
local iter = 0;
local numObj = {};
local numPurge = 0;

// --------------------------------------------------------------------------------
class damageNumbers extends SqRootScript {
function OnDamage() {
local i, ai, hudObj, height, pos, num, lastDamage;
local m = message();
local AIHeights = [
["Assassin", 7.22],
["Human", 7.22],
["Midwife", 7.27],
["Protocol Droid", 6.72],
["Training Droid", 6.72],
["Once-Grunts", 7.42],
["Big Droids", 6.88],
["Rumbler", 8.61],
["SHODAN", 8.07]
];

// only display numbers for damage player caused
if (!Link.AnyExist("~CulpableFor", m.culprit, "Player")) {
return;
}

// ensure overlay manager exists in current map
if (ObjID(DMG_HUD_CON)) {
hudObj = ObjID(DMG_HUD_CON);
}
else {
hudObj = Object.Create("Marker");
Object.SetName(hudObj, DMG_HUD_CON)
Property.Set(hudObj, "Scripts", "Script 0", "zbNumHudControl");
}

// handle damage stacking and multiple damage sources on same projectile
lastDamage = 0;
if (ShockGame.SimTime() - (GetData("LastDmgTime") || 0) <= COMBINE_THRESHOLD) {
for (i = _numList.len() - 1; i >= 0; i--) {
if (_numList[i].obj == self) {
lastDamage = _numList.remove(i).text.tointeger();
break;
}
}
}
SetData("LastDmgTime", ShockGame.SimTime());

// create damage number
num = {obj = self, state=0, text=(m.damage + lastDamage).tostring(), pos=vector(), startTime=ShockGame.SimTime(), xOffset=0, yOffset=0, xArc=0};
pos = Object.Position(self);
height = 0;
// no way to get raw creature height or bounding box, so look up in a table
// (this is for human-sized AIs only; smaller AIs just use the object center)
foreach (ai in AIHeights) {
if (Object.InheritsFrom(self, ai[0])) {
height = ((ai[1] * (HasProperty("CretScale") ? GetProperty("CretScale") : 1)) / 2) * 0.5;
}
}
num.pos = vector(pos.x, pos.y, pos.z + height);

// add to render list
_numList.push(num);
if (_numList.len() > DMG_MAX_NUMS) {
_numList.remove(0);
}
SendMessage(hudObj, "Show");
}
}

// --------------------------------------------------------------------------------
// HUD controller
class zbNumHudControl extends SqRootScript {
function OnShow() {
ShockOverlay.AddHandler(dmgOverlay);
}

function OnEndScript() {
clobberAll();
}

function destructor() {
clobberAll();
}

function clobberAll() {
ShockOverlay.RemoveHandler(dmgOverlay);
_numList = [];
}
}

// --------------------------------------------------------------------------------
// Display damage numbers in HUD
class dmgOverlayClass extends IShockOverlayHandler {
function DrawHUD() {
ShockOverlay.SetCustomFont(0, "metafont", "intrface\\");
ShockOverlay.SetFont(2);
numPurge = -1;
for (iter = 0; iter < _numList.len(); iter++) {
numObj = _numList[iter];
if (numObj.state == 0) {
ShockOverlay.GetStringSize(numObj.text, xRef, yRef);
numObj.xOffset = xRef.tointeger() / 2;
numObj.yOffset = yRef.tointeger();
numObj.xArc = Data.RandFltNeg1to1();
numObj.state = 1;
}
if (numObj.state == 1) {
t = (ShockGame.SimTime() - numObj.startTime).tofloat() / DMG_ANIM_TIME;
if (t < 1) {
if (ShockOverlay.WorldToScreen(numObj.pos, xRef, yRef)) {
xNum = xRef.tointeger() - numObj.xOffset;
numObj.xOffset += numObj.xArc;
//yNum = (yRef.tointeger() - yOffset) - sqrt(1-(--t)*t) * 25;
yNum = (yRef.tointeger() - numObj.yOffset) - (1 - ((1 - t) * (1 - t))) * 30;
ShockOverlay.SetTextColor(0, 0, 0);
ShockOverlay.DrawString(numObj.text, xNum + 1, yNum + 1);
ShockOverlay.SetTextColor(250 - 70 * t, 20, 20);
ShockOverlay.DrawString(numObj.text, xNum, yNum);
}
}
else {
numObj.state = 2;
}
}
else {
numPurge = iter;
}
}
// clean up finished slots
if (numPurge > -1) {
_numList = _numList.slice(numPurge + 1);
if (_numList.len() == 0) {
ShockOverlay.RemoveHandler(dmgOverlay);
}
}
}
}

// This must follow the class definition
dmgOverlay <- dmgOverlayClass();
Acknowledged by: Chandlermaki

6682f22830412ZylonBane

6682f22830461
Speaking of which, for these sort of things is it the norm for the killing blow to display the potential damage, or the actual damage?

Like, should dropping a nuke on an earthworm display "-100000000", or "-1"?

6682f2283050dvoodoo47

6682f22830562
my preference would be actual damage, meaning if a worm has 8 hp, takes 24 points of damage and is slain, the number displayed is 24, not 8.
Acknowledged by: Chandlermaki
6682f228306e1
Another nice little addon. You do come up with some interesting ideas, and then apply them very well, ZB. I wish I had your talent.

6682f228307dfZylonBane

6682f22830830
Thanks but, y'know, I didn't come up with this sort of thing. I even cited Prey as the direct inspiration.

6682f228308c1voodoo47

6682f22830910
we are smarter than the Prey people.

6682f22830e5bsarge945

6682f22830eb1
Speaking of which, for these sort of things is it the norm for the killing blow to display the potential damage, or the actual damage?

Like, should dropping a nuke on an earthworm display "-100000000", or "-1"?

The potential damage number is arguably more useful, because it let's you know the true damage you're doing and how much overkill you're applying.

By the end of the game, hybrids will often die in 1 shot. By the damage numbers it might look like the pistol and assault rifle are doing the same damage because they both do an instant kill.

The numbers Mason, what do they mean?
Acknowledged by: Chandlermaki

6682f22830f7fZylonBane

6682f22830fd0
Welp, it turns out there's one scenario where using metaproperties to add scripts to objects is completely useless-- when the object is set to not inherit scripts. Sigh.

6682f228310a9voodoo47

6682f228310fc
yes, that one I really dislike, and the only thing you can do afaik is handle it locally, a map dml getting rid of the not inherit checkmark or adding the mod script on the concrete.

guess we could also handle this by simply editing the SCP maps and removing the few not inherit checkmarks permanently.

6682f228311a4ZylonBane

6682f228311f4
In this case the issue is more the gamesys. Several AI archetypes have scripts set with inherit disabled.

No choice but to assign directly to a script slot on those guys.
Acknowledged by: voodoo47

6682f228312cesarge945

6682f22831320
I asked a while ago in the SCP suggestions thread if there could be some effort to reduce or remove the don't inherit flag on as many objects as possible, specifically because of this.

Keypads are some of the worst offenders iirc.

6682f228313e7ZylonBane

6682f22831432
Most objects with Don't Inherit have it for a reason, because otherwise they'd inherit scripts that would mess things up.

The keypads thing was fixable because Irrational implemented two different ways to make keypads unhackable, presumably the awful way that requires a custom script first, then the better way by setting a negative code later.

6682f228314dfZylonBane

6682f22831532
Finally promoted this to the mods forum, since I've already put way more effort into this than I ever thought I would. Configurable color, automatic color, frame rate- and resolution-independent animation, dynamic font selection, yadda yadda.

6682f228317d6voodoo47

6682f22831834
already put way more effort into this than I ever thought I would.
by now you should know better.

Your name:
This box must be left blank:

The deck number where you shall meet Dr. Janice Polito:
1 Guest is here.
Having crossed the gorge, Anne is left on the final support of the monorail at the top of a ridge marking one of the foothills of Mt. Crick, just to her west.
Contact SMF 2.0.19 | SMF © 2016, Simple Machines | Terms and Policies
FEEP
6682f22832368