Game Development Community

Schedule causing crash?

by James Hill · in Torque Game Engine · 10/26/2004 (8:40 pm) · 23 replies

I have a poison spell that applies damage every couple seconds. Currently I schedule a function that applies damage several times. But when I die from the damage, the game does a weird freeze then crashes. Can you not die with functions scheduled or the game crashes? Is the schedule what's even causing the crash? This is my code, if anyone has an idea of what is going wrong or a better way to go about this, your thoughts would be greatly appreciated.

%times = 5;
%amount = 5;
for(%index = 0; %index < %times; %index++)
{
	%this.schedule(2000 * %index, poison, %amount);
}

function Player::poison(%this, %amount)
{
	if(%this.getDamageLevel() <= 0) {
		return;
		}  // this isn't helping
	if(%this.getDamageLevel() != 0) {
		%this.applyDamage(%amount);
			
	}
	
}
Page «Previous 1 2
#1
10/26/2004 (10:15 pm)
As a random non-torque (but another type of) developer. Are you turning off the poison event when the character dies? If not the poison event will fire and not have an object to apply to, or worse, continue to apply it when you re-create the character.
#2
10/27/2004 (2:34 am)
I think FruitBaiInShades is right, if your player dies the poison function is called with an invalid pointer.
Solution: get the ID of the schedule and when the player dies cancel the schedule
for(%index = 0; %index < %times; %index++)
{
   $PoisonID = %this.schedule(2000 * %index, poison, %amount);
}

Player::onDeath(...)
{
  cancel($PoisonID);
}
Obviously, in this example, $PoisonID is a global variable, so you cannot have more than one player poisoned at the same time. I leave to you the solution for more players :)

Edit:
I see only now one thing, you shouldn't write a schedule function in a for cycle, write it in the poison function itself, practically the first time you explicity call the poison function, then inside the poison function schedule another call to itself and get the id of that schedule, practically you must have a single schedule function running at a time
function Player::poison(%this, %amount)
{   
   %this.applyDamage(%amount);           
   $PoisonID = %this.schedule(2000, poison, %amount);
}
#3
10/27/2004 (5:26 am)
No if an object is distroyed all scheduled events associated with it are cancelled.
#4
10/27/2004 (7:13 am)
@Michael,
really? could you tell me where in the code this happend? or where have you read it?
#5
10/27/2004 (7:17 am)
Actually Michael, in my experiance Schedualed events will continue untill they are stopped. So canceling a schedual that isn't needed is essential.

ps for each player do somthing like
for(%index = 0; %index < %times; %index++){ 
  %this.PoisonID = %this.schedule(2000 * %index, poison, %amount);
}

Player::onDeath(%this, %obj ...){  
if(%this.PoisonID  !$= "")
cancel(%this.PoisonID);
}
#6
10/27/2004 (7:56 am)
@Anthony, the for loop must be removed otherwise you store only the last ID in this way
#7
10/27/2004 (12:51 pm)
I actually didn't see a point to the loop at all it was just an example. . . from what I can tell the loop is used to make the time between each schedual longer. I think maybe you are trying to start all the scheduals at once which seem like a dangerous way to do it, more overhead. Instead make a function to poison, then in that function test to see if the player has health and is not cured, then if it passes that test have the function schedual itself to be called again. It should simplify the code.
#8
10/27/2004 (5:45 pm)
Thanks for the help guys. I implemented this new method, but i'm still having issues. Not sure if I'm declaring the PoisonID correctly or not.

//game.cs
function GameConnection::createPlayer(%this, %spawnPoint)
{
     // Create the player object
    %player = new Player() {
          ...
          PoisonID = "";
    }
}

function Player::poison(%this, %amount, %times)
{
     echo("Times " @ %times);
     echo("PlayerState " @ %this.getState());	
     if(%this.getState() !$= "Dead")
     {
          %this.applyDamage(%amount);
          echo("Poison Hurts");
          %times--;
		
          if(%times > 0) 
              %this.PoisonID = %this.schedule(2000, poison, %amount, %times);	
     }
}

