Game Development Community

dev|Pro Game Development Curriculum

Adding a Alternate fire/Second trigger to weapons

by Dean Calver · 04/17/2004 (1:18 pm) · 16 comments

To add a alternate fire there are 2 main changes, one adds a new state to the shape and the other is adding a new button to the player. This will cover adding the adding of a new weapon state, I'll come back and cover the button changes if nessecary.

Basically everything in shape*.h or shape*.cc that refer to to trigger should copied and changed to secondtrigger. Precise examples below, though its looks like alot in most cases its simple a case of duplicating the existing trigger code and change all references to trigger with secondTrigger.

Add the following line to enable a new state
In shapeBase.h,
after const char* stateTransitionTriggerDown add [MaxStates];
const char* stateTransitionSecondTriggerUp   [MaxStates];
const char* stateTransitionSecondTriggerDown [MaxStates];
also after bool mTrigger[MaxTriggerKeys] add
bool mSecondTrigger[MaxTriggerKeys];
also after bool triggerDown add
bool secondTriggerDown;
change an additional parameter to virtual void setImage( ... ), so it looks like
virtual void setImage(U32 imageSlot, ShapeBaseImageData* imageData, StringHandle &skinNameHandle, bool loaded = true, bool ammo = false, bool triggerDown = false, bool secondTriggerDown = false, bool target = false);
after bool getImageTriggerState(U32 imageSlot) add
void setImageSecondTriggerState(U32 imageSlot,bool trigger);
bool getImageSecondTriggerState(U32 imageSlot);

In shapeImage.cc
After transition.trigger[0] = transition.trigger[1] = -1; add
transition.secondtrigger[0] = transition.secondtrigger[1] = -1;
after stateTransitionTriggerDown[i] = 0; add
stateTransitionSecondTriggerUp[i] = 0;      stateTransitionSecondTriggerDown[i] = 0;
after s.transition.trigger[1] = lookupState stateTransitionTriggerDown[i]); add
s.transition.secondtrigger[0] = lookupState(stateTransitionSecondTriggerUp[i]);
s.transition.secondtrigger[1] = lookupState(stateTransitionSecondTriggerDown[i]);
after addField("stateTransitionOnTriggerDown", TypeString, Offset(stateTransitionTriggerDown, ShapeBaseImageData), MaxStates); add
addField("stateTransitionOnSecondTriggerUp", TypeString, Offset(stateTransitionSecondTriggerUp, ShapeBaseImageData), MaxStates);
addField("stateTransitionOnSecondTriggerDown", TypeString, Offset(stateTransitionSecondTriggerDown, ShapeBaseImageData), MaxStates);
after stream->writeInt(s.transition.trigger[1]+1,NumStateBits); add
stream->writeInt(s.transition.secondtrigger[0]+1,NumStateBits);
stream->writeInt(s.transition.secondtrigger[1]+1,NumStateBits);
after s.transition.trigger[1] = stream->readInt(NumStateBits) - 1; add
s.transition.secondtrigger[0] = stream->readInt(NumStateBits) - 1;
s.transition.secondtrigger[1] = stream->readInt(NumStateBits) - 1;
after triggerDown = false; add
secondTriggerDown = false;
after if ((ns = stateData.transition.trigger[1]) != -1)
if (isImageReady(imageSlot,ns,depth))
return true;
add
if ((ns = stateData.transition.secondtrigger[1]) != -1)
    if (isImageReady(imageSlot,ns,depth))
        return true;

change ShapeBase::setImage( ... ) to
void ShapeBase::setImage(U32 imageSlot, ShapeBaseImageData* imageData, StringHandle& skinNameHandle, bool loaded, bool ammo, bool triggerDown, bool secondTriggerDown, bool target)
after image.triggerDown = triggerDown; add
image.secondTriggerDown = secondTriggerDown;
after image.triggerDown = false; add
image.secondTriggerDown = false;
add 2 functions
bool ShapeBase::getImageSecondTriggerState(U32 imageSlot)
{
   if (isGhost() || !mMountedImageList[imageSlot].dataBlock)
      return false;
   return mMountedImageList[imageSlot].secondTriggerDown;
}

void ShapeBase::setImageSecondTriggerState(U32 imageSlot,bool trigger)
{
   if (isGhost() || !mMountedImageList[imageSlot].dataBlock)
      return;
   MountedImage& image = mMountedImageList[imageSlot];

   if (trigger) {
      if (!image.secondTriggerDown && image.dataBlock) {
         image.secondTriggerDown = true;
         if (!isGhost()) {
            setMaskBits(ImageMaskN << imageSlot);
            updateImageState(imageSlot,0);
         }
      }
   }
   else
      if (image.secondTriggerDown) {
         image.secondTriggerDown = false;
         if (!isGhost()) {
            setMaskBits(ImageMaskN << imageSlot);
            updateImageState(imageSlot,0);
         }
      }
}
after if ((ns = stateData.transition.trigger[image.triggerDown]) != -1) {
setImageState(imageSlot,ns);
return;
}
add
if ((ns = stateData.transition.secondtrigger[image.secondTriggerDown]) != -1) {
      setImageState(imageSlot,ns);
      return;
   }
