Jump to content

Steve_Yorkshire

Contributor
  • Posts

    353
  • Joined

  • Last visited

Posts posted by Steve_Yorkshire

  1. I've had a bit more of play around using the subExplosion type found in explosion.cpp/h:

     

    //projectile.h
    class ProjectileData : public GameBaseData
    {
    //...
    public:
     
    	enum ExplosionConsts
    	{
    		EC_MAX_EXPLOSIONS = 4,
    	};
     
       // variables set in datablock definition:
     
    //...
     
       S32 fadeDelay;    // the IRangeValidatorScaled field validator
     
       /*
       ExplosionData* explosion;
       S32 explosionId;
    */
     
       ExplosionData*    explosionList[EC_MAX_EXPLOSIONS];
       S32               explosionIDList[EC_MAX_EXPLOSIONS];
     
       ExplosionData* waterExplosion;      // Water Explosion Datablock
    //...

     

    //projectile.cpp 
    //...
    void ProjectileData::initPersistFields()
    {
    //...
       //addField("explosion", TYPEID< ExplosionData >(), Offset(explosion, ProjectileData),
       //   "@brief Explosion datablock used when the projectile explodes outside of water.\n\n");
     
       addField("explosion", TYPEID< ExplosionData >(), Offset(explosionList, ProjectileData), EC_MAX_EXPLOSIONS,
    	   "List of additional ExplosionData objects to create at the start of the "
    	   "explosion.");
     
       addField("waterExplosion", TYPEID< ExplosionData >(), Offset(waterExplosion, ProjectileData),
          "@brief Explosion datablock used when the projectile explodes underwater.\n\n");
    //...
    }
     
    //...
    bool ProjectileData::preload(bool server, String &errorStr)
    {
    //...
                Con::errorf(ConsoleLogEntry::General, "ProjectileData::preload: Invalid packet, bad datablockId(particleWaterEmitter): %d", particleWaterEmitterId);
     
    	  /*
          if (!explosion && explosionId != 0)
             if (Sim::findObject(explosionId, explosion) == false)
                Con::errorf(ConsoleLogEntry::General, "ProjectileData::preload: Invalid packet, bad datablockId(explosion): %d", explosionId);
    	  */
     
    	  for (S32 k = 0; k
    	  {
    		  if (!explosionList[k] && explosionIDList[k] != 0)
    		  {
    			  if (Sim::findObject(explosionIDList[k], explosionList[k]) == false)
    			  {
    				  Con::errorf(ConsoleLogEntry::General, "ExplosionData::onAdd: Invalid packet, bad datablockId(explosion): 0x%x", explosionIDList[k]);
    			  }
    		  }
    	  }
     
          if (!waterExplosion && waterExplosionId != 0)
    //...
    }
    //...
     
    void ProjectileData::packData(BitStream* stream)
    {
    //...
       /*
       if (stream->writeFlag(explosion != NULL))
          stream->writeRangedU32(explosion->getId(), DataBlockObjectIdFirst,
                                                     DataBlockObjectIdLast);
       */
       for (S32 i = 0; i
       {
    	   if (stream->writeFlag(explosionList != NULL))
    	   {
    		   stream->writeRangedU32(explosionList->getId(), DataBlockObjectIdFirst, DataBlockObjectIdLast);
    	   }
       }
     
       if (stream->writeFlag(waterExplosion != NULL))
    //...
    }
     
    void ProjectileData::unpackData(BitStream* stream)
    {
    //...
       /*
       if (stream->readFlag())
          explosionId = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
       */
     
       for (S32 k = 0; k
       {
    	   if (stream->readFlag())
    	   {
    		   explosionIDList[k] = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
    	   }
       }
     
       if (stream->readFlag())
          waterExplosionId = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
    //...
    }
    //...
     
    void Projectile::explode( const Point3F &p, const Point3F &n, const U32 collideType )
    {
    //...
    }


    However it all rather ground to a halt because I am not familiar with how to get the explosionList[EC_MAX_EXPLOSIONS] in the actual explode() function of projectile.cpp. :?

  2. Projectiles are a little boring having only one explosion and if you want to use an animated particle sprite sheet or an explosion model it's going to get even more repetitive.


    Here's the general idea, the projectile has up to 4 explosion datablocks instead of 1. On exploding the projectile looks up how many explosion datablocks in can reference and then randomly chooses one. If it can't find any additional explosions it will default to the single stock one.


    Obviously you can do the same with water explosions, but ehre I'm only using dirt/dry explosions.


    I am currently in "art mode" so here's a -

    **warning of terrible C++ ahead**

    - feel free to expand on the idea and make it less horrible.


    First up, add new datablocks and information for explosions to the projectile. Here I am using the stock projectile in art/datablocks/Lurker.cs. This requires adding new particles and emitters, as well as editing the stock BulletDirtExplosion emitters to make it easier to see.

     

    //...
    datablock ParticleData(BulletDirtDust)
    {
       textureName          = "art/particles/impact";
       dragCoefficient      = "1";
       gravityCoefficient   = "-0.100122";
       windCoefficient      = 0;
       inheritedVelFactor   = 0.0;
       constantAcceleration = "-0.83";
       lifetimeMS           = 800;
       lifetimeVarianceMS   = 300;
       spinRandomMin = -180.0;
       spinRandomMax =  180.0;
       useInvAlpha   = true;
     
       colors[0]     = "0.496063 0.393701 0.299213 0.692913";
       colors[1]     = "0.692913 0.614173 0.535433 0.346457";
       colors[2]     = "0.897638 0.84252 0.795276 0";
     
       sizes[0]      = "0.997986";
       sizes[1]      = "2";
       sizes[2]      = "2.5";
     
       times[0]      = 0.0;
       times[1]      = "0.498039";
       times[2]      = 1.0;
       animTexName = "art/particles/impact";
    };
     
    datablock ParticleEmitterData(BulletDirtDustEmitter)
    {
       ejectionPeriodMS = 20;
       periodVarianceMS = 10;
       ejectionVelocity = "1";
       velocityVariance = 1.0;
       thetaMin         = 0.0;
       thetaMax         = 180.0;
       lifetimeMS       = 250;
       particles = "BulletDirtDust";
       blendStyle = "ADDITIVE";//yorks "NORMAL";
    };
     
    //yorks start
    datablock ParticleData(BulletDirtDust1)
    {
       textureName          = "art/particles/impact";
       dragCoefficient      = "1";
       gravityCoefficient   = "-0.1";
       windCoefficient      = 0;
       inheritedVelFactor   = 0.0;
       constantAcceleration = "-0.83";
       lifetimeMS           = 800;
       lifetimeVarianceMS   = 300;
       spinRandomMin = -180.0;
       spinRandomMax =  180.0;
       useInvAlpha   = true;
     
       colors[0]     = "1 0 0 0";
       colors[1]     = "1 0 0.0 0.5";
       colors[2]     = "1 0 0.0 0";
     
       sizes[0]      = "1";
       sizes[1]      = "2";
       sizes[2]      = "2.5";
     
       times[0]      = 0.0;
       times[1]      = "0.5";
       times[2]      = 1.0;
       animTexName = "art/particles/impact";
    };
     
    datablock ParticleEmitterData(BulletDirtDust1Emitter)
    {
       ejectionPeriodMS = 20;
       periodVarianceMS = 10;
       ejectionVelocity = "1";
       velocityVariance = 1.0;
       thetaMin         = 0.0;
       thetaMax         = 180.0;
       lifetimeMS       = 250;
       particles = "BulletDirtDust1";
       blendStyle = "ADDITIVE";
    };
     
    datablock ParticleData(BulletDirtDust2)
    {
       textureName          = "art/particles/impact";
       dragCoefficient      = "1";
       gravityCoefficient   = "-0.1";
       windCoefficient      = 0;
       inheritedVelFactor   = 0.0;
       constantAcceleration = "-0.83";
       lifetimeMS           = 800;
       lifetimeVarianceMS   = 300;
       spinRandomMin = -180.0;
       spinRandomMax =  180.0;
       useInvAlpha   = true;
     
       colors[0]     = "0.0 0.0 1 1";
       colors[1]     = "0.0 0.0 1 0.5";
       colors[2]     = "0.0 0.0 1 0";
     
       sizes[0]      = "1";
       sizes[1]      = "2";
       sizes[2]      = "3";
     
       times[0]      = 0.0;
       times[1]      = "0.5";
       times[2]      = 1.0;
       animTexName = "art/particles/impact";
    };
     
    datablock ParticleEmitterData(BulletDirtDust2Emitter)
    {
       ejectionPeriodMS = 20;
       periodVarianceMS = 10;
       ejectionVelocity = "1";
       velocityVariance = 1.0;
       thetaMin         = 0.0;
       thetaMax         = 180.0;
       lifetimeMS       = 250;
       particles = "BulletDirtDust2";
       blendStyle = "ADDITIVE";
    };
     
    datablock ParticleData(BulletDirtDust3)
    {
       textureName          = "art/particles/impact";
       dragCoefficient      = "1";
       gravityCoefficient   = "-0.1";
       windCoefficient      = 0;
       inheritedVelFactor   = 0.0;
       constantAcceleration = "-0.83";
       lifetimeMS           = 800;
       lifetimeVarianceMS   = 300;
       spinRandomMin = -180.0;
       spinRandomMax =  180.0;
       useInvAlpha   = true;
     
       colors[0]     = "0.0 1 0 1";
       colors[1]     = "0.0 1 0 0.5";
       colors[2]     = "0.0 1 0 0";
     
       sizes[0]      = "1";
       sizes[1]      = "2";
       sizes[2]      = "3";
     
       times[0]      = 0.0;
       times[1]      = "0.5";
       times[2]      = 1.0;
       animTexName = "art/particles/impact";
    };
     
    datablock ParticleEmitterData(BulletDirtDust3Emitter)
    {
       ejectionPeriodMS = 20;
       periodVarianceMS = 10;
       ejectionVelocity = "1";
       velocityVariance = 1.0;
       thetaMin         = 0.0;
       thetaMax         = 180.0;
       lifetimeMS       = 250;
       particles = "BulletDirtDust3";
       blendStyle = "ADDITIVE";
    };
    //yorks end
     
    //-----------------------------------------------------------------------------
    // Explosion
    //-----------------------------------------------------------------------------
    datablock ExplosionData(BulletDirtExplosion)
    {
       soundProfile = BulletImpactSound;
       lifeTimeMS = 65;
     
       // Volume particles
       particleEmitter = BulletDirtDustEmitter;
       particleDensity = 4;
       particleRadius = 0.3;
     
       //yorks start
       /*
       // Point emission
       emitter[0] = BulletDirtSprayEmitter;
       emitter[1] = BulletDirtSprayEmitter;
       emitter[2] = BulletDirtRocksEmitter;
       */
          // Point emission
       emitter[0] = BulletDirtDustEmitter;
       emitter[1] = BulletDirtDustEmitter;
       emitter[2] = BulletDirtDustEmitter;
       //yorks end
    };
     
    //yorks start
    datablock ExplosionData(BulletDirtExplosion1)
    {
       soundProfile = BulletImpactSound;
       lifeTimeMS = 65;
     
       // Volume particles
       particleEmitter = BulletDirtDust1Emitter;
       particleDensity = 4;
       particleRadius = 0.3;
     
       // Point emission
       emitter[0] = BulletDirtDust1Emitter;
       emitter[1] = BulletDirtDust1Emitter;
       emitter[2] = BulletDirtDust1Emitter;
    };
     
    datablock ExplosionData(BulletDirtExplosion2)
    {
       soundProfile = BulletImpactSound;
       lifeTimeMS = 65;
     
       // Volume particles
       particleEmitter = BulletDirtDust2Emitter;
       particleDensity = 4;
       particleRadius = 0.3;
     
       // Point emission
       emitter[0] = BulletDirtDust2Emitter;
       emitter[1] = BulletDirtDust2Emitter;
       emitter[2] = BulletDirtDust2Emitter;
    };
     
    datablock ExplosionData(BulletDirtExplosion3)
    {
       soundProfile = BulletImpactSound;
       lifeTimeMS = 65;
     
       // Volume particles
       particleEmitter = BulletDirtDust3Emitter;
       particleDensity = 4;
       particleRadius = 0.3;
     
       // Point emission
       emitter[0] = BulletDirtDust3Emitter;
       emitter[1] = BulletDirtDust3Emitter;
       emitter[2] = BulletDirtDust3Emitter;
    };
    //yorks end
     
    //...
     
    datablock ProjectileData( BulletProjectile )
    {
       projectileShapeName = "";
     
       directDamage        = 5;
       radiusDamage        = 0;
       damageRadius        = 0.5;
       areaImpulse         = 0.5;
       impactForce         = 1;
     
       explosion           = BulletDirtExplosion;
       decal               = BulletHoleDecal;
     
       //yorks start
       explosion1           = BulletDirtExplosion1;
       explosion2           = BulletDirtExplosion2;
       explosion3           = BulletDirtExplosion3;
       //yorks end
     
       muzzleVelocity      = 120;
       velInheritFactor    = 1;
     
       armingDelay         = 0;
       lifetime            = 992;
       fadeDelay           = 1472;
       bounceElasticity    = 0;
       bounceFriction      = 0;
       isBallistic         = false;
       gravityMod          = 1;
    };
    //...

     

    So we have now have 4 explosions which will show white (original), red, blue and green so we can see the difference.


    Next up we need to crack open the C++. Open up soure/T3D/projectile.h and list the new explosion data.

     

    /...
       ExplosionData* explosion;
       S32 explosionId;
     
       //yorks start
       ExplosionData* explosion1;
       S32 explosion1Id;
     
       ExplosionData* explosion2;
       S32 explosion2Id;
     
       ExplosionData* explosion3;
       S32 explosion3Id;
       //yorks end
     
       ExplosionData* waterExplosion;      // Water Explosion Datablock
    //...

     

    And then the meat of the sandwich, source/T3D/projectile.cpp.

     

    ProjectileData::ProjectileData()
    {
    //...
       explosion = NULL;
       explosionId = 0;
     
       //yorks start
       explosion1 = NULL;
       explosion1Id = 0;
     
       explosion2 = NULL;
       explosion2Id = 0;
     
       explosion3 = NULL;
       explosion3Id = 0;
       //yorks end
     
       waterExplosion = NULL;
    //...
    }
     
    //...
     
    void ProjectileData::initPersistFields()
    {
    //...
       addField("explosion", TYPEID< ExplosionData >(), Offset(explosion, ProjectileData),
          "@brief Explosion datablock used when the projectile explodes outside of water.\n\n");
       addField("waterExplosion", TYPEID< ExplosionData >(), Offset(waterExplosion, ProjectileData),
          "@brief Explosion datablock used when the projectile explodes underwater.\n\n");
     
       //yorks start
       addField("explosion1", TYPEID< ExplosionData >(), Offset(explosion1, ProjectileData),
    	   "@brief Explosion1 datablock used when the projectile explodes outside of water.\n\n");
       addField("explosion2", TYPEID< ExplosionData >(), Offset(explosion2, ProjectileData),
    	   "@brief Explosion2 datablock used when the projectile explodes outside of water.\n\n");
       addField("explosion3", TYPEID< ExplosionData >(), Offset(explosion3, ProjectileData),
    	   "@brief Explosion3 datablock used when the projectile explodes outside of water.\n\n");
       //yorks end
     
       addField("splash", TYPEID< SplashData >(), Offset(splash, ProjectileData),
          "@brief Splash datablock used to create splash effects as the projectile enters or leaves water\n\n");
    //...
    }
     
    //...
     
    bool ProjectileData::preload(bool server, String &errorStr)
    {
    //...
          if (!explosion && explosionId != 0)
             if (Sim::findObject(explosionId, explosion) == false)
                Con::errorf(ConsoleLogEntry::General, "ProjectileData::preload: Invalid packet, bad datablockId(explosion): %d", explosionId);
     
    	  //yorks start
    	  if (!explosion1 && explosion1Id != 0)
    		  if (Sim::findObject(explosion1Id, explosion1) == false)
    			  Con::errorf(ConsoleLogEntry::General, "ProjectileData::preload: Invalid packet, bad datablockId(explosion1): %d", explosion1Id);
     
    	  if (!explosion2 && explosion2Id != 0)
    		  if (Sim::findObject(explosion2Id, explosion2) == false)
    			  Con::errorf(ConsoleLogEntry::General, "ProjectileData::preload: Invalid packet, bad datablockId(explosion2): %d", explosion2Id);
     
    	  if (!explosion3 && explosion3Id != 0)
    		  if (Sim::findObject(explosion3Id, explosion3) == false)
    			  Con::errorf(ConsoleLogEntry::General, "ProjectileData::preload: Invalid packet, bad datablockId(explosion3): %d", explosion3Id);
    	  //yorks end
     
          if (!waterExplosion && waterExplosionId != 0)
    //...
    }
     
    //--------------------------------------------------------------------------
    void ProjectileData::packData(BitStream* stream)
    {
    //...
       if (stream->writeFlag(explosion != NULL))
          stream->writeRangedU32(explosion->getId(), DataBlockObjectIdFirst,
                                                     DataBlockObjectIdLast);
     
       //yorks start
       if (stream->writeFlag(explosion1 != NULL))
    	   stream->writeRangedU32(explosion1->getId(), DataBlockObjectIdFirst,
    	   DataBlockObjectIdLast);
     
       if (stream->writeFlag(explosion2 != NULL))
    	   stream->writeRangedU32(explosion2->getId(), DataBlockObjectIdFirst,
    	   DataBlockObjectIdLast);
     
       if (stream->writeFlag(explosion3 != NULL))
    	   stream->writeRangedU32(explosion3->getId(), DataBlockObjectIdFirst,
    	   DataBlockObjectIdLast);
       //yorks end
     
       if (stream->writeFlag(waterExplosion != NULL))
    //...
    }
     
    void ProjectileData::unpackData(BitStream* stream)
    {
    //...
       if (stream->readFlag())
          explosionId = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
     
       //yorks start
       if (stream->readFlag())
    	   explosion1Id = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
     
       if (stream->readFlag())
    	   explosion2Id = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
     
       if (stream->readFlag())
    	   explosion3Id = stream->readRangedU32(DataBlockObjectIdFirst, DataBlockObjectIdLast);
       //yorks end
     
       if (stream->readFlag())
    //...
    }
     
    //...
     
    void Projectile::explode( const Point3F &p, const Point3F &n, const U32 collideType )
    {
    //...
    else 
       {
          // Client just plays the explosion at the right place...
          //       
          Explosion* pExplosion = NULL;
     
    	  //yorks in
    	  S32 mRandomize = 0;
     
          if (mDataBlock->waterExplosion && pointInWater(p))
          {
             pExplosion = new Explosion;
             pExplosion->onNewDataBlock(mDataBlock->waterExplosion, false);
          }
    	  else
    		  /*yorks out start
    	  if (mDataBlock->explosion)
    	  {
    	  pExplosion = new Explosion;
    	  pExplosion->onNewDataBlock(mDataBlock->explosion, false);
    	  }
    	  //yorks out end */
    	  //yorks in start
    	  {
    		  //yorks start with 1 continue check with others if exists else default to normal explosion
    		  if (mDataBlock->explosion1)
    		  {
    			  //yorks we have >1 explosion, check for others
    			  if (mDataBlock->explosion2)
    			  {
    				  if (mDataBlock->explosion3)
    					  mRandomize = 3;
    				  else
    					  mRandomize = 2;
    			  }
    			  else
    				  mRandomize = 1;
    		  }
     
    		  //yorks get the random
    		  if (mRandomize == 0)
    		  {
    			  //stock explosion
    			  if (mDataBlock->explosion)
    			  {
    				  pExplosion = new Explosion;
    				  pExplosion->onNewDataBlock(mDataBlock->explosion, false);
    			  }
    		  }
    		  else
    		  {
    			  //yorks get random number betweem 0 and mRandomize
    			  S32 mChoose = (gRandGen.randI(0, mRandomize));
     
    			  if (mChoose == 1)
    			  {
    				  pExplosion = new Explosion;
    				  pExplosion->onNewDataBlock(mDataBlock->explosion1, false);
    			  }
    			  else
    			  {
    				  if (mChoose == 2)
    				  {
    					  pExplosion = new Explosion;
    					  pExplosion->onNewDataBlock(mDataBlock->explosion2, false);
    				  }
    				  else
    				  {
    					  if (mChoose == 3)
    					  {
    						  pExplosion = new Explosion;
    						  pExplosion->onNewDataBlock(mDataBlock->explosion3, false);
    					  }
    					  else
    					  {
    						  pExplosion = new Explosion;
    						  pExplosion->onNewDataBlock(mDataBlock->explosion, false);
    					  }
    				  }
    			  }
    		  }
    	  }
    	  //yorks in end
     
          if( pExplosion )
    //...
    }
     
    //...

     

    And that should be that. It ain't elegant but it works, as I said up top, feel free to improve it (no really plz). :lol:


    And this is what it looks like in action:


    KdaqnWd11Ck

  3. Whilst playing around with 3.8 I've found a rather horrifying bug:


    When using the Material Editor or the Particle Emitter Editor, they have a nasty tendency to overwrite other datablock definitions. :evil:


    example:

    singleton Material(base1)
    {
      mapTo = "base1";
      //etc
    }
    
    singleton Material(base2)
    {
      mapTo = "base2";
      //etc
    }
    

     

    becomes:

     

    singleton Material(base2)
    {
      mapTo = "base2";
      //etc
    }
    
    singleton Material(base2)
    {
      mapTo = "base2";
      //etc
    }
    

     

    And you won't notice until you restart T3D and material Base1 is missing and shows up with the orange no material image. This also happens with data saved through particleEmitters, though not particle datablocks. As I've been making lots of changes with Material and ParticleEmitter editors I have noticed this wrong overwriting to be happening a lot. However I've not noticed doing a particular "thing" to cause it. Sometimes it's fine - but eventually it won't be.


    This was not a problem I noticed making AirDrag, but mostly spent the last few releases of Torque updating existing stuff rather than creating new stuff with the editors, so I cannot say when this started happening.


    Note: tested messing around with materials on both custom and stock 3.8 builds and both suffer from this issue so it's not something my custom code introduced. Has anyone been intensitvely using matieral or particle editors and noticed this issue?

    :|

  4. FIXED: SEE BELOW


    Whilst looking through the stock code, I noticed that ProximityMine.cpp/h checks for mOwner and triggerOnOwner(bool) to set whether you want it to explode on the original owner of the mine or not ---- except mOwner can never be set.

     

    // Detect movement in the trigger area
                   if ( ( sql.mList == mOwner && !mDataBlock->triggerOnOwner ) ||
                        sql.mList->getVelocity().len() < mDataBlock->triggerSpeed )
                      continue;

    mOwner and triggerOnOwner called when it decides if it should explode (line ~444) but as mOwner is always null it always explodes. Note: when in scripts/server/proximityMine.cs onThrow functionthe object has a "sourceObject" defined like projectiles, but unlike projectiles there is nothing to refer to this in C++.


    So, thoughts on best fix?

    1: Add a setOwner engineDefine and do it manually from script (feels a bit of a faff)

    2: Add the script definition of sourceObject into C++ to be the mOwner variable, like projectile.cpp does and pack/unpack it.

    eg: inside initPersistFields and change mSourceObjectId to mOwner:

    addGroup("Source");
     
       addField("sourceObject",     TypeS32,     Offset(mSourceObjectId, Projectile),
          "@brief ID number of the object that fired the projectile.\n\n"
          "@note If the projectile was fired by a WeaponImage, sourceObject will be "
          "the object that owns the WeaponImage. This is usually the player.");


    I expect #2 is the better option but thought I'd ask for opinions.


    //edit 24 Jan 2016

    Fixed this. Also killed 2 birds with 1 stone by making "sourceObject" in the ProximityMineData::onThrow function in scripts/server/proximityMine.cs used for setting and checking the mine's owner. If someone else triggers the mine, the owner can still be damaged if they are close to the blast.


    The only downside which I have found is that the player collides with the mine as it has no "step" function for it's collision. Owner has to jump on/over the mine to move through it.


    Stock code from scripts/server/proximityMine.cs, sourceObject now referenced in C++

    function ProximityMineData::onThrow( %this, %user, %amount )
    {
       // Remove the object from the inventory
       %user.decInventory( %this, 1 );
     
       // Construct the actual object in the world, and add it to
       // the mission group so its cleaned up when the mission is
       // done.  The object is given a random z rotation.
       %obj = new ProximityMine()
       {
          datablock = %this;
          sourceObject = %user;
          rotation = "0 0 1 "@ (getRandom() * 360);
          static = false;
          client = %user.client;
       };
       MissionCleanup.add(%obj);
       return %obj;
    }


    ===============================================================================


    TorqueScript Changes:


    art/datablocks/weapons/proxMine.cs

     

    //...
     
    datablock ProximityMineData( ProxMine )
    {
       //...
     
       autoTriggerDelay = 0;
       triggerOnOwner = false;//stock = true; WHETHER THE OWNER TRIGGERS THE MINE
       triggerRadius = 3.0;
       //...


    -----------------------------------------------

    C++ Changes:


    source/T3D/proximityMine.h


    We get rid of "mOwner" and replace it with sourceObjectId and a pointer to the ghost, just like in projectile.cpp.

     

    class ProximityMine: public Item
    {
       typedef Item Parent;
     
    protected:
    //...
     
       TSThread*            mAnimThread;
       //SceneObject*         mOwner;//<----- yorks out, use sourceObjectId now
     
       State                mState;
    //...
       void renderObject( ObjectRenderInst* ri, SceneRenderState* state, BaseMatInstance* overrideMat );
     
       //<-------- yorks in start
       S32      mSourceObjectId;
       SimObjectPtr mSourceObject; ///< Actual pointer to the source object, times out after SourceIdTimeoutTicks
       //<-------- yorks in end
     
    public:
       DECLARE_CONOBJECT( ProximityMine );
    //...
       bool onAdd();
       void onRemove();
       bool onNewDataBlock( GameBaseData* dptr, bool reload );
       static void initPersistFields();//<---------- yorks new in to get sourceObject set from script
     
       virtual void setTransform( const MatrixF& mat );
    //...
       void unpackUpdate( NetConnection* conn, BitStream* stream );
     
       S32 getOwnerID() { return mSourceObjectId; }//<------- yorks new in
    };
     
    #endif // _PROXIMITYMINE_H_


    source/T3D/proximityMine.cpp

     

    //...
     
    ProximityMine::ProximityMine()
    {
       mTypeMask |= StaticShapeObjectType;
    //...
     
       // For the Item class
       mSubclassItemHandlesScene = true;
     
       mSourceObjectId = -1;//<---------- yorks in
    }
     
    ProximityMine::~ProximityMine()
    {
    }
     
    //<------ yorks in start
    void ProximityMine::initPersistFields()
    {
     
    	addGroup("Source");
     
    	addField("sourceObject", TypeS32, Offset(mSourceObjectId, ProximityMine),
    		"@brief ID number of the object that fired the mine.\n\n"
    		"@note This is usually the player.");
     
    	endGroup("Source");
     
    	Parent::initPersistFields();
    }
    //<------- yorks in end
     
    //...
     
    bool ProximityMine::onAdd()
    {
       if ( !Parent::onAdd() || !mDataBlock )
          return false;
     
       addToScene();
     
       //<----- yorks out start
       //if (isServerObject())
          //scriptOnAdd();
       //<----- yorks out end
     
       //<-------- yorks in start
       if (isServerObject())
       {
    	   ShapeBase* ptr;
    	   if (Sim::findObject(mSourceObjectId, ptr))
    	   {
    		   mSourceObject = ptr;
     
    		   // Since we later do processAfter( mSourceObject ) we must clearProcessAfter
    		   // if it is deleted. SceneObject already handles this in onDeleteNotify so
    		   // all we need to do is register for the notification.
    		   deleteNotify(ptr);
    	   }
    	   else
    	   {
    		   if (mSourceObjectId != -1)
    			   Con::errorf(ConsoleLogEntry::General, "ProximityMine::onAdd: mSourceObjectId is invalid");
    		   mSourceObject = NULL;
    	   }
       }
       else
       {
    	   if (mSourceObject.isValid())
    		   processAfter(mSourceObject);
       }
       //<------ yorks in end
     
       if ( mStatic )
       {
          // static mines are armed immediately
          mState = Deployed;
          mStateTimeout = 0;
       }
     
       return true;
    }
     
    //...
     
    void ProximityMine::processTick( const Move* move )
    {
       //...
                   SimpleQueryList::insertionCallback, &sql );
                for ( S32 i = 0; i < sql.mList.size(); i++ )
                {
    		//<---- yorks out start - not using mOwner now
    		/*
                   // Detect movement in the trigger area
                   if ( ( sql.mList == mOwner && !mDataBlock->triggerOnOwner ) ||
                        sql.mList->getVelocity().len() < mDataBlock->triggerSpeed )
                      continue;
    			 */
    		//<---- yorks out end - not using mOwner now
    		//<---- yorks in start - now using mSourceObject, and check it's valid
    				if ((mSourceObject.isValid() && sql.mList == mSourceObject && !mDataBlock->triggerOnOwner) ||
    					sql.mList->getVelocity().len() < mDataBlock->triggerSpeed)
    					continue;
    		//<---- yorks in end - now using mSourceObject, and check it's valid
     
                   // Mine has been triggered
                   mShapeInstance->destroyThread( mAnimThread );
                   mAnimThread = NULL;
    //...
     
    U32 ProximityMine::packUpdate( NetConnection* connection, U32 mask, BitStream* stream )
    {
    //...
     
       stream->writeFlag( ( mask & ExplosionMask ) && ( mState == Exploded ) );
     
       //yorks in start
       if (mSourceObject.isValid())
       {
    	   // Potentially have to write this to the client, let's make sure it has a
    	   //  ghost on the other side... 
    	   //yorks this is from projectile so not sure if this is true for proximityMine
    	   S32 ghostIndex = connection->getGhostIndex(mSourceObject);
    	   if (stream->writeFlag(ghostIndex != -1))
    	   {
    		   stream->writeRangedU32(U32(ghostIndex),
    			   0,
    			   NetConnection::MaxGhostCount);
    	   }
    	   else
    		   // have not recieved the ghost for the source object yet, try again later
    		   retMask |= GameBase::InitialUpdateMask;
       }
       else
    	   stream->writeFlag(false);
       //yorks in end
     
       return retMask;
    }
     
    void ProximityMine::unpackUpdate( NetConnection* connection, BitStream* stream )
    {
    //...
     
       if ( mStatic && mState <= Deployed )
       {
          // static mines are armed immediately
          mState = Deployed;
          mStateTimeout = 0;
       }
     
       //<------------ yorks in start
    	if (stream->readFlag())
       {
    	   mSourceObjectId = stream->readRangedU32(0, NetConnection::MaxGhostCount);
     
    	   NetObject* pObject = connection->resolveGhost(mSourceObjectId);
    	   if (pObject != NULL)
    		   mSourceObject = dynamic_cast(pObject);
    	}
    	else
    	{
    	   mSourceObjectId = -1;
    	   mSourceObject = NULL;
    	}
       //<------- yorks in end
    }
     
    //...
     
    //right at the bottom add a TS function for debug testing the mine's sourceObject
     
    DefineEngineMethod(ProximityMine, getOwner, S32, (), ,
    	"@brief Get the owner of the proximity mine.\n\n"
    	"@returns mSourceObjectId.")
    {
    	return object->getOwnerID();
    }


    And here's the source for download:

    http://yorkshirerifles.com/downloads/proxMine_yorks.zip


    As always, feedback and improvements welcome.

    proxMine_yorks.zip

    C++

  5. But I have noticed that some of the pictures has blanked out in his tutorials/resources

    Some of the old free upload/hosts seem to have bugged/deleted some of my old pics - which is annoying but hey, get what you pay for. :/


    Just to note, all my old tutorials should be good with teh exception that $typemasks::TsStatic (or whatever it was called) no longer exists and needs updating to $TypeMasks::StaticObjectType - but apart from that, should work as written.


    So ... How To Into MMO not getting much traction, then? ;) :P :mrgreen:

  6. Adding engineAPI.h to arcaneFX.h threw up 122 "unresolved external symbols" relating to "onStaticModified".


    Adding engineAPI.h individually to the 5 error files stopped the original errors, until all 5 files had it, then it threw the above 122 errors again.


    Adding console/console.h had no effect on original errors.


    I mostly code gameplay and new classes so this bit of the engine is rather baffling.


    Also I notice Jeff had missed a few code comments so shockWaveData wasn't covered in his port, but it was easy to fix those errors.

  7. I've been porting AFX from 3.6.3 to 3.8 and hit some strange build errors. There's a few "uses undefined struct" and "cannot convert" errors relating to 5 of the AFX files but the errors reference console.h rather than lines in the AFX code. I'm a bit confused and at a loss what to do.


    Here's a pic (right click -> view) for full size

    http://yorkshirerifles.com/random/afx_bugs1.jpg


    And here's the output

    1>------ Build started: Project: AFXtest DLL, Configuration: Release Win32 ------
    1>  afxEA_AreaDamage.cpp
    1>  afxEA_CollisionEvent.cpp
    1>  afxEA_StaticShape.cpp
    1>  afxGuiSubstitutionField.cpp
    1>C:/Torque/Torque3D_38_Win/test_afx/Engine/source/console/console.h(888): error C2079: 'callback' uses undefined struct '_EngineConsoleExecCallbackHelper'
    1>          with
    1>          [
    1>              A=GameBaseData *
    1>          ] (..\..\..\..\..\Engine\source\afx\ea\afxEA_AreaDamage.cpp)
    1>          ..\..\..\..\..\Engine\source\afx\ea\afxEA_AreaDamage.cpp(212) : see reference to function template instantiation 'ConsoleValueRef Con::executef(A,B,C,D,E,F,G)' being compiled
    1>          with
    1>          [
    1>              A=GameBaseData *
    1>  ,            B=const char *
    1>  ,            C=const char *
    1>  ,            D=const char *
    1>  ,            E=char *
    1>  ,            F=const char *
    1>  ,            G=char *
    1>          ]
    1>C:/Torque/Torque3D_38_Win/test_afx/Engine/source/console/console.h(888): error C2440: 'initializing' : cannot convert from 'GameBaseData *' to 'int' (..\..\..\..\..\Engine\source\afx\ea\afxEA_AreaDamage.cpp)
    1>          There is no context in which this conversion is possible
    1>C:/Torque/Torque3D_38_Win/test_afx/Engine/source/console/console.h(888): error C2059: syntax error : 'template' (..\..\..\..\..\Engine\source\afx\ea\afxEA_AreaDamage.cpp)
    1>C:/Torque/Torque3D_38_Win/test_afx/Engine/source/console/console.h(887): error C2079: 'callback' uses undefined struct '_EngineConsoleExecCallbackHelper'
    1>          with
    1>          [
    1>              A=ShapeBase *
    1>          ] (..\..\..\..\..\Engine\source\afx\ea\afxEA_AreaDamage.cpp)
    1>          ..\..\..\..\..\Engine\source\afx\ea\afxEA_AreaDamage.cpp(227) : see reference to function template instantiation 'ConsoleValueRef Con::executef(A,B,C,D,E,F)' being compiled
    1>          with
    1>          [
    1>              A=ShapeBase *
    1>  ,            B=const char *
    1>  ,            C=const char *
    1>  ,            D=char *
    1>  ,            E=char *
    1>  ,            F=const char *
    1>          ]
    1>C:/Torque/Torque3D_38_Win/test_afx/Engine/source/console/console.h(887): error C2440: 'initializing' : cannot convert from 'ShapeBase *' to 'int' (..\..\..\..\..\Engine\source\afx\ea\afxEA_AreaDamage.cpp)
    1>          There is no context in which this conversion is possible
    1>C:/Torque/Torque3D_38_Win/test_afx/Engine/source/console/console.h(887): error C2059: syntax error : 'template' (..\..\..\..\..\Engine\source\afx\ea\afxEA_AreaDamage.cpp)
    1>  afxStatusBox.cpp
    1>C:/Torque/Torque3D_38_Win/test_afx/Engine/source/console/console.h(885): error C2079: 'callback' uses undefined struct '_EngineConsoleExecCallbackHelper'
    1>          with
    1>          [
    1>              A=StaticShapeData *
    1>          ] (..\..\..\..\..\Engine\source\afx\ea\afxEA_StaticShape.cpp)
    1>          ..\..\..\..\..\Engine\source\afx\ea\afxEA_StaticShape.cpp(158) : see reference to function template instantiation 'ConsoleValueRef Con::executef(A,B,C,D)' being compiled
    1>          with
    1>          [
    1>              A=StaticShapeData *
    1>  ,            B=const char *
    1>  ,            C=const char *
    1>  ,            D=StringTableEntry
    1>          ]
    1>C:/Torque/Torque3D_38_Win/test_afx/Engine/source/console/console.h(885): error C2440: 'initializing' : cannot convert from 'StaticShapeData *' to 'int' (..\..\..\..\..\Engine\source\afx\ea\afxEA_StaticShape.cpp)
    1>          There is no context in which this conversion is possible
    1>C:/Torque/Torque3D_38_Win/test_afx/Engine/source/console/console.h(885): error C2059: syntax error : 'template' (..\..\..\..\..\Engine\source\afx\ea\afxEA_StaticShape.cpp)
    1>C:/Torque/Torque3D_38_Win/test_afx/Engine/source/console/console.h(886): error C2079: 'callback' uses undefined struct '_EngineConsoleExecCallbackHelper'
    1>          with
    1>          [
    1>              A=GuiInspector *
    1>          ] (..\..\..\..\..\Engine\source\afx\ui\afxGuiSubstitutionField.cpp)
    1>          ..\..\..\..\..\Engine\source\afx\ui\afxGuiSubstitutionField.cpp(202) : see reference to function template instantiation 'ConsoleValueRef Con::executef(A,B,C,D,E)' being compiled
    1>          with
    1>          [
    1>              A=GuiInspector *
    1>  ,            B=const char *
    1>  ,            C=StringTableEntry
    1>  ,            D=StringTableEntry
    1>  ,            E=const char *
    1>          ]
    1>C:/Torque/Torque3D_38_Win/test_afx/Engine/source/console/console.h(886): error C2440: 'initializing' : cannot convert from 'GuiInspector *' to 'int' (..\..\..\..\..\Engine\source\afx\ui\afxGuiSubstitutionField.cpp)
    1>          There is no context in which this conversion is possible
    1>C:/Torque/Torque3D_38_Win/test_afx/Engine/source/console/console.h(886): error C2059: syntax error : 'template' (..\..\..\..\..\Engine\source\afx\ui\afxGuiSubstitutionField.cpp)
    1>C:/Torque/Torque3D_38_Win/test_afx/Engine/source/console/console.h(888): error C2079: 'callback' uses undefined struct '_EngineConsoleExecCallbackHelper'
    1>          with
    1>          [
    1>              A=GameBaseData *
    1>          ] (..\..\..\..\..\Engine\source\afx\ea\afxEA_CollisionEvent.cpp)
    1>          ..\..\..\..\..\Engine\source\afx\ea\afxEA_CollisionEvent.cpp(179) : see reference to function template instantiation 'ConsoleValueRef Con::executef(A,B,C,D,E,F,G)' being compiled
    1>          with
    1>          [
    1>              A=GameBaseData *
    1>  ,            B=StringTableEntry
    1>  ,            C=const char *
    1>  ,            D=const char *
    1>  ,            E=const char *
    1>  ,            F=char *
    1>  ,            G=StringTableEntry
    1>          ]
    1>C:/Torque/Torque3D_38_Win/test_afx/Engine/source/console/console.h(888): error C2440: 'initializing' : cannot convert from 'GameBaseData *' to 'int' (..\..\..\..\..\Engine\source\afx\ea\afxEA_CollisionEvent.cpp)
    1>          There is no context in which this conversion is possible
    1>C:/Torque/Torque3D_38_Win/test_afx/Engine/source/console/console.h(888): error C2059: syntax error : 'template' (..\..\..\..\..\Engine\source\afx\ea\afxEA_CollisionEvent.cpp)
    1>C:/Torque/Torque3D_38_Win/test_afx/Engine/source/console/console.h(883): error C2079: 'callback' uses undefined struct '_EngineConsoleExecCallbackHelper'
    1>          with
    1>          [
    1>              A=afxStatusBox *
    1>          ] (..\..\..\..\..\Engine\source\afx\ui\afxStatusBox.cpp)
    1>          ..\..\..\..\..\Engine\source\afx\ui\afxStatusBox.cpp(44) : see reference to function template instantiation 'ConsoleValueRef Con::executef(A,B)' being compiled
    1>          with
    1>          [
    1>              A=afxStatusBox *
    1>  ,            B=const char *
    1>          ]
    1>C:/Torque/Torque3D_38_Win/test_afx/Engine/source/console/console.h(883): error C2440: 'initializing' : cannot convert from 'afxStatusBox *' to 'int' (..\..\..\..\..\Engine\source\afx\ui\afxStatusBox.cpp)
    1>          There is no context in which this conversion is possible
    1>C:/Torque/Torque3D_38_Win/test_afx/Engine/source/console/console.h(883): error C2059: syntax error : 'template' (..\..\..\..\..\Engine\source\afx\ui\afxStatusBox.cpp)
    2>------ Build started: Project: AFXtest, Configuration: Release Win32 ------
    2>LINK : fatal error LNK1181: cannot open input file 'C:\Torque\Torque3D_38_Win\test_afx\My Projects\AFXtest\game\AFXtest DLL.lib'
    ========== Build: 0 succeeded, 2 failed, 15 up-to-date, 0 skipped ==========

     

    Any help appreciated. :?

×
×
  • Create New...