Jump to content
The Dark Mod Forums

Weapon Projectile issue


Recommended Posts

Hi, i start with a new fan mission but i get a problem, when i shot with a custom weapon that launch a lot of projectiles with a lot of spread,(like a shotgun) the projectile spread don't work, all projectiles are launched in to the same place (center view), it's very frustrating, maybe its a code bug, but in the weapon script "launchprojectiles();" the spread and the num_projectiles are not working.

Please, if anyone knows how i can fix it, just leave a reply or any information about that. If someone works on the official code, maybe can fix that issue for the new release, that can be useful for people that wants improve the actual weapons.

Sorry for my basic english, my mother language is spanish :)

Link to comment
Share on other sites

The weapon is a double barrel gun, in the fire function, here is the script

void weapon_arrowz::Fire() 
{  float ammoClip;
    ammoClip = ammoInClip();
    entity playerOwn = getOwner();
    if ( ammoClip == 1 ) {
        playAnim( ANIMCHANNEL_ALL, "fire_last" );
    if ( ammoClip > 1 ) {
        playAnim( ANIMCHANNEL_ALL, "fire" );
    launchProjectiles( 8, 8, 0, 1.0, 1.0 );            //here is the problem
    launchProjectiles( 12, 16, 0, 1.0, 1.0 );       // the spread is not working, first value "num of projectiles", second value "spread"

    waitUntil( animDone( ANIMCHANNEL_ALL, ARROWZ_FIRE_TO_IDLEX ) );
    weaponState( "Idle", ARROWZ_FIRE_TO_IDLEX );

i can post the full script of the weapon, but the problem is the launchprojectiles function,  but here is it



Edited by acdcbelmar
more especifications
Link to comment
Share on other sites

handgun works fine because uses iron sights, melee weapons are using the normal collision melee system, i want put a crossbow that can launch 3 arrows (enemies also can use the weapon, but for now only professional thieves can use the handgun ), in this mission the weapons are droppable, so you can clear your inventory of weak weapons. I think that add a weight for each special item can solve the unlimited inventory, so more items, more slow movement. what do you think?





Link to comment
Share on other sites

The mission is about slave traffic(horror), you must run away from your captors and decide if save the another persons. I have some monsters for the nightmare zones ( are zones in that the fear of the people manifests as monsters). I am learning how to use the darkradiant, because i was use the d3editor a lot of time, this summer i will release the mission i think, but the only thing that a want fix is the problem of the projectiles, the shotgun script and sound are very good, the model can change.

In the weapon projectile i was test the "firealongplayerview" and "launchfrombarrel" keys, but they not fix the problem

Edited by acdcbelmar
more especifications
Link to comment
Share on other sites

Here is the relevant code:

float spreadRad = DEG2RAD( spread );
for( i = 0; i < num_projectiles; i++ ) {
    ang = idMath::Sin( spreadRad * gameLocal.random.RandomFloat() );
    spin = (float)DEG2RAD( 360.0f ) * gameLocal.random.RandomFloat();
    //dir = playerViewAxis[ 0 ] + playerViewAxis[ 2 ] * ( ang * idMath::Sin( spin ) ) - playerViewAxis[ 1 ] * ( ang * idMath::Cos( spin ) );
    dir = muzzleAxis[ 0 ]; // Dram: Make the weapon shoot directly from the barrel bone. Found by Ishtvan
    if (projectileDef->dict.GetBool("fire_along_playerview", "0")) {
        // greebo: Fire the projectile along the playerview direction
        dir = playerViewAxis.ToAngles().ToForward();

The corresponding commit:

Revision: 1417
Author: dram
Date: 10 октября 2007 г. 13:08:24
-Changed weapon and player so that the arrow is launched from the muzzle angle rather then the player angle
-Changed the drifting to use 3 fracsins so that each axis is irrelevant of the other, thus giving a more random drifting
Modified : /trunk/game/player.cpp
Modified : /trunk/game/weapon.cpp

I think the original intent was to change the shooting direction from "view" to "muzzle". The spread was removed in process. The option to shoot by "view" direction was later returned under fire_along_playerview arg.

It seems that we can restore the spread back, but there are two problems:

  1. If some existing weapons accidentally pass nonzero spread, we will have to fix them too.
  2. If we fix the code, it would be hard for you to use it right now. Although I guess it is not impossible: we can build executable at current SVN, and give you folder with current shaders to override the ones from 2.07.
Link to comment
Share on other sites

Thanks for the reply. I understand the situation and i think that i can wait for the code fix, i was try to build the 2.06 version and i was fix the problem, but 2.06 get me a lot of crashes, so like i said, i can wait for that. Here is the that i was added, maybe can help:

//////////////////////////////////////////////////////////////////////////////////////////////////////////// thanks ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

This is other thing, it's not essential but i notice that when i test some functions

Another thing i had noticed is when you drop a item from the inventory that uses "inventoryDrop();" script (a custom player tool for example) the item is not dropped, the script runs but the item persist in the inventory, here is the code: this script is for use a item(playertool) for select a weapon like a inventory item, using "tdm_frob_weapon_selects_weapon" because the script that i made gives you a item, and if that is a weapon, you automatically select that item, so i can limit the amount of weapons, this is for my FM.

object playertools_weapon_knifeb : player_tools {
    string weapon;
    string item;
    void inventoryUse(entity userEntity, entity frobbedEntity, float buttonState);
    void inventoryDrop();   // here is it the other thing, the script runs but the item is not dropped
void playertools_weapon_knifeb::inventoryUse(entity userEntity, entity frobbedEntity, float buttonState)
     entity knifeb = sys.spawn(getKey("def_weapon_select"));
void playertools_weapon_knifeb::inventoryDrop()
    if ( $player1.getCurrentWeapon() == getKey("def_weapon_select"))
    entity knifey = sys.spawn("atdm:weapon_unarmed_item");

$player1.changeInvItemCount(getKey("inv_name"), getKey("inv_category"), -1); // for some reason, this function dont work, i cant understand why

/* // here is my script fix, but is better have a code function for this, 


    entity projectiles = sys.spawn(getKey("def_item_drop"));
    vector viewAngless = $player1.getViewAngles();
    vector directions = sys.angToForward(viewAngless);
    vector velocitys = directions;
    vector origins = $player1.getEyePos();
    origins += directions * 30;




object playertools_weapon_shortsword : player_tools {
    void inventoryUse(entity userEntity, entity frobbedEntity, float buttonState);
    void inventoryDrop();
void playertools_weapon_shortsword::inventoryUse(entity userEntity, entity frobbedEntity, float buttonState)
     entity knife = sys.spawn("atdm:weapon_shortsword");
void playertools_weapon_shortsword::inventoryDrop()
    if ( $player1.getCurrentWeapon() == "atdm:weapon_shortsword")
    entity knifex = sys.spawn("atdm:weapon_unarmed_item"); // custom item for select the unarmed weapon, using tdm_frob_weapon_select_weapon that selects the weapon that you pickup

    entity projectile = sys.spawn("atdm:playertools_weapon_knife");
    vector viewAngles = $player1.getViewAngles();
    vector direction = sys.angToForward(viewAngles);
    vector velocity = direction;
    vector origin = $player1.getEyePos();
    origin += direction * 30;
//    holdEntity(projectile.getName());


/////////////////////////////////////////////// for this thing maybe the problem is in the player.cpp , in this part of the code ///////////////////////////////////////////////////////

void idPlayer::DropInventoryItem()
    bool bDropped = false;
    CGrabber *grabber = gameLocal.m_Grabber;
    idEntity *heldEntity = grabber->GetSelected();
    idEntity *equippedEntity = grabber->GetEquipped();

    // Dequip or drop the item in the grabber hands first
    if( equippedEntity != NULL )
    else if(heldEntity != NULL)
        grabber->Update( this, false );
        // Grabber is empty (no item is held), drop the current inventory item
        const CInventoryCursorPtr& cursor = InventoryCursor();

        CInventoryItemPtr item = cursor->GetCurrentItem();
        CInventoryCategoryPtr category = cursor->GetCurrentCategory();

        // Do we have a droppable item in the first place?
        if (item != NULL && item->IsDroppable() && item->GetCount() > 0)
            // Retrieve the actual entity behind the inventory item
            idEntity* ent = item->GetItemEntity();
            DM_LOG(LC_INVENTORY, LT_INFO)LOGSTRING("Attempting to drop inventory entity %s\r", ent->name.c_str());

            // greebo: Try to locate a drop script function on the entity's scriptobject
            const function_t* dropScript = ent->scriptObject.GetFunction(TDM_INVENTORY_DROPSCRIPT);
            if( dropScript != NULL )
                // Call the custom drop script
                DM_LOG(LC_INVENTORY, LT_DEBUG)LOGSTRING("Running inventory drop script...\r");
                idThread* thread = new idThread(dropScript);
                thread->CallFunctionArgs(dropScript, true, "ee", ent, this);
//////////////////////////////////////////////////// here ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////               
                // The dropScript changes the inventory count itself, so don't set 
                // bDropped to true here.
            // greebo: Only place the entity in the world, if there is no custom dropscript
            // The flashbomb for example is spawning projectiles on its own.
            else if( DropToHands( ent, item ) )

//////////////////////// acdc start - here is my custom fix, i think that this form is better for call a script when a item is dropped, i dont know about coding but this works for me/////////////////////

if ( ent->spawnArgs.GetBool( "drop_script" ) )
            const function_t *func;
            idThread *thread;

            func = ent->scriptObject.GetFunction( ent->spawnArgs.GetString( "drop_script_call", "drop" ) );

            if ( func )
                // create a thread and call the function
                thread = new idThread();
                thread->CallFunction( ent, func, true );

//////////////////////////////////////// end of acdc ////////////////////////////
                DM_LOG(LC_INVENTORY, LT_INFO)LOGSTRING("Item was successfully put in hands: %s\r", ent->name.c_str());
                bDropped = true;
                // There wasn't space to drop the item
                StartSound( "snd_drop_item_failed", SND_CHANNEL_ITEM, 0, false, NULL );
                DM_LOG(LC_INVENTORY, LT_INFO)LOGSTRING("Grabber did not find space in the world to fit entity in hands: %s\r", ent->name.c_str());

            // Decrease the inventory count (this will also clear empty categories)
            // This applies for both stackable as well as droppable items
            if( bDropped)
                DM_LOG(LC_INVENTORY, LT_INFO)LOGSTRING("Item dropped, changing inventory count.\r");

                ChangeInventoryItemCount(item->GetName(), category->GetName(), -1); 

            // Always update the HUD, the drop script might have changed the inventory count itself.
            inventoryHUDNeedsUpdate = true;


maybe the crashes are causes for this changes that i made, but with the 2.06 version without changes i get some crashes also, so i dont know, maybe this information can help to the darkmod team

- thanks for all


Weapon.cpp Weapon.h

Link to comment
Share on other sites

in the two files that i was uploaded are my custom fix for the weapon problem, is another launchprojectile function that not replace the previous code, so actual weapons will be not changed, maybe needs a revision because i ' m not a expert coder, i am just beginning in this field. the changes are under the letters:

// acdc

Weapon.cpp Weapon.h

Link to comment
Share on other sites

I think the original intent was: if you are eager to customize item dropping, then you should take care of everything yourself.

I have managed to make spyglass droppable with custom method by adding the following code to class definition of playertools_spyglass:

    void inventoryDrop(entity ownerEntity);

and the following code at the file scope:

void playertools_spyglass::inventoryDrop(entity ownerEntity)
    ownerEntity.changeInvItemCount(getKey("inv_name"), getKey("inv_category"), -1);

It properly removes the spyglass from inventory. I have checked the C++ side, and it seems to do proper thing.


Probably you miss a parameter in your inventoryDrop method. Or maybe your item doesn't have the corresponding spawnargs.

Link to comment
Share on other sites



I think the original intent was: if you are eager to customize item dropping, then you should take care of everything yourself.

I have managed to make spyglass droppable with custom method by adding the following code to class definition of playertools_spyglass:



When was the spyglass not droppable?  I know I've thrown it several times in the past as a distraction tactic.

Link to comment
Share on other sites

9 minutes ago, Springheel said:

When was the spyglass not droppable?  I know I've thrown it several times in the past as a distraction tactic.

We are discussing the case when custom script method is called instead of builtin drop.

I have checked the script in SVN, and did not find inventoryDrop method anywhere. So I guess we have no custom-droppable items in the stock game.

Link to comment
Share on other sites

Speaking of the original issue with projectile spread.

Do we have any shooting weapons except for arrows? The base class atdm:projectile_arrow has spawnarg fire_along_playerview set. Theoretically, TDM once had weapons who fired directly from muzzle, instead of from view origin. Any idea if we have such weapons now (for purpose of testing) ?

Created issue 5041 about weapon spread.

UPDATE: Committed the fix to SVN. The spread works well with it, in my opinion.

Link to comment
Share on other sites

I don't think changing core mechanics like that is a good idea. It would be nice if you consulted the team first, plus this needs to be tested by at least several people.

It seems like the changes were tested but nothing was changed it the core mod, cool :)

Edited by peter_spy
Link to comment
Share on other sites

thanks for the help stgatilov, i can't compile the 2.07 version of the code for now because my visual studio 2013 only compiles 2.06 or below so i need made some changes in my pc programs. I will test the item dropping code tonight, maybe the script that i use for drop the item is not functional.

About the code of the projectile, if it cause problems for the game or players, can be added a function in weapon.cpp called "launchprojectile2" or "launchprojectileold"?, so the actual code for the arrow will be no affected for this and it will only works for custom weapon and testing. That is all, i will write the results later and maybe i will upload the pack of weapons in moddb, i think that more people wants make missions with a custom ambientation, (medieval, cyberpunk, post-apocalyptic, etc) and they can use my work

///////////////////// this is the change that i was made in the weapon.cpp based in the d3xp code //////////////////////////

// event defs

const idEventDef EV_Weapon_LaunchProjectilesEllipse("launchProjectilesEllipse", EventArgs('d', "num_projectiles", "", 'f', "spreada", "", 'f', "spreadb", "", 'f', "FuseOffset", "", 'f', "power", ""),
    EV_RETURNS_VOID, "no description");

// class defs

EVENT( EV_Weapon_LaunchProjectilesEllipse,    idWeapon::Event_LaunchProjectilesEllipse )

// code
void idWeapon::Event_LaunchProjectilesEllipse( int num_projectiles, float spreada, float spreadb, float fuseOffset, float power ) {
    idProjectile    *proj;
    idEntity        *ent;
    int                i;
    idVec3            dir;
    float            anga, angb;
    float            spin;
    float            distance;
    trace_t            tr;
    idVec3            start;
    idVec3            muzzle_pos;
    idBounds        ownerBounds, projBounds;

    if ( IsHidden() ) {

//    if ( !projectileDict.GetNumKeyVals() ) {
//    const char *classname = weaponDef->dict.GetString( "classname" );
//    gameLocal.Warning( "No projectile defined on '%s'", classname );
//    return;
//    }
    CInventoryWeaponItemPtr weaponItem = owner->GetWeaponItem(weaponDef->dict.GetString("inv_weapon_name"));
    if (weaponItem == NULL) return;

    // Retrieve the currently active projectile def name from the inventory item
    const idStr& projectileDefName = weaponItem->GetProjectileDefName();

    if (projectileDefName.IsEmpty())
        gameLocal.Warning("No projectile entityDef defined on '%s'", name.c_str());

    const idDeclEntityDef* projectileDef = gameLocal.FindEntityDef(projectileDefName);

    if (projectileDef == NULL)
        gameLocal.Warning("Projectile entityDef %s not found.", projectileDefName.c_str());
    // avoid all ammo considerations on a client
    if ( !gameLocal.isClient ) {
        CInventoryWeaponItemPtr weaponItem = owner->GetCurrentWeaponItem();

        // check if we're out of ammo or the clip is empty
        int ammoAvail = weaponItem->HasAmmo();
        if (!ammoAvail || ((clipSize != 0) && (ammoClip <= 0))) {

        if (clipSize && ammoRequired) {
            ammoClip -= powerAmmo ? (int)power : 1;

    // set the shader parm to the time of last projectile firing,
    // which the gun material shaders can reference for single shot barrel glows, etc
    renderEntity.shaderParms[ SHADERPARM_DIVERSITY ]    = gameLocal.random.CRandomFloat();
    renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ]    = -MS2SEC( gameLocal.time );

    if ( worldModel.GetEntity() ) {
        worldModel.GetEntity()->SetShaderParm( SHADERPARM_DIVERSITY, renderEntity.shaderParms[ SHADERPARM_DIVERSITY ] );
        worldModel.GetEntity()->SetShaderParm( SHADERPARM_TIMEOFFSET, renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] );

    // calculate the muzzle position
    if ( barrelJointView != INVALID_JOINT && projectileDef->dict.GetBool( "launchFromBarrel" ) ) {
        // there is an explicit joint for the muzzle
        GetGlobalJointTransform( true, barrelJointView, muzzleOrigin, muzzleAxis );
    } else {
        // go straight out of the view
        muzzleOrigin = playerViewOrigin;
        muzzleAxis = playerViewAxis;

    // add some to the kick time, incrementally moving repeat firing weapons back
    if ( kick_endtime < gameLocal.time ) {
        kick_endtime = gameLocal.time;
    kick_endtime += muzzle_kick_time;
    if ( kick_endtime > gameLocal.time + muzzle_kick_maxtime ) {
        kick_endtime = gameLocal.time + muzzle_kick_maxtime;

    if ( !gameLocal.isClient ) {
        ownerBounds = owner->GetPhysics()->GetAbsBounds();

        owner->AddProjectilesFired( num_projectiles );

        float spreadRadA = DEG2RAD( spreada );
        float spreadRadB = DEG2RAD( spreadb );

        for( i = 0; i < num_projectiles; i++ ) {
            //Ellipse Form
            spin = (float)DEG2RAD( 360.0f ) * gameLocal.random.RandomFloat();
            anga = idMath::Sin(spreadRadA * gameLocal.random.RandomFloat());
            angb = idMath::Sin(spreadRadB * gameLocal.random.RandomFloat());
            dir = playerViewAxis[ 0 ] + playerViewAxis[ 2 ] * ( angb*idMath::Sin( spin ) ) - playerViewAxis[ 1 ] * ( anga*idMath::Cos( spin ) );

            gameLocal.SpawnEntityDef( projectileDef->dict, &ent );
            if ( !ent || !ent->IsType( idProjectile::Type ) ) {
                const char *projectileName = weaponDef->dict.GetString( "def_projectile" );
                gameLocal.Error( "'%s' is not an idProjectile", projectileName );

            proj = static_cast<idProjectile *>(ent);
            proj->Create( owner, muzzleOrigin, dir );

            projBounds = proj->GetPhysics()->GetBounds().Rotate( proj->GetPhysics()->GetAxis() );

            // make sure the projectile starts inside the bounding box of the owner
            if ( i == 0 ) {
                muzzle_pos = muzzleOrigin + playerViewAxis[ 0 ] * 2.0f;
                if ( ( ownerBounds - projBounds).RayIntersection( muzzle_pos, playerViewAxis[0], distance ) ) {
                    start = muzzle_pos + distance * playerViewAxis[0];
                else {
                    start = ownerBounds.GetCenter();
                gameLocal.clip.Translation( tr, start, muzzle_pos, proj->GetPhysics()->GetClipModel(), proj->GetPhysics()->GetClipModel()->GetAxis(), MASK_SHOT_RENDERMODEL, owner );
                muzzle_pos = tr.endpos;

            proj->Launch( muzzle_pos, dir, pushVelocity, fuseOffset, power );

        // toss the brass
        if( brassDelay >= 0 ) {
            PostEventMS( &EV_Weapon_EjectBrass, brassDelay );

    // add the light for the muzzleflash
    if ( !lightOn ) {

    owner->WeaponFireFeedback( &weaponDef->dict );

    // reset muzzle smoke
    weaponSmokeStartTime = gameLocal.time;


Thanks again for the support , i love the dark mod comunity, make my first mission is like a dream. I was doing mods for Quake4 and Doom3, but TheDarkMod haves more interesting things/functions (water, enemy vision based on light, attach a lot of things to the weapon, doors, enhanced Graphics , etc) and keep improving more and more.


Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recent Status Updates

    • snatcher

      TDM Modpack v2.6 released!
      · 0 replies
    • peter_spy

      Perhaps an unpopular opinion: TDM team might benefit from someone with actual QA experience; someone with naturally and professionally developed curiosity, who is interested in how and why things work, how they break At least to me it's kind of mind-boggling how untested some rather important features are (first the absence alert feature for items, now the rope +body carry behavior).
      · 4 replies
    • nbohr1more

      The Dark Mod is hosting an Ask Me Anything thread on the PC Gaming reddit forum:  https://www.reddit.com/r/pcgaming/comments/10nfcwj/hello_we_are_the_international_development_team/
      Feel free to join the discussion there
      · 2 replies
    • stgatilov

      Bumped into an interesting piece of wisdom called Hyrum's Law:
      With a sufficient number of users of an API, it does not matter what you promise in the contract: all observable behaviors of your system will be depended on by somebody.
      · 5 replies
    • The Black Arrow

      I love playing The Dark Mod when it's cold in my place. Bonus points when it's a bit (or even very) dark and it's raining, too.
      · 2 replies
  • Create New...