after if ((ns = stateData.transition.trigger[image.triggerDown]) != -1) {
setImageState(imageSlot,ns);
return;
}
if ((ns = stateData.transition.secondtrigger[image.secondTriggerDown]) != -1) {
         setImageState(imageSlot,ns);
         return;
      }

About the author

Been a games dev for more years than its comfortable to remember. Have shipped a fair few games, most recently have been Lead Programmer on Brink and Heavenly Sword.


#1
04/18/2004 (4:32 am)
Not sure if anything actualy uses it, but any other instances of setImage in classes that inherit from ShapeBase also need to be changed so that they also use the same function signature. Again I'm not sure if anything actualy does use it tho.
#2
04/18/2004 (4:55 am)
If you don't want to make any engine changes and just script it, check out www.garagegames.com/mg/forums/result.thread.php?qt=6637
(not sure if there's any difference in functionality since I didn't try this resource)
#3
05/09/2004 (9:02 pm)
Could you post your script changes?

thx,
RedCore
#4
05/09/2004 (10:00 pm)
err, click on the link I posted?
#5
05/10/2004 (2:08 pm)
Beffy: I was talking to Dean Calvin :)

"I
#6
07/13/2004 (5:00 pm)
will it work for vehicle weapon mounts?

thanks
#7
09/09/2004 (1:57 pm)
stefan did your link work? I'm having major problems with it. I found some more things too work off of their a little scattered though mayhaps when I figure the problem I write a climax too all that material I have the newest torque at this point in time so maybe that would be the problem?
#8
09/09/2004 (9:29 pm)
my link? what are you talking about? :P
what problems do you have with what? the script I posted in the thread I've linked to? that script worked of course, if thats what you mean...
#9
07/19/2005 (8:16 am)
One additional piece that is necessary in the current HEAD as of 7/19/05

You will need to go to shapeBase.h and go down to about line 146 in the middle of defining the Transition struct. After the line

S32 trigger[2]; ///< Trigger up/down

add

S32 secondtrigger[2];


@Dean ... A very nice piece of work...
#10
02/16/2006 (6:05 pm)
I just wanted to post my appreciation of this resource. I wanted to also make a comment on what Stefan asked about the difference between this resource and his own. I looked at both ways and the reason I liked this resource best is it makes it very easy to integrate the secondary fire into the state system for the weapons. Which is a huge advantage imo.
#11
08/03/2006 (10:50 am)
ok, so after implementing this resource. how do u edit the weapon script?

like stateOnSecondTriggerDown= altfire
state[7]=alt fire
function::Altfire

(jsut int he direction, not the actual script, im missing a lot)

but would the general appreanace look like this?

also how do u bind the key?
would it be: funation secondTrigger()
{
What would go here????
}



move.bind.etc


*i hope this thread isnt closed:S
#12
12/17/2006 (1:56 am)
I use many mount points on my player characters and want to be able to fire off all the different weapons.
This is what I came up with:
function Armor::onTrigger(%this, %obj, %triggerNum, %val)
{
    %weapon = %obj.getMountedImage(%triggerNum);
    if(%triggerNum > 2)  //if it is not the default first 2 triggers or jump
    {
    	if(!isObject(%weapon) || (%weapon.getClassName() !$= "ShapeBaseImageData"))
    	{
    	   return;
    	}
    	if(%val == 1)
        {
           %weapon.onFire(%obj,%triggerNum);
        }
    }
}
#13
07/17/2007 (6:19 am)
@ Brokeass Games: yes, but this doesnt hack into the stateMachine, meaning that if you would send loads of triggers from the client, your weapon would fire at an unlimited rate.


I also have a question though. normally blablaOnTriggerDown or Up responds to $mvTriggerCount0 right? what triggercount would this respond to? we did not define that did we?
#14
03/26/2008 (7:41 am)
In player.cc, updateMove (I think), the image trigger state is set from the move trigger array.

Useful resource, thanks!
#15
08/08/2008 (10:26 pm)
@Dean: you had mentioned following up on the script implementation--I don't suppose you'd care to follow up?

Although I don't really know C++, I can generally puzzle this sort of stuff out--but in this case I'm baffled. How does one go about modifying the Image with alternate fire information? I mean presumeably no one is going to go to this trouble to have it fire in exactly the same way.

For example (also), I don't see that trigger information is passed onto Image::onFire functions. It seems to me that would be an easy place to differentiate, say, the spread of your shotgun, or the speed of your projectiles.

Any input (from anyone) would be greatly appreciated! Long and short of it is I can't figure out how to actually use this code.
#16
05/21/2009 (2:51 pm)
@Dean - FYI. This resource has proven itself as solid over the years and it was time for it to become official. I merged this into Torque 3D (with the minor change of calling it the 'alt' trigger) and it will be part of the core starting with beta 3.