function Player::onDeath( %this, %obj )
{
     echo("On Death Called");
     echo(%this.PoisonID);
     if(%this.PoisonID !$= "") {
        cancel(%this.PoisonID);
        echo("Poison Cancelled?");
        echo(%this.PoisonID);
        }	
}
I also moved the code within onDeath into PlayerClass::onDisabled and into because the Player::onDeath isn't getting called. With the code in the onDisabled, it echoes "On Death Called" but doesn't get inside the if statement.

This is the last few lines in the console log
Times 3
PlayerState Move
Poison hurts

Times 2
PlayerState Move
Poison hurts

Times 1
PlayerState Move

On Death Called

Poison hurts


Any help would be great. Before the game crashes, the screen shakes and wobbles (not sure how to describe it). Thanks :)
#9
10/27/2004 (6:10 pm)
Actually remove the test in ondeath. . .it doesn't need to be there, canceling nothing won't cause a crash, tell me if that works
#10
10/27/2004 (6:32 pm)
I'm still crashing without the check. I'm not exactly sure why the check should be taken out. I was thinking that that check was to see if something was scheduled, and then cancel it if it was. It looks to me like it's trying to apply damage after the ondeath is called. But this ondeath code is in PlayerClass::onDisabled along with the playdeathanimation and start fade. Am I doing this all wrong? Thanks
#11
10/27/2004 (6:55 pm)
You are right, place it in the onDisable


Ah I think I see the problem each Player method will pass 2 variables %this (the datablock) and %obj (the object instance), your %amount is actually the object instance. Personally I would make it a seperate function so you could poision non player things

so redo poison like this
function poison(%this, %amount, %times){
     echo("Times " @ %times);
     echo("PlayerState " @ %this.getState());
        if(%this.getState() !$= "Dead")     { 
         %this.applyDamage(%amount);  
        echo("Poison Hurts"); 
         %times--; 
               if(%times > 0) 
              %this.PoisonID = schedule(2000, 0,poison, %this, %amount, %times); 
       }
}
#12
10/27/2004 (7:07 pm)
Ohhh I found this nice thing
ConsoleFunction(isEventPending, bool, 2, 2, "isEventPending(%scheduleId);")
{
   argc;
   return Sim::isEventPending(dAtoi(argv[1]));
}
also looks like schedual need to be written as

%this.PoisonID = schedule(2000, 0,poison, %this, %amount, %times);
#13
10/28/2004 (5:08 am)
I missed what the 0 in the schedule was for. Using this, poison only gets called once. I'm going to check out this isEventPending and see if I can't get that working for me today - thanks for all your help.
#14
10/28/2004 (5:22 am)
The 0 can be replaced with a simgroup to monitor the schedual, which isn't ressisary. Can you post your console. It should keep schedualling.

use iseventpendingas follows
if (isEventPending(%this.PoisonID ))cancel(%this.PoisonID);
#15
10/28/2004 (6:12 am)
BTW I got this working without a crash as so

somewhere command to start it
%client.player.PoisonID = schedule(2000, 0, "poison", %client.player, 20, 6);

%client.Player is the object which get poisoned in this case a bot, with 100 health, 6*20 is 120 so it will try to posion after he is dead.

NEXT the poison code
function poison(%this, %amount, %times){
    echo("Times " @ %times);
    echo("amount " @ %amount);
    echo("PlayerState " @ %this.getState());
    if(%this.getState() !$= "Dead")     {
    %this.applyDamage(%amount);
    echo("Poison Hurts");
    %times--;
    if(%times > 0)
    %this.PoisonID = schedule(2000, 0,"poison", %this, %amount, %times);
    }
}


