Advertisement
techforce

Swinging Grappling hook

Oct 7th, 2014
3,001
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Clone C 14.58 KB | None | 0 0
  1. /====================================================================
  2. //
  3. // SWINGING GRAPPLING HOOK          by: Perecli Manole AKA Bort
  4. //
  5. //====================================================================
  6. // Aside from this new file, the following are the modifications
  7. // done to id's original source files:
  8. //--------------------------------------------------------------------
  9. // File: Progs.src
  10. // Location: before the "weapons.qc" line
  11. // Added: hook.qc
  12. //--------------------------------------------------------------------
  13. // File: Client.qc
  14. // Procedure: PlayerPostThink
  15. // Location: before line "W_WeaponFrame ();"
  16. // Added: CheckGrapHook ();
  17. //--------------------------------------------------------------------
  18. // File: World.qc
  19. // Procedure: worldspawn
  20. // Location: after line "precache_model ("progs/s_spike.mdl");"
  21. // Added: precache_model ("progs/hook.mdl");
  22. //        precache_model ("progs/chain.mdl");
  23. //--------------------------------------------------------------------
  24. // File: Weapons.qc
  25. // Procedure: W_Precache
  26. // Location: end of procedure
  27. // Added: precache_sound ("shambler/smack.wav");
  28. //        precache_sound ("blob/land1.wav");
  29. //        precache_sound ("hook/chain1.wav");
  30. //        precache_sound ("hook/chain2.wav");
  31. //        precache_sound ("hook/retract.wav");
  32. //--------------------------------------------------------------------
  33. // File: Defs.qc
  34. // Declaration group: player only fields
  35. // Location: after line ".float pain_finished;"
  36. // Added: .float hook;
  37. //--------------------------------------------------------------------
  38.  
  39. /*
  40. Rob;
  41. <hook>.ammo_shells: grading raise/lower
  42. <hook>.ammo_nails:  damageable entity flag
  43. */
  44.  
  45.  
  46. void(vector org, vector vel, float damage) SpawnBlood;  // prototype
  47. float () crandom;                               // prototype
  48.  
  49. // hook bit flags
  50. float   HOOK_ON     = 1;        // set if hook command is active
  51. float HOOK_IN   = 2;        // set if hook has attached
  52. float SHRINK_ON     = 4;        // set if shrink chain is active
  53. float GROW_ON   = 8;        // set if grow chain is active
  54.  
  55. // impulse constants
  56. float I_HOOK        = 64;
  57. float   I_GROW      = 65;
  58. float   I_SHRINK        = 66;
  59. float   I_STOP      = 67;
  60.  
  61. // constants
  62. float MIN_CHAIN_LEN     = 40;       // minimum chain length
  63. float MAX_CHAIN_LEN     = 1000; // maximum chain length
  64. float CHAIN_LINK_LEN    = 55;       // length between chain link origins
  65.  
  66.  
  67.  
  68. //--------------------------------------------------------------------
  69. // Vector dot product function
  70. //--------------------------------------------------------------------
  71. float (vector from, vector onto) Dot =
  72. {
  73.     return from_x * onto_x + from_y * onto_y + from_z * onto_z;
  74. };
  75.  
  76.  
  77. //--------------------------------------------------------------------
  78. // Removes hook and detaches player
  79. //--------------------------------------------------------------------
  80. void () DropHook =
  81. {
  82.  
  83.     local entity linkptr, nextptr;
  84.  
  85.     // remove all hook flags
  86.     self.owner.shook = 0;
  87.     sound (self.owner, CHAN_AUTO, "weapons/bounce2.wav", 1, ATTN_NORM);
  88.  
  89.     // removes hook and chain
  90.     linkptr = self.goalentity;
  91.     while (linkptr != world)
  92.     {
  93.         nextptr = linkptr.goalentity;
  94.         remove (linkptr);
  95.         linkptr = nextptr;
  96.     }
  97.     remove( self );
  98.  
  99. };
  100.  
  101.  
  102. //--------------------------------------------------------------------
  103. // Spawn and removes and refreshes chain links
  104. //--------------------------------------------------------------------
  105. void () MaintainLinks =
  106. {
  107.  
  108.     local vector chainvec,      // vector of the chain
  109.                      p_self_origin, // predicted future hook origin
  110.                      chainunit;     // vector of chain with distance of 1
  111.     local entity newlink,       // pointer to chain link being added
  112.                      currlink,      // pointer to current link being traversed
  113.                      nextlink;      // pointer to next link after current link
  114.     local float chainlen,       // length of chain
  115.                     currpos,        // numeric position of currlink
  116.                     linknum,        // number of links that should exist
  117.                     linkstart;      // length from hook at which currlink starts
  118.  
  119.                    
  120.                    
  121.     // predicts hook's future position since chain links fall behind
  122.     currpos = vlen(self.velocity) / 22;   // currpos used here just as an intermediate value
  123.     p_self_origin = self.origin + normalize(self.velocity) * currpos;
  124.  
  125.         // get info about chain
  126.  
  127.     // Rob; put 8 units back for appearances in cam view
  128.     if ( (self.dest2_x & (self.owner.flags & FL_CREEPCAM)) )
  129.     {
  130.         makevectors( self.owner.v_angle );
  131.         chainvec = (((self.owner.origin + '0 0 16') - v_forward * 8) - p_self_origin);
  132.     }
  133.     else
  134.         chainvec = ((self.owner.origin + '0 0 16') - p_self_origin);
  135.  
  136.     chainunit = normalize(chainvec);
  137.     chainvec = chainvec - chainunit * 18;
  138.     chainlen = vlen(chainvec);
  139.  
  140.     currlink = self;
  141.     currpos = 0;
  142.  
  143.     // generate and refresh links
  144.     linknum = ceil(chainlen / CHAIN_LINK_LEN);
  145.     while (currpos < linknum)
  146.     {
  147.         // add entities if chain's length grows
  148.         if (currlink.goalentity == world)
  149.         {
  150.             newlink = spawn();
  151.             newlink.movetype = MOVETYPE_NOCLIP;
  152.             newlink.solid = SOLID_NOT;
  153.             newlink.effects = EF_NOMODELFLAGS | EF_LOWPRECISION;
  154.             setmodel (newlink, "progs/chain.mdl");
  155.             setsize (newlink, '0 0 0', '0 0 0');
  156.             newlink.goalentity = world;
  157.             currlink.goalentity = newlink;
  158.         }
  159.         currlink = currlink.goalentity;
  160.         currpos = currpos + 1;
  161.  
  162.         // set angles
  163.         currlink.angles = vectoangles(chainvec);
  164.  
  165.         // fixes vectoangles round off error
  166.         if ((currlink.angles_y > 0) && (currlink.angles_y < 180))
  167.             currlink.angles = currlink.angles + '0 1 0';
  168.  
  169.         // vibrates chain links on the z axis
  170.         //currlink.angles_z = currlink.angles_z + crandom() * 30;
  171.  
  172.         // set position and frames
  173.         linkstart = (currpos - 1) * CHAIN_LINK_LEN;
  174.         if (currpos < linknum)
  175.         {
  176.             setorigin (currlink, p_self_origin + chainunit * (linkstart + CHAIN_LINK_LEN / 2 ));
  177.             currlink.frame = 9;
  178.         }
  179.         else
  180.         {
  181.             setorigin (currlink, p_self_origin + chainunit * (linkstart + (chainlen - linkstart) / 2 ));
  182.             currlink.frame = floor((chainlen - linkstart) / CHAIN_LINK_LEN * 10);
  183.         }
  184.     }
  185.  
  186.     // remove remaining entities if chain's length shrinks
  187.     nextlink = currlink.goalentity;
  188.     currlink.goalentity = world;
  189.     currlink = nextlink;
  190.     while (currlink != world)
  191.     {
  192.         nextlink = currlink.goalentity;
  193.         remove (currlink);
  194.         currlink = nextlink;
  195.     }
  196. };
  197.  
  198.  
  199. //--------------------------------------------------------------------
  200. // Hook behavior function
  201. //--------------------------------------------------------------------
  202. float GROW_RATE = 16;
  203. float SHRINK_RATE = -20;
  204. void () HookBehavior =
  205. {
  206.  
  207.     local vector spray;     // for blood
  208.     local vector chainvec;      // chain vector
  209.     local vector velpart;       // player's velocity component moving to or away from hook
  210.     local float chainlen;       // length of extended chain
  211.     //local float framestep;        // grow or shrink step per frame
  212.     local float f1, f2;     // restrainment forces
  213.     local float i1, i2;     // intermediate values
  214.  
  215.     local float gs; // Rob
  216.  
  217.     self.nextthink = time + sys_ticrate;
  218.  
  219.     // decide when to disconnect hook
  220.     if (  !(self.owner.shook & HOOK_ON) ||  // if hook has been retracted
  221.             self.owner.teleport_time > time ||  // if player goes through teleport
  222.             self.owner.solid == SOLID_NOT   ||  // if player dies
  223.             self.enemy.solid == SOLID_NOT || !self.owner.button0)   // if target dies
  224.     {
  225.         DropHook();
  226.        
  227.         return;
  228.     }
  229.  
  230.     // give some damage to entities that take damage
  231.     if (self.enemy.takedamage)
  232.     {
  233.         if (time > self.wait)
  234.         {
  235.                if (ODDFRAME)
  236.             T_Damage (self.enemy, self, self.owner, 5);
  237.  
  238.             // when hook hits live entity add blood and sounds
  239.             if (self.enemy.solid == SOLID_SLIDEBOX)
  240.             {
  241.                 // .ammo_nails flag used only here
  242.                 if (! self.ammo_nails)
  243.                 {
  244.                     sound (self, CHAN_AUTO, "shambler/smack.wav", 1, ATTN_NORM);
  245.                     self.ammo_nails = TRUE;
  246.                 }
  247.                 else
  248.                     sound (self, CHAN_AUTO, "blob/land1.wav", 0.8, ATTN_NORM);
  249.                 spray_x = 100 * crandom();
  250.                 spray_y = 100 * crandom();
  251.                 spray_z = 100 * crandom() + 50;
  252.                 SpawnBlood (self.origin, spray, 20);
  253.                 setorigin (self, self.enemy.origin + self.enemy.mins + self.enemy.size * 0.5);
  254.             }
  255.  
  256.             self.wait = time + 0.3;
  257.         }
  258.     }
  259.  
  260.     self.velocity = self.enemy.velocity;
  261.  
  262.     chainvec = self.origin - (self.owner.origin + '0 0 16');
  263.     chainlen = vlen (chainvec);
  264.  
  265. // .ammo_shells = +- amount to size
  266.     gs = self.ammo_shells;
  267.     ////////////////////////////////////////////////
  268.     if (self.owner.button0)
  269.     {  gs = gs + 2;
  270.         if (gs > GROW_RATE) gs = GROW_RATE;
  271.     }
  272.     else
  273.     {  
  274.     DropHook();
  275.        
  276.         return;
  277.     gs = gs - 4;
  278.         if (gs < SHRINK_RATE) gs = SHRINK_RATE;
  279.     }
  280.     /*
  281.     else
  282.     {
  283.         if (gs > 0)
  284.         {   gs = gs - 2; // fade from grow
  285.             if (gs < 0) gs = 0;
  286.         }
  287.         if (gs < 0)
  288.         {   gs = gs + 4; // fade from shrink
  289.             if (gs > 0) gs = 0;
  290.         }
  291.     }
  292.     */
  293.     self.armorvalue = self.armorvalue + gs;
  294.  
  295.     if (gs > 0)
  296.     {
  297.         if ( (self.owner.flags & FL_ONGROUND) )
  298.             self.armorvalue = chainlen;
  299.         else
  300.         {
  301.             if (self.delay < time)
  302.             {
  303.                 f1 = gs / GROW_RATE;
  304.                 //sound (self.owner, CHAN_AUTO, "weapons/chain1.wav", f1, ATTN_NORM);
  305.                 self.delay = time + 0.2;
  306.             }
  307.         }
  308.         if ( self.armorvalue > MAX_CHAIN_LEN )
  309.             self.armorvalue = MAX_CHAIN_LEN;
  310.     }
  311.     if (gs < 0)
  312.     {
  313.         // fixes not raising when directly under the hook
  314.         if ( (self.owner.flags & FL_ONGROUND) )
  315.             self.owner.flags = self.owner.flags - FL_ONGROUND;
  316.  
  317.         if (self.armorvalue < MIN_CHAIN_LEN)
  318.             self.armorvalue = MIN_CHAIN_LEN;
  319.         else
  320.         {
  321.             if (self.delay < time)
  322.             {
  323.                 i1 = fabs(gs);
  324.                 i2 = fabs(SHRINK_RATE);
  325.                 f1 = i1 / i2;
  326.                 //sound (self.owner, CHAN_AUTO, "weapons/chain2.wav", f1, ATTN_NORM);
  327.                 self.delay = time + 0.2;
  328.             }
  329.         }
  330.     }
  331.     ///////////////////////////////////////////////
  332.     self.ammo_shells = gs;
  333.  
  334.  
  335. // chain physics
  336.  
  337.     // if player's location is beyond the chain's reach
  338.     if (chainlen > self.armorvalue)
  339.     {
  340.         // determine player's velocity component of chain vector
  341.         i1 = Dot(self.owner.velocity,chainvec);
  342.         i2 = Dot(chainvec,chainvec);
  343.         velpart = chainvec * (i1 / i2);
  344.  
  345.         // restrainment default force
  346.         f2 = (chainlen - self.armorvalue) * 5;
  347.  
  348.         // if player's velocity heading is away from the hook
  349.         if (Dot(self.owner.velocity,chainvec) < 0)
  350.         {
  351.             if (chainlen > self.armorvalue)
  352.             self.owner.velocity = self.owner.velocity - (velpart * 0.4);
  353.            
  354.             // if chain has streched for 25 units
  355.             //if (chainlen > self.armorvalue + 25)
  356.                 // remove player's velocity component moving away from hook
  357.             //  self.owner.velocity = self.owner.velocity - velpart;
  358.             f1 = f2;
  359.         }
  360.         else  // if player's velocity heading is towards the hook
  361.         {
  362.             if (vlen(velpart) < f2)
  363.                 f1 = f2 - vlen(velpart);
  364.             else
  365.                 f1 = 0;
  366.         }
  367.     }
  368.     else
  369.         f1 = 0;
  370.  
  371.     // applys chain restrainment
  372.     self.owner.velocity =  0.5 *(self.owner.velocity + normalize(chainvec) * f1);
  373.  
  374.     MaintainLinks ();
  375. };
  376.  
  377.  
  378. //--------------------------------------------------------------------
  379. // Hook's touch function
  380. //--------------------------------------------------------------------
  381. void() HookTouch =
  382. {
  383.     // armorvalue is used to hold current length of chain
  384.     self.armorvalue = vlen(self.origin - (self.owner.origin + '0 0 16'));
  385.  
  386.     // flags hook as being attached to something
  387.     self.owner.shook = self.owner.shook | HOOK_IN;
  388.  
  389.     if (other.solid != SOLID_SLIDEBOX)
  390.     {
  391.         sound (self, CHAN_AUTO, "player/axhit2.wav", 1, ATTN_NORM);
  392.         self.avelocity = '0 0 0';
  393.     }
  394.  
  395.     self.velocity = other.velocity;
  396.  
  397.     self.enemy = other;
  398.     self.think = HookBehavior;
  399.     self.nextthink = time + sys_ticrate;
  400.     self.touch = SUB_Null;
  401.  
  402. };
  403.  
  404.  
  405. //--------------------------------------------------------------------
  406. // Limit hook length during launch
  407. //--------------------------------------------------------------------
  408. void() LaunchHook =
  409. {
  410.  
  411.  
  412.     // armorvalue is used to hold current length of chain
  413.     self.armorvalue = vlen(self.origin - (self.owner.origin + '0 0 32'));
  414.  
  415.     if ( !(self.owner.shook & HOOK_ON) ||
  416.             self.armorvalue > MAX_CHAIN_LEN ||
  417.             self.owner.solid == SOLID_NOT || !self.owner.button0    )
  418.     {
  419.         DropHook();
  420.         return;
  421.     }
  422.  
  423.     MaintainLinks ();
  424.  
  425.     self.nextthink = time + sys_ticrate;
  426. };
  427.  
  428.  
  429. //--------------------------------------------------------------------
  430. // Initiates the hook
  431. //--------------------------------------------------------------------
  432. void(entity myself) InitiateHook =
  433. {
  434.  
  435.     local entity newhook;
  436.  
  437.     newhook = spawn ();
  438.     newhook.owner = myself;
  439.     newhook.classname = "hook";
  440.     newhook.movetype = MOVETYPE_FLY;
  441.     newhook.solid = SOLID_BBOX;
  442.     newhook.effects = EF_NOMODELFLAGS | EF_LOWPRECISION;
  443.     setmodel (newhook, "progs/hook.mdl");
  444.     setsize (newhook, '0 0 0', '0 0 0');
  445.     makevectors (myself.v_angle);
  446.     setorigin (newhook, myself.origin + (v_forward*16) + '0 0 32' );
  447.     newhook.velocity = v_forward*2000;
  448.     newhook.angles = vectoangles(v_forward);
  449.     newhook.avelocity = '0 0 600';
  450.     sound (myself, CHAN_AUTO, "weapons/ax1.wav", 1, ATTN_NORM);
  451.      
  452.    
  453.     // used as pointer to first chain link
  454.     newhook.goalentity = world;
  455.  
  456.     // Rob; (reminders 0 init values used)
  457.     // self.wait = 0;  // damage to ents wait cycle
  458.     // self.ammo_shells = 0; // graded shrink/grow variable
  459.     // self.ammo_nails = FALSE;  // initial hit flag for live ents
  460.     // self.delay = 0; // wait cycle for chain raising/lowering sounds
  461.  
  462.     newhook.touch = HookTouch;
  463.     newhook.nextthink = time + sys_ticrate;
  464.     newhook.think = LaunchHook;
  465. };
  466.  
  467.  
  468. // called by player jump events (weapons.qc: W_WeaponFrame() )
  469. void() CheckGrapHookJump =
  470. {
  471.  
  472.     if ( (self.shook & HOOK_IN) )
  473.     {
  474.         if ( (self.flags & FL_JUMPRELEASED) &&  // previous jump cycle has finished
  475.              !(self.flags & FL_ONGROUND) )      // player not on ground
  476.         {
  477.             self.shook = 0; // let hook entity's next think know it's dead
  478.             self.velocity_z = self.velocity_z + 200;
  479.             sound (self, CHAN_BODY, "player/plyrjmp8.wav", 1, ATTN_NORM);
  480.         }
  481.     }
  482. };
  483.  
  484. //--------------------------------------------------------------------
  485. // Checks impulse
  486. //--------------------------------------------------------------------
  487. void() CheckGrapHook =
  488. {
  489.     if ((!(self.shook & HOOK_ON)) && self.button0)
  490.     {
  491.         // flags hook as being active
  492.         self.shook = HOOK_ON;
  493.  
  494.         InitiateHook (self);
  495.         return;
  496.     }
  497.  
  498.     /*
  499.    
  500.     if (self.shook & HOOK_ON)
  501.     {
  502.         // release hook
  503.         if (self.impulse == I_HOOK)
  504.         {
  505.             self.shook = self.shook - (self.shook & HOOK_ON);
  506.             return;
  507.         }
  508.  
  509.         // deactivate chain growth or shrink
  510.         if (!self.button0)
  511.         {
  512.             self.shook = self.shook - (self.shook & (GROW_ON | SHRINK_ON));
  513.             return;
  514.         }
  515.  
  516.         // activate chain growth
  517.         if (self.impulse == I_GROW)
  518.         {
  519.             self.shook = self.shook | GROW_ON;
  520.             self.shook = self.shook - (self.shook & SHRINK_ON);
  521.             return;
  522.         }
  523.  
  524.         // activate chain shrinking
  525.         if (self.button0 )
  526.         {
  527.             self.shook = self.shook | SHRINK_ON;
  528.             self.shook = self.shook - (self.shook & GROW_ON);
  529.         }
  530.     }
  531.     */
  532. };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement