Author Topic: Node Coloring || Ranged Vectors || Emitters && Corpses  (Read 3927 times)

Hello, Coding Help! I have a bit of a problem. I'm making an infection thing, where slowly people's body parts start rotting away (cough cough black death). The only problem is that if someone goes into options, and then presses apply, their avatar's colors go back to normal. Is there any way to combat this? Here's my code:

function givePlague(%client, %giver)
{
   if(isObject(%client.player))
   {
      if(%giver == 1)
         %client.chatMessage("\c7You are the \c0plague-giver\c7. Punish those who are deemed \c8unholy.");
      else
      {
         announce("\c3" @ %client.name @ ":\c6 Achoo!");
         schedule(5000, announce,"\c7The plague has taken another victim.");
      }
      %client.player.setMaxForwardSpeed("10");
      %client.hasPlague = 1;
      %client.player.setNodeColor("lhand","0 0 0 1");
      %client.player.schedule(2000,setNodeColor,"larm","0 0 0 1");
      %client.player.schedule(3000,setNodeColor,"rhand","0 0 0 1");
      %client.player.schedule(3700,setNodeColor,"rarm","0 0 0 1");
      %client.player.schedule(5300,setNodeColor,"chest","0 0 0 1");
      %client.player.schedule(6200,setNodeColor,"headskin","0 0 0 1");
      %client.player.schedule(7000,setNodeColor,"ALL","0 0 0 1");
   }
   else
   {
      %client.chatMessage("\c7You were going to be given the \c0ultimate blessing\c7, but you have already been taken.");
   }
}


I also have a package that makes updatebodyColors() do nothing.
« Last Edit: May 18, 2015, 09:42:19 PM by Johnny Blockhead »

I also have a package that makes updatebodyColors() do nothing.

See if blocking serverCmdUpdateBodyParts and serverCmdUpdateBodyColors does what you're looking for.

Code: [Select]
package MySuperAwesomePackage
{
function serverCmdUpdateBodyColors(%client, %a, %b, %c, %d, %e, %f, %g, %h, %i, %j, %k, %l, %m, %body, %face)
{
if(!%client.hasPlague)
{
parent::serverCmdUpdateBodyColors(%client, %a, %b, %c, %d, %e, %f, %g, %h, %i, %j, %k, %l, %m, %body, %face);
}
}

function serverCmdUpdateBodyParts(%client, %a, %b, %c, %d, %e, %f, %g, %h, %i, %j, %k, %l, %m, %body, %face)
{
if(!%client.hasPlague)
{
parent::serverCmdUpdateBodyColors(%client, %a, %b, %c, %d, %e, %f, %g, %h, %i, %j, %k, %l, %m, %body, %face);
}
}
};
activatePackage(MySuperAwesomePackage);

I am not a smart man. Thanks Jes!

Edit: For those curious, the infection process looks sorta like this:
« Last Edit: May 13, 2015, 08:37:41 PM by Johnny Blockhead »

Sorry for the double post. :(

I'm making the code for infecting players. It's triggered whenever you left click. Everything is fine and dandy, but how would I be able to  limit the distance a player could infect somebody from? I was thinking about clipping the %end variable to be a few feet in front of a character. I'd pretty much make %end be %start but added a bit on the x or y axises. Yet, I don't know how I'd account for the player looking in whatever direction he is looking in [addRelativeVelocity didn't help]. Or, is there a more efficient way to do this that I'm missing altogether?

I believe that this should do the trick:

Code: [Select]
%distance = 3; //the default onActivate distance is 5, for reference
%vector = vectorScale(vectorNormalize(%player.getEyeVector()), %distance);

We get the unit vector with vectorNormalize and then scale it to our desired magnitude, %distance.

I believe that this should do the trick:

Code: [Select]
%distance = 3; //the default onActivate distance is 5, for reference
%vector = vectorScale(vectorNormalize(%player.getEyeVector()), %distance);

We get the unit vector with vectorNormalize and then scale it to our desired magnitude, %distance.