Finally a way to stop it, because bot are have the armor classname I put it in the Armor on Disabled, notice how I use the object instance.
function Armor::onDisabled(%this,%obj,%state)
{

   %obj.playDeathCry();
   %obj.playDeathAnimation();
   %obj.setDamageFlash(0.75);

   // Release the main weapon trigger
   %obj.setImageTrigger(0,false);

   // Schedule corpse removal.  Just keeping the place clean.
   %obj.schedule($CorpseTimeoutValue - 1000, "startFade", 1000, 0, true);
   %obj.schedule($CorpseTimeoutValue, "delete");
   

  [b]if(isEventPending(%obj.PoisonID)) {
   echo("warning posion");
   cancel(%obj.PoisonID);
   }[/b]
}

Here is a copy of my console
Times 6
amount 20
PlayerState Move
Poison Hurts
Times 5
amount 20
PlayerState Move
Poison Hurts
Times 4
amount 20
PlayerState Move
Poison Hurts
Times 3
amount 20
PlayerState Move
Poison Hurts
Times 2
amount 20
PlayerState Move
Poison Hurts
Times 1
amount 20
PlayerState Dead
keyboard0 input device acquired.
moving bot
keyboard0 input device unacquired.
Received info request from a master server [IP:216.116.32.49:28002].
Times 6
amount 20
PlayerState Dead

Note how the warning posion isn't called in the console it is there incase you dies of other circumstances while being poisoned.
#16
10/28/2004 (2:59 pm)
Hey thanks a million for all your help. I tried adding your suggestions but I still crash. The game doesn't crash when I poison a bot, only when I poison myself. The spell is actually a weapon that shoots a "poison arrow". From the poisonProjectile::onCollision(...) I add the following to schedule the poison function.

%col.PoisonID = schedule(2000, 0, "poison", %col, 10, 6);
//didn't schedule the function with %col.player.PoisonID

and in the onFire I added this to poison myself:

%obj.PoisonID = schedule(2000, 0, "poison", %obj, 10, 6);


this is the console log, I used 10 for the amount because our wizard currently has 50 hp.
************************************************************************************
Spell Cast
************************************************************************************
Projectile Launched
Times 6
amount 10
PlayerState Move
Poison Hurts
Times 5
amount 10
PlayerState Move
Poison Hurts
Times 4
amount 10
PlayerState Move
Poison Hurts
Times 3
amount 10
PlayerState Move
Poison Hurts
Times 2
amount 10
PlayerState Move
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
On Death Called

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Poison Hurts
Times 1
amount 10


Thanks again for all your help. I'm going to keep tryin to figure it out and will post the solution if I find it.
#17
10/28/2004 (3:53 pm)
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
On Death Called
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

should say On Disabled Called - the echo "warning poison" would follow immediately if PoisonID wasn't "".

Am I declaring PoisonID correctly? This is where I declared it.

function GameConnection::createPlayer(%this, %spawnPoint)
{
    %player = new Player() {
        ...
     PoisonID = "";
   }
}
#18
10/29/2004 (2:18 pm)
@ Anthony

if (isEventPending(%this.PoisonID ))cancel(%this.PoisonID);


That is an incorrect usage of "isEventPending" and is unneccesay.

cancel(%this.PoisonID);


works better in this situation. Also you said....

Quote:The 0 can be replaced with a simgroup to monitor the schedual, which isn't ressisary. Can you post your console. It should keep schedualling.

Which is also incorrect. The 0 can be replaced with an objectID# to tie the schedule to that object. If the object still exists when the event is ready, the event happens, if the object has been deleted, the event terminates.
#19
11/02/2004 (6:19 pm)
Err sorry for the late post. Thanks for the help, I couldn't get the game to stop crashing for some reason. The cancel worked and no more schedules tried to poison me, but I still crashed when my HP hit 0. Not sure what the deal was. Well I made the player always get left with 1 hp and added motion blur while poisoned to make up for it. All I could do with my limited time left.
#20
08/01/2007 (7:20 pm)
I am having a similar problem. I cannot kill my bots from within a schedule, they can be damaged just fine but they within the schedules scope they are IsGhost, when a projectile or some other method damages them, they are !IsGhost. Smells like a bug to me or serious annoyance. If i comment out the !IsGhost conditionals within a few shapeBase functions, the bots die, then the game crashes.

The debugging continues....
Page «Previous 1 2