Showing posts with label death delay. Show all posts
Showing posts with label death delay. Show all posts

Sunday, January 6, 2008

Delayed Death after Getting Shot

By: Lord Jesus

This cheat comes to us by way of an idea from blogger, person. Here is an excerpt of his comment to Super "Kill Me" on Demand in which he proposed the idea:

    I have a suggestion... Maybe there could be a client side delay so that when the tank detects that it has been shot, it will let you live for just a little longer, giving you a short time in which you could kill your killer before you died. Like for example. I get in a fight with a shock waver. I wait for him to land, but am hit before he lands. Instead of exploding, I would have 2 seconds to kill him first.

The delayed death cheat can also be useful for cheaters with slow connections and/or moderate to high lag since the delay can possibly be attributed to lag. Some administrators, though, may kick players who lag or seem to lag until they are able to fix the problem especially if other players are complaining about it.

Being that I'm not a software developer, this may look a bit rough; however, it works. Suggestions to clean it up or to make it easier are always welcome.

Anyway, I found in my experiments that setting the delay to 2.0f seemed a little long. It would be easily noticed, and you would be singled out shortly for cheating. In this example, I use 1.0f which turns out to be a little closer to two seconds than it does one. You can adjust that value to suit your liking. Perhaps, you can shorten it to make it less noticeable yet still give you just enough time to pop off a shot or two at the player who shot you. Additionally, my idea was to have a countdown on the display. Being that the time is short, I decided to go simply with "Death imminent" as a quick warning for you to get your shot(s) off before you blow up.

I didn't include a delay for Thief. The idea is to shoot a person who actually shot you. I also didn't include a delay for Steamroller; however, implementing a delay for that as well wouldn't be difficult.

All of the changes that we will make will be in the file, playing.cxx.

At the beginning, of playing.cxx, you will see a section for "system includes":

// system includes
#ifdef _WIN32
#include
#include
#include
#include
#else
#include
#include
#include
#include
#include
#endif
#include

At the end of that, add "int deathStart;" so that the section now reads like this:

// system includes
#ifdef _WIN32
#include
#include
#include
#include
#else
#include
#include
#include
#include
#include
#endif
#include
int deathStart;

Next, search for "destructCountdown" and you will find these lines:

float pauseCountdown = 0.0f;
float destructCountdown = 0.0f

Just below the "destructCountdown" line, add this new line:

float deathCountdown = 0.0f;

The lines should now read like this:

float pauseCountdown = 0.0f;
float destructCountdown = 0.0f;
float deathCountdown = 0.0f;

Search for "destructCountdown" again, and you will find this section:

static void updateDestructCountdown(float dt)
{
if (!myTank) {
destructCountdown = 0.0f;
}
if (destructCountdown > 0.0f && !myTank->isAlive()) {
destructCountdown = 0.0f;
hud->setAlert(1, NULL, 0.0f, true);
}
if (destructCountdown > 0.0f) {
const int oldDestructCountdown = (int)(destructCountdown + 0.99f);
destructCountdown -= dt;
if (destructCountdown <= 0.0f) {
// now actually destruct
gotBlowedUp( myTank, SelfDestruct, myTank->getId() );

hud->setAlert(1, NULL, 0.0f, true);
} else if ((int)(destructCountdown + 0.99f) != oldDestructCountdown) {
// update countdown alert
char msgBuf[40];
sprintf(msgBuf, "Self Destructing in %d", (int)(destructCountdown + 0.99f));
hud->setAlert(1, msgBuf, 1.0f, false);
}
}
return;
}

Below that, add these lines:

static void updateDeathCountdown(float dt)
{
if (!myTank) {
deathCountdown = 0.0f;
}
if (deathCountdown > 0.0f && !myTank->isAlive()) {
deathCountdown = 0.0f;
hud->setAlert(1, NULL, 0.0f, true);
}
if (deathCountdown > 0.0f) {
const int oldDeathCountdown = (int)(deathCountdown + 0.99f);
deathCountdown -= dt;
if (deathCountdown <= 0.0f) {
// blow up my tank and then reset
// deathCountdown & deathStart back to zero
gotBlowedUp(myTank,GotShot,deathStart);
deathCountdown = 0.0f;
deathStart = 0;

hud->setAlert(1, NULL, 0.0f, true);
} else if ((int)(deathCountdown + 0.99f) != oldDeathCountdown) {
// update countdown alert
char msgBuf[40];
sprintf(msgBuf, "Death imminent");
hud->setAlert(1, msgBuf, 1.0f, false);
}
}
return;
}

Search for "destructCountdown" one more time, and you will find this section:

// update the countdowns
updatePauseCountdown(dt);
updateDestructCountdown(dt);

Below that, add "updateDeathCountdown(dt);" so that the section now reads like this:

// update the countdowns
updatePauseCountdown(dt);
updateDestructCountdown(dt);
updateDeathCountdown(dt);

Now, search for "used later", and you will find this section:

// used later
float waterLevel = World::getWorld()->getWaterLevel();

if (hit) {
// i got shot! terminate the shot that hit me and blow up.
// force shot to terminate locally immediately (no server round trip);
// this is to ensure that we don't get shot again by the same shot
// after dropping our shield flag.
if (hit->isStoppedByHit())
serverLink->sendEndShot(hit->getPlayer(), hit->getShotId(), 1);

FlagType* killerFlag = hit->getFlag();
bool stopShot;

if (killerFlag == Flags::Thief) {
if (myTank->getFlag() != Flags::Null) {
serverLink->sendTransferFlag(myTank->getId(), hit->getPlayer());
}
stopShot = true;
}
else {
stopShot = gotBlowedUp(myTank, GotShot, hit->getPlayer(), hit);
}

if (stopShot || hit->isStoppedByHit()) {
Player* hitter = lookupPlayer(hit->getPlayer());
if (hitter) hitter->endShot(hit->getShotId());
}
}
// if not dead yet, see if i'm sitting on death