The eye vector comes normalized already so you can skip that step if you'd like.

Thanks guys! I got it working. I've been attempting to create an emitter system, but I'm pretty stuck. I read the special effects tutorial, so I know what I'm doing. Sorta. I have the script below running, but it seems to only churn out black sludge, even though I have a trail emitter texture set. Also, I'm trying to mount the emitter to the player's chest, but I can't find a node list, or how to properly use mountImage/mountObject. Can anyone clear this up for me?

//Trails
datablock ShapeBaseImageData(TrailImage)
{
   shapeFile = "base/data/shapes/empty.dts";
   emap = false;
   mountPoint = $HeadSlot;
   stateName[0] = "Ready"; //This is first
   stateTransitionOnTimeout[0] = "loopStart"; //Name of state to go to next.
   stateTimeoutValue[0] = 0.1; //Seconds for it to go to the next part of the loop.

   stateName[1] = "loopStart"; //Name of the state
   stateTransitionOnTimeout[1] = "loopEnd"; //next state you go to
   stateTimeoutValue[1] = 0.1; //Seconds til the next part of the loop
   stateEmitter[1] = "TrailEmitter"; //The emitted emitter datablock here.
   stateEmitterTime[1] = 1; //Time for the emitter to last, in seconds.

   stateName[2] = "loopEnd";
   stateWaitForTimeout[2] = 0;
   stateTransitionOnTimeout[2] = "loopStart";
   stateEmitterTime[2] = 1; //Emitter lifespan
   stateEmitter[2] = "TrailEmitter";
   stateTimeoutValue[2] = 1;
};
datablock ParticleData(TrailParticle)
{
   dragCoefficient      = 6.0;
   gravityCoefficient   = 0.0;
   inheritedVelFactor   = 0.0;
   constantAcceleration = 0.0;
   lifetimeMS           = 1000;
   lifetimeVarianceMS   = 500;
   useInvAlpha          = true;
   textureName          = "add-ons/server_hub/trail1";
   colors[0]     = "1.0 1.0 1.0 1.0";
   colors[1]     = "1.0 1.0 1.0 1.0";
   colors[2]     = "1.0 1.0 1.0 1.0";
   sizes[0]      = 0.6;
   sizes[1]      = 0.4;
   sizes[2]      = 0.4;
   times[0]      = 0.0;
   times[1]      = 0.2;
   times[2]      = 1.0;
};

datablock ParticleEmitterData(TrailEmitter)
{
   ejectionPeriodMS = 60;
   periodVarianceMS = 0;
   ejectionVelocity = 0.5;
   ejectionOffset   = 0.9;
   velocityVariance = 0.49;
   thetaMin         = 0;
   thetaMax         = 120;
   phiReferenceVel  = 0;
   phiVariance      = 360;
   overrideAdvance = false;
   particles = "TrailParticle";
   uiName = "Trail - Dutton";
};

function servercmdTrail(%client)
{
   %emitter = new particleEmitterNode()
   {
      dataBlock = "GenericEmitterNode";
      emitter = "TrailEmitter";
      position = %client.player.getPosition(); //
      spherePlacement = 0;
      velocity = 1;
   };
   %client.player.mountImage(trailImage, 1);
}
« Last Edit: May 16, 2015, 06:12:40 PM by Johnny Blockhead »

you need to create the emitter BEFORE your create the trail image. so copy/paste your emitter+particle code above the image's code

Thanks! It displays the image fine. I'm still quite puzzled though, since I want to mount an emitter to the player's chest. I have this code in a servercmd (%client.player.mountImage(TrailImage, $backSlot);) and I have defined mountPoint = $backSlot; in the TrailImage datablock. Even after switching this around and reading most of the Coding Help topics there is on the subject, I still can't get the emitter to follow me.
Edit: I've tried every pairing of slots, variable or not, and it still doesn't work.