Just after the comments at the beginning of the "if (hit)" section, add these lines:

// skip this if the Death Counter is counting
if (deathCountdown > 0.0f) return;

The section should now read like this:

if (hit) {
// i got shot! terminate the shot that hit me and blow up.
// force shot to terminate locally immediately (no server round trip);
// this is to ensure that we don't get shot again by the same shot
// after dropping our shield flag.

// skip this if the Death Counter is counting
if (deathCountdown > 0.0f) return;

Next, notice these lines in particular in the "if (hit)" section:

else {
stopShot = gotBlowedUp(myTank, GotShot, hit->getPlayer(), hit);
}

Replace "stopShot = gotBlowedUp(myTank, GotShot, hit->getPlayer(), hit);" with these lines:

deathCountdown = 1.0f;
deathStart = hit->getPlayer();

// imminent death alert
char msgBuf[40];
sprintf(msgBuf, "Death imminent");
hud->setAlert(1, msgBuf, 1.0f, false);

The section should now read like this:

else {
deathCountdown = 1.0f;
deathStart = hit->getPlayer();

// imminent death alert
char msgBuf[40];
sprintf(msgBuf, "Death imminent");
hud->setAlert(1, msgBuf, 1.0f, false);
}

The entire section after your changes should now look like this:

// used later
float waterLevel = World::getWorld()->getWaterLevel();

if (hit) {
// i got shot! terminate the shot that hit me and blow up.
// force shot to terminate locally immediately (no server round trip);
// this is to ensure that we don't get shot again by the same shot
// after dropping our shield flag.

// skip this if the Death Counter is counting
if (deathCountdown > 0.0f) return;

if (hit->isStoppedByHit())
serverLink->sendEndShot(hit->getPlayer(), hit->getShotId(), 1);

FlagType* killerFlag = hit->getFlag();
bool stopShot;

if (killerFlag == Flags::Thief) {
if (myTank->getFlag() != Flags::Null) {
serverLink->sendTransferFlag(myTank->getId(), hit->getPlayer());
}
stopShot = true;
}
else {
deathCountdown = 1.0f;
deathStart = hit->getPlayer();

// imminent death alert
char msgBuf[40];
sprintf(msgBuf, "Death imminent");
hud->setAlert(1, msgBuf, 1.0f, false);
}

if (stopShot || hit->isStoppedByHit()) {
Player* hitter = lookupPlayer(hit->getPlayer());
if (hitter) hitter->endShot(hit->getShotId());
}
}
// if not dead yet, see if i'm sitting on death

I realize that the HUD alert is redundant. I noticed that there was a delay in the alert so I added it in the above section, as well, so that it would display more quickly.

What we've established so far is the creation of a couple of values, deathCountdown and deathStart, which we will use for our countdown, and we set their defaults (e.g., deathCountdown = 0.0f). We also added the the code for the actual countdown and time keeping. Next, we initiate the countdown when we get shot by setting deathCountdown to 1.0f, and we display an alert for "Death imminent". We also retain the identity of the player who initially shot us and started the countdown by setting the value of deathStart to represent the identity of that player so that we can use it later for blowing up when the countdown completes. We skip the "if (hit)" section if there is already a countdown in progress so that we don't start a new countdown for each shot that hits us once a countdown has already started (i.e., we ignore all other shots that may hit us after the countdown begins). When the countdown finishes, we blow up (and as a result lose a point, and the killer gets his or her point), and the countdown values, deathCountdown and deathStart, are then set back to 0.0f and 0, respectively.

Notice that we use "return" to skip the "if (hit)" section. We do that since using a line such as "stopShot = true" when deathCountdown > 0.0f will get us kicked for wrong end shot detections. Essentially, the server will kick us if we are ending other players' shots that hit us without our tank blowing up. That technique of avoiding getting blown up was utilized by cheaters of yore, and it was known as end shot cheating. I know that because I, myself, used to be one of the culprits long ago. Anyway, it is better to ignore a shot altogether rather than try to end it without blowing up. That's why god mode cheating works and end shot cheating no longer does.

This next part is left over from when I was experimenting with a previous revision of this cheat. The idea was to bypass blowing up until a countdown had finished. It may not be necessary (I haven't tried it without it); but, this cheat works with it in place. So, if it ain't broke, don't fix it :P If anyone wants to experiment with it, let us know how it worked.

Search for "tank && (tank->getTeam() == ObserverTeam" and you will find this section:

static bool gotBlowedUp(BaseLocalPlayer* tank,
BlowedUpReason reason,
PlayerId killer,
const ShotPath* hit, int phydrv)
{
if (tank && (tank->getTeam() == ObserverTeam || !tank->isAlive()))
return false;

Change "(tank && (tank->getTeam() == ObserverTeam || !tank->isAlive()))" to this:

((tank && (tank->getTeam() == ObserverTeam || !tank->isAlive()) || deathCountdown > 0.0f))

Yeah, I know it's "fugly". Anyway, the section should now read like this:

static bool gotBlowedUp(BaseLocalPlayer* tank,
BlowedUpReason reason,
PlayerId killer,
const ShotPath* hit, int phydrv)
{
if ((tank && (tank->getTeam() == ObserverTeam || !tank->isAlive()) || deathCountdown > 0.0f))
return false;

Save the file, compile your new client, and you're finished. Thank you to blogger, person, for bringing this idea to us.

As always...

Have fun!

>:)

**********

Related posts:

Instant Self Destruct
Ultimate Pausing