Crap, I also have another super-mystery. I'm making a thing where when you die, you leave behind a statue, in the place of where you were last. Here's my code:
package corpseParty //PlayDeathAnimation
{
   function gameConnection::onDeath(%client, %killerPlayer, %killer, %damageType, %damageLoc)
   {
      if($gamemode $= "corpseParty")
      {
         //Defining variables
         %pos = %client.player.getPosition();
         %client.oldPlayer = %client.player;

         //Creating the statue
         %client.createPlayer(%pos); //Note: this overrides %client.player with a new value.

         //Modifying the player
         %client.player.setNodeColor("ALL", "112 112 112 1");
         %client.player.setShapeNameDistance(0);

         //Restoring the player
         %client.player = %client.oldPlayer;

         //Nullifying variables
         %client.oldPlayer = "";

         //Deleting the player
         %client.player.delete();
      }
      parent::onDeath(%client, %killerPlayer, %killer, %damageType, %damageLoc);
   }
   function Player::PlayDeathAnimation(%pl)
   {
      if($gamemode $= "corpseParty")
      {
         return;
      }
      parent::PlayDeathAnimation(%pl);
   }
};
activatePackage(corpseParty);

This works fine, except the statue left behind isn't crouched or looking in the same direction as you. I know you can't get the yaw/roll on the server side, and there's nothing to be found when looking to make a person keep being crouched server-side.
« Last Edit: May 15, 2015, 10:30:36 PM by Johnny Blockhead »

Player::removeBody is scheduled for the 'delete + puff of smoke' after death. If you package/remove it, this might keep the 'real' body with the current mounted items/emitters when you die, instead of having to create a new one and mimic what the old one was doing. It should keep the direction you're facing, but I don't know how crouching interacts with removing death animations.

Thanks! It works like a charm, here's my code:
package corpseParty
{
   function gameConnection::onDeath(%client)
   {
      if($gamemode $= "corpseParty")
      {
         %client.player.setNodeColor("ALL","112 112 112 1");
      }
      parent::onDeath(%client);
   }
   function player::PlayDeathAnimation(%player)
   {
      if($gamemode $= "corpseParty")
      {
         return;
      }
      parent::PlayDeathAnimation(%player);
   }
   function Player::RemoveBody(%player)
   {
      if($gamemode $= "corpseParty")
      {
         return;
      }
      parent::removeBody(%player);
   }
};
activatePackage(corpseParty);

The only problem is that the statues left behind don't have any collision. I tried spawning a new player in their death location, giving the user something to bump into, but that didn't work either.
also my emitter question :(
Edit:I found this thread, looking into it... http://forum.blockland.us/index.php?topic=213270.msg6028169#msg6028169. The solution appears to be either recoding the death system from scratch or making a static shape that is in the position of the corpse.
Edit 2: I tried using staticshapes, but it still doesn't work. I think it's because it doesn't know what dimensions the staticshape is, and it has no model so it won't bump into the player. I don't know how to model for BL so I don't think this is an option.
« Last Edit: May 16, 2015, 06:07:09 PM by Johnny Blockhead »

(all of these are packaged)
Okay, here are the two versions of my script that try the two different methods. Spawning a bot, in order for players to collide with it:
      if($gamemode $= "corpseParty")
      {
         %client.player.setNodeColor("ALL","112 112 112 1");
         //Creates a bot.
         %client.truePlayer = %client.player;
         %client.createPlayer(%truePlayer.getPosition());
         //Modifies bot.
         %client.player.setNodeColor("ALL","0 0 0 0");
         %client.player.setShapeNameDistance(0);
         //Restores everything.
         %client.player = %client.truePlayer;
         %client.truePlayer = "";
      }
      parent::onDeath(%client);

This method always ends up with me falling out of the sky, in a full-body transparent garb. Anyways, it looks like my method for making someone invisible isn't working.
And making a staticshape to collide with:
      if($gamemode $= "corpseParty")
      {
         %client.player.setNodeColor("ALL","112 112 112 1");
         //This creates a staticshape, giving the corpse collision.
         datablock staticShapeData(corpseCollision)
         {
            shapeFile = "base/data/shapes/empty.dts";
         };
         %shape = new staticShape()
         {
            datablock = "corpseCollision";
            position = %client.player.getPosition();
            rotation = %client.player.rotation;
         };
      }

This one just straight up doesn't work. I think it's because the model is empty, so there's nothing to collide with. Maybe I could set it to the player's model?
Edit: I'm working on the third option, just rewriting the death thing itself. It's weird though, since the corpse camera mode makes me respawn when I click.
Edit 2: Ok, here's my code:
if($gamemode $= "corpseParty")
{
   %client.player.setShapeNameDistance(0);
   %client.spawnPlayer();
   return;
}

It works, the only weird thing is that the shapename command works, but when I try to color the player's nodes nothing happens. Also collision doesn't work. I am led to believe that torque automatically strips away collision from clientless players, it's not hidden in the death functions. So, can anyone correct my methods above? Please?
« Last Edit: May 16, 2015, 07:37:34 PM by Johnny Blockhead »

Quote
%client.truePlayer = %client.player;
         %client.createPlayer(%truePlayer.getPosition());
%truePlayer doesn't exist (instead, use %client.truePlayer), so you're appearing at (0, 0, 0) which might be 'in the sky'.

Quote
%client.player.setNodeColor("ALL","0 0 0 0");
Use %client.player.hideNode("ALL");. Transparency doesn't work quite right.

empty.dts doesn't have a collision model. The player (m.dts) might not, I don't know - player collisions are a cylinder around you, not a model-to-model collision.

Still looking into 'collisions disabled on death'. I think it's to do with states like "onDisabled", but in the engine code rather than a callback we can see.

EDIT: If you do setDamageLevel(0) on a dead player, they become solid again, but can also get hurt and killed again! This might have weird effects with other add-ons.



Technical version:
https://github.com/GarageGames/Torque3D/blob/74a05854d56afe15cbc341575b73b3474af18277/Engine/source/T3D/player.cpp - Torque 3D is a future version of Torque Game Engine, but it's similar enough

You become Disabled when damaged beyond max health. (Conversely, you can become Enabled when setting damage below that again)
Code: [Select]
void Player::updateDamageLevel()
{
   if (!isGhost())
      setDamageState((mDamage >= mDataBlock->maxDamage)? Disabled: Enabled);
   if (mDamageThread)
      mShapeInstance->setPos(mDamageThread, mDamage / mDataBlock->destroyedLevel);
}

When this happens, your collision mask (= raycast typemasks) stops being a Player and becomes a Corpse.
Code: [Select]
void Player::updateDamageState()
{
   // Become a corpse when we're disabled (dead).
   if (mDamageState == Enabled) {
      mTypeMask &= ~CorpseObjectType;
      mTypeMask |= PlayerObjectType;
   }
   else {
      mTypeMask &= ~PlayerObjectType;
      mTypeMask |= CorpseObjectType;
   }

   Parent::updateDamageState();
}

Players collide (physics) with these things, which doesn't include corpses.
Code: [Select]
static U32 sCollisionMoveMask =  TerrainObjectType       |
                                 WaterObjectType         |
                                 PlayerObjectType        |
                                 StaticShapeObjectType   |
                                 VehicleObjectType       |
                                 PhysicalZoneObjectType;
« Last Edit: May 17, 2015, 04:19:15 AM by Space Guy »

I love you.
I seriously can't believe the solution was that simple, for the bot spawning method. It works perfectly! I'm kinda curious though to see how you managed to set the damage of a dead player, when if you even try to use /getid on a corpse it gets the information of the thing behind it. If I try to access it through a script, it can't tell what object I'm referring to.

But besides that, everything is okay and I have a working solution.emitters:(

edit: HELL YES! I got it working:

It was something to do with how I defined the datablocks. I basically rewrote them and they worked.

Edit 2: I was able to access the corpses through container radius searches.
« Last Edit: May 17, 2015, 04:01:50 PM by Johnny Blockhead »