Advertisement
techforce

GYRO

Oct 11th, 2011
518
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Clone C 17.97 KB | None | 0 0
  1.  
  2. /*
  3. =================================================================
  4.  
  5.     Gyro - The QuakeC Physics Plugin
  6.  
  7.         Version 1.0
  8.         By Quake Matt (rogermelon@yahoo.com)
  9.  
  10. =================================================================
  11.  
  12.  
  13.         ----- Introduction -----
  14.  
  15.     Welcome to Gyro!
  16.    
  17.     Packaged into a single .qc file, Gyro is designed for anybody
  18.     wishing to add some simple physics to their mods without getting
  19.     bogged down with code rewrites and lots of nasty maths. With just
  20.     a couple of extra lines of code, it's easy to have your rockets
  21.     deflected by explosions, have gibs float smoothly on the water
  22.     surface or, if you really want to, have your grenades hover above
  23.     the ground and repulse incoming nails!
  24.  
  25.     All of the processing is done transparently to existing code so,
  26.     more often than not, no changes need to made - only a few physics
  27.     initialisation routines need to be called and the rest just slots
  28.     into place!
  29.  
  30.  
  31.  
  32.         ----- Installation -----
  33.  
  34.     1.  Add "physics.qc" into your progs.src file, just between
  35.         "subs.qc" and "fight.qc".
  36.  
  37.     2.  In world.qc, find the worldspawn() function. You need
  38.         to add the line "P_StartPhysics();" somewhere in here.
  39.         I usually put it just after "W_Precache();", but it
  40.         shouldn't make any difference where you put it.
  41.  
  42.     3.  Before you can see any physics running, you need to run
  43.         one or more 'activation macros' on your entities. At the
  44.         very least, you must use "P_ActivatePhysics(targ, weight)"
  45.         on an entity, as this will declare it to be part of the
  46.         physics system. All the activation macros are given below.
  47.  
  48.     4.  With the P_* macros, you can get all sorts of effects,
  49.         such as bouyancy and thrust, but you'll still be missing
  50.         one important part of the system - the forces, such as
  51.         the shockwave of an explosion. Forces are typically just
  52.         a single line and integrate perfectly with physics-enabled
  53.         objects!
  54.  
  55.  
  56.  
  57.         ----- Physics Macros -----
  58.  
  59.     P_Deactivate(entity) =
  60.         Deactivates all physics on an entity.
  61.  
  62.  
  63.     P_ActivatePhysics(entity, float weight) =
  64.         Activates basic physics on and binds an entity to Gyro.
  65.         No other activations will take effect without this! The
  66.         weight value is given in units approximating grams, so
  67.         a grenade would weigh between about 500-1000 units. This
  68.         macro will also set air resistance, based on weight.
  69.  
  70.  
  71.     P_ActivateBouyancy(entity, float bouyancy) =
  72.         Bouyancy is how well an object will float in water and is
  73.         set in the same units as the weight. Basically, if the
  74.         bouyancy is less than the weight, the object will sink
  75.         and, if greater than the weight, the object will float.
  76.         Water resistance is also set, plus lava and slime will
  77.         behave differently.
  78.  
  79.  
  80.     P_ActivateAerodynamics(entity, float aerodynamics) =
  81.         An aerodynamic object will attempt to face the direction
  82.         it's travelling, which is handy for rockets and other
  83.         streamlined objects. A higher aerodynamics value (100+
  84.         is good for rockets) will make the object turn faster.
  85.  
  86.  
  87.     P_ActivateThrust(entity, float thrust) =
  88.         This makes an object constantly emit a thrust out of
  89.         it's back end, like the thrust on a rocket, for example.
  90.         The units pretty much equate to grams again, so a thrust
  91.         greater than the weight can keep an object airbourne.
  92.  
  93.  
  94.     P_ActivateHover(entity, float power, float range) =
  95.         Perhaps just a gimmick, a hovering object will be pushed
  96.         up and away from the ground. The range of the hover force
  97.         is given in standard Quake distance units while power is,
  98.         of course, given in the same units as weight. You might
  99.         need to experiment with this to get the results you want!
  100.  
  101.  
  102.     By passing an input of zero, these macros can also be used to
  103.     deactivate features. For added fun, you could even try passing
  104.     some negative values. Additionally, can set parameters manually if
  105.     you need to, say to negate air resistance on a thrust-less object.
  106.     Take a look at the entit fields in the code below to see what you
  107.     need!
  108.  
  109.  
  110.  
  111.         ----- Force Macros -----
  112.  
  113.     F_Deactive(entity) =
  114.         Removes all force effects from an object.
  115.  
  116.  
  117.     F_ActivateSphere(entity, float power, float range, float lifespan) =
  118.         A basic, yet useful, spherical force. This can be used for
  119.         explosions, gravity wells, repulsor shields, etc. The power
  120.         indicates the strength of the force, but doesn't (yet)
  121.         correspond to the standard weight units. Basically,
  122.         somewhere in the region of 200-300 is fine for an explosion.
  123.         The range gives the radius of the force, ands should be fairly
  124.         easy to figure out, while the lifespan determines how long
  125.         the force lasts. During the lifespan, the power of the force
  126.         will decay, unless the lifespan is set to zero or less, in
  127.         which case the force will remain, at full power, until
  128.         deactivated.
  129.  
  130.  
  131.     The above macros deal with adding a force to an entity, yet this isn't
  132.     always want you want. To create a stationary force in the air, replace
  133.     "Activate" with "Spawn" (eg. F_SpawnSphere) and give a position vector
  134.     rather than an entity. Be warned, though, that forces created in this
  135.     manner cannot be removed by hand, only by setting a lifespan!
  136.  
  137.  
  138.  
  139.         ----- Physics Feedback -----
  140.  
  141.     Occasionally, it's necessary for an object to know when physics are
  142.     being applied to it. Perhaps a nail needs to stop flying and start
  143.     bouncing when it gets caught in an explosion, or a rocket burns out
  144.     when it hits water? No problem, since Gyro lets you define two extra
  145.     entity voids: ".p_use_force" and ".p_use_water"
  146.  
  147.     These are called whenever an object is subjected to either water or
  148.     a force (like an explosion), and can be very handy for changing how
  149.     objects behave without needing to check for conditions yourself.
  150.  
  151.  
  152.  
  153.         ----- Hints and Tips -----
  154.  
  155.     - Remember that you can make negative forces, to suck things in
  156.     - Check out the modified weapons.qc to see how things work
  157.     - Use impulse 101 and 102 in the above mod to see something special
  158.     - Bouyancy combined with aerodynamics makes floating objects better
  159.     - Setting a thrust can keep deflected rockets moving properly
  160.     - New versions are on the way, with some fancy new forces
  161.     - Gyro can be plugged into even non-FPS mods
  162.  
  163.  
  164.  
  165.         ----- Known Bugs -----
  166.  
  167.     - Too many splashing noises on some engines
  168.     - Flying/floating objects can sometimes get stuck to floor
  169.     - Weight system not 100% perfect (bouyancy, etc)
  170.  
  171.  
  172.  
  173.         ----- Next Version -----
  174.  
  175.     - F_ActivateDampen (sphere, increases air resistance)
  176.     - F_ActivateTurbine (cyclic force, like a whirlwind)
  177.     - Turbulence, particularly to emulate waves in water
  178.     - More feedback control
  179.     - More macros
  180.  
  181.  
  182.  
  183.         ----- Copyright and Distribution -----
  184.  
  185.     Gyro is Copyright (C) 2005, Matthew Lawrence
  186.  
  187.     This program is free software; you can redistribute it and/or modify
  188.     it under the terms of the GNU General Public License as published by
  189.     the Free Software Foundation. Just let me know when you do!
  190.  
  191.     Thanks for reading!
  192.  
  193.  
  194.  
  195. =================================================================
  196.         WARNING: BAD CODING BEGINS NOW
  197. =================================================================
  198. */
  199.  
  200.  
  201.  
  202. /*
  203. =================================================================
  204. Physics Entity Fields and Constant Declarations
  205. =================================================================
  206. */
  207. .string f_enable;
  208. .float  f_type;
  209. .float  f_range;
  210. .float  f_power;
  211. .float  f_decay;
  212.  
  213. float   F_SPHERE    = 1;
  214.  
  215. .string p_enable;
  216. .float  p_weight;
  217. .float  p_thrust;
  218. .float  p_flags;
  219. .float  p_aero;
  220.  
  221. .float  p_bouy_air;
  222. .float  p_bouy_water;
  223. .float  p_bouy_slime;
  224. .float  p_bouy_lava;
  225.  
  226. .float  p_resist_air;
  227. .float  p_resist_water;
  228. .float  p_resist_slime;
  229. .float  p_resist_lava;
  230.  
  231. .float  p_hover_range;
  232. .float  p_hover_power;
  233.  
  234. .void() p_use_force;
  235. .void() p_use_water;
  236.  
  237. float   P_BOUYANT   = 1;
  238. float   P_AERODYNAMIC   = 2;
  239. float   P_THRUSTER  = 4;
  240. float   P_FLOATING  = 8;
  241. float   P_HOVER     = 16;
  242.  
  243.  
  244.  
  245. /*
  246. =================================================================
  247. Entity-Physics Initialisation Macros
  248. =================================================================
  249. */
  250. void(entity ent) P_Deactivate =
  251. {
  252.     ent.p_enable = "FALSE";
  253.     ent.p_weight = 0;
  254.     ent.p_thrust = 0;
  255.     ent.p_flags = 0;
  256.     ent.p_aero = 0;
  257.  
  258.     ent.p_bouy_air = 0;
  259.     ent.p_bouy_water = 0;
  260.     ent.p_bouy_slime = 0;
  261.     ent.p_bouy_lava = 0;
  262.  
  263.     ent.p_resist_air = 0;
  264.     ent.p_resist_water = 0;
  265.     ent.p_resist_slime = 0;
  266.     ent.p_resist_lava = 0;
  267.  
  268.     ent.p_hover_range = 0;
  269.     ent.p_hover_power = 0;
  270.  
  271.     ent.p_use_force = SUB_Null;
  272.     ent.p_use_water = SUB_Null;
  273. };
  274.  
  275.  
  276. void(entity ent, float weight) P_ActivatePhysics =
  277. {
  278.     if (weight == 0)
  279.     {
  280.         ent.p_enable = "FALSE";
  281.         return;
  282.     }
  283.  
  284.     ent.p_enable = "TRUE";
  285.     ent.p_weight = weight;
  286.  
  287.     ent.p_resist_air = 1.0 - (1.0 / (weight * 0.8));
  288.     ent.p_bouy_air = 0.0;
  289. };
  290.  
  291.  
  292. void(entity ent, float bouyancy) P_ActivateBouyancy =
  293. {
  294.     if (bouyancy == 0)
  295.     {
  296.         ent.p_flags = ent.p_flags - (ent.p_flags & P_BOUYANT);
  297.         return;
  298.     }
  299.  
  300.     ent.p_flags = (ent.p_flags - (ent.p_flags & P_BOUYANT)) + P_BOUYANT;
  301.  
  302.     ent.p_resist_water = 1.0 - (1.0 / (ent.p_weight * 0.028));
  303.     ent.p_resist_slime = 1.0 - (1.0 / (ent.p_weight * 0.026));
  304.     ent.p_resist_lava = 1.0 - (1.0 / (ent.p_weight * 0.016));
  305.  
  306.     ent.p_bouy_water = (bouyancy / ent.p_weight) * 40.0;
  307.     ent.p_bouy_slime = (bouyancy / ent.p_weight) * 46.0;
  308.     ent.p_bouy_lava = (bouyancy / ent.p_weight) * 54.0;
  309.  
  310.     if (ent.p_resist_water < 0.0)
  311.         ent.p_resist_water = 0.0;
  312.     if (ent.p_resist_slime < 0.0)
  313.         ent.p_resist_slime = 0.0;
  314.     if (ent.p_resist_lava < 0.0)
  315.         ent.p_resist_lava = 0.0;
  316. };
  317.  
  318.  
  319. void(entity ent, float aero) P_ActivateAerodynamics =
  320. {
  321.     if (aero == 0)
  322.     {
  323.         ent.p_flags = ent.p_flags - (ent.p_flags & P_AERODYNAMIC);
  324.         return;
  325.     }
  326.  
  327.     ent.p_flags = (ent.p_flags - (ent.p_flags & P_AERODYNAMIC)) + P_AERODYNAMIC;
  328.     ent.p_aero = aero * 0.001;
  329. };
  330.  
  331.  
  332. void(entity ent, float thrust) P_ActivateThrust =
  333. {
  334.     if (thrust == 0)
  335.     {
  336.         ent.p_flags = ent.p_flags - (ent.p_flags & P_THRUSTER);
  337.         return;
  338.     }
  339.  
  340.     ent.p_flags = (ent.p_flags - (ent.p_flags & P_THRUSTER)) + P_THRUSTER;
  341.     ent.p_thrust = (thrust / ent.p_weight) * 40.0;
  342. };
  343.  
  344.  
  345. void(entity ent, float power, float range) P_ActivateHover =
  346. {
  347.     if ((power == 0) || (range == 0))
  348.     {
  349.         ent.p_flags = ent.p_flags - (ent.p_flags & P_HOVER);
  350.         return;
  351.     }
  352.  
  353.     ent.p_flags = (ent.p_flags - (ent.p_flags & P_HOVER)) + P_HOVER;
  354.     ent.p_hover_power = (power / ent.p_weight) * 40.0;
  355.     ent.p_hover_range = range;
  356. };
  357.  
  358.  
  359.  
  360. /*
  361. =================================================================
  362. Force Creation Macros
  363. =================================================================
  364. */
  365. void(entity ent) F_Deactivate =
  366. {
  367.     ent.f_enable = "FALSE";
  368. };
  369.  
  370.  
  371. void(entity ent, float power, float range, float lifespan) F_ActivateSphere =
  372. {
  373.     ent.f_enable = "TRUE";
  374.     ent.f_type = F_SPHERE;
  375.     ent.f_range = range;
  376.     ent.f_power = power;
  377.     if (lifespan <= 0.0)
  378.         ent.f_decay = 0.0;
  379.     else
  380.         ent.f_decay = power / (lifespan * 20.0);
  381. };
  382.  
  383.  
  384. void(vector org, float power, float range, float lifespan) F_SpawnSphere =
  385. {
  386.     local entity    force;
  387.  
  388.     force = spawn();
  389.     force.origin = org;
  390.     force.think = SUB_Remove;
  391.     force.nextthink = time + lifespan;
  392.  
  393.     F_ActivateSphere(force, power, range, lifespan);
  394. };
  395.  
  396.  
  397.  
  398. /*
  399. =================================================================
  400. Force Application and Control
  401. =================================================================
  402. */
  403. void(entity targ) F_ApplySphere =
  404. {
  405.     if (self == targ)
  406.         return;
  407.  
  408.     local float dist, power;
  409.  
  410.     dist = vlen(targ.origin - self.origin);
  411.  
  412.     if (dist > self.f_range)
  413.         return;
  414.  
  415.     traceline (self.origin, targ.origin, FALSE, self);
  416.     if (trace_fraction != 1.0)
  417.         return;
  418.  
  419.     local entity    temp;
  420.     local vector    dir;
  421.  
  422.     dir = normalize(targ.origin - self.origin);
  423.     power = ((1.0 - (dist / self.f_range)) * self.f_power) / (targ.p_weight*0.001);
  424.  
  425.     targ.velocity = targ.velocity + (dir*power);
  426.  
  427.     if (targ.flags & FL_ONGROUND)
  428.     {
  429.         targ.flags = targ.flags - FL_ONGROUND;
  430.         targ.origin = targ.origin + '0 0 4';
  431.         if (power > 0)
  432.             targ.velocity_z = power;
  433.         else
  434.             targ.velocity_z = 0 - power;
  435.     }
  436.  
  437.     if (targ.p_use_force)
  438.     {
  439.         temp = self;
  440.         self = targ;
  441.         targ.p_use_force();
  442.         self = temp;
  443.     }
  444. };
  445.  
  446.  
  447.  
  448. /*
  449. =================================================================
  450. Basic Entity-Physics Control
  451. =================================================================
  452. */
  453. void() P_RunThrust =
  454. {
  455.     local vector    thrust;
  456.     makevectors(self.angles);
  457.  
  458.     //----- Correct Vector Pitch -----------------------
  459.     thrust = v_forward * self.p_thrust;
  460.     thrust_z = thrust_z * (-1);
  461.  
  462.     //----- Apply Thrust to Velocity -------------------
  463.     self.velocity = self.velocity + thrust;
  464. };
  465.  
  466.  
  467. void(vector targ, float mul, float damper) P_ApplyHoverForce =
  468. {
  469.     traceline(self.origin, targ, TRUE, self);
  470.  
  471.     if (trace_fraction == 1.0)
  472.         return;
  473.  
  474.     if (damper)
  475.         self.velocity_z = self.velocity_z * ((trace_fraction * 0.1) + 0.9);
  476.  
  477.     targ = normalize(self.origin - targ);
  478.     targ = (1-trace_fraction) * targ * self.p_hover_power * mul;
  479.     self.velocity = self.velocity + targ;
  480. };
  481.  
  482.  
  483. void() P_RunHover =
  484. {
  485.     local vector    offx, offy, offs;
  486.  
  487.     offx = '1 0 0' * (self.p_hover_range * 0.5);
  488.     offy = '0 1 0' * (self.p_hover_range * 0.5);
  489.     offs = self.origin - (self.p_hover_range * '0 0 1');
  490.  
  491.     P_ApplyHoverForce(offs, 0.2, TRUE);
  492.     P_ApplyHoverForce(offs + offx, 0.22, FALSE);
  493.     P_ApplyHoverForce(offs - offx, 0.22, FALSE);
  494.     P_ApplyHoverForce(offs + offy, 0.22, FALSE);
  495.     P_ApplyHoverForce(offs - offy, 0.22, FALSE);
  496. };
  497.  
  498.  
  499. void() P_RunAerodynamics =
  500. {
  501.     if (!self.velocity)
  502.         return;
  503.     local vector    moveangle, turnangle;
  504.     local float mul;
  505.  
  506.     //----- Get Motion Angles --------------------------
  507.     moveangle = vectoangles(self.velocity);
  508.  
  509.     //----- Find Velocity Influence --------------------
  510.     mul = vlen(self.velocity) * self.p_aero;
  511.     if (mul > 1.0)
  512.         mul = 1.0;
  513.  
  514.     //----- Check if Object is Floating ----------------
  515.     if (self.p_flags & P_FLOATING)
  516.     {
  517.         moveangle_x = 0.0;
  518.         mul = 0.4;
  519.     }
  520.  
  521.     //----- Compute Angular Difference -----------------
  522.     turnangle = moveangle - self.angles;
  523.  
  524.     //----- Bring into -180..180 Range -----------------
  525.     if (turnangle_x > 180)
  526.         turnangle_x = turnangle_x - 360;
  527.     else if (turnangle_x < -180)
  528.         turnangle_x = turnangle_x + 360;
  529.     if (turnangle_y > 180)
  530.         turnangle_y = turnangle_y - 360;
  531.     else if (turnangle_y < -180)
  532.         turnangle_y = turnangle_y + 360;
  533.     if (turnangle_z > 180)
  534.         turnangle_z = turnangle_z - 360;
  535.     else if (turnangle_z < -180)
  536.         turnangle_z = turnangle_z + 360;
  537.  
  538.     //----- Compute Angluar Velocity -------------------
  539.     turnangle = turnangle * mul;
  540.     self.avelocity = self.avelocity * (1 - self.p_aero);
  541.     self.avelocity = self.avelocity + turnangle;
  542. };
  543.  
  544.  
  545. void() P_RunMotion =
  546. {
  547.     local float conts, water, resist, bouyancy;
  548.     local vector    testpos;
  549.  
  550.     conts = pointcontents(self.origin);
  551.  
  552.     //----- No Water Behaviour -------------------------
  553.     if (!(self.p_flags & P_BOUYANT))
  554.         conts = CONTENT_EMPTY;
  555.  
  556.     //----- Retrieve Content Parameters ----------------
  557.     if (conts == CONTENT_WATER)
  558.     {
  559.         resist = self.p_resist_water;
  560.         bouyancy = self.p_bouy_water;
  561.         water = TRUE;
  562.     }
  563.     else if (conts == CONTENT_SLIME)
  564.     {
  565.         resist = self.p_resist_slime;
  566.         bouyancy = self.p_bouy_slime;
  567.         water = TRUE;
  568.     }
  569.     else if (conts == CONTENT_LAVA)
  570.     {
  571.         resist = self.p_resist_lava;
  572.         bouyancy = self.p_bouy_lava;
  573.         water = TRUE;
  574.     }
  575.     else
  576.     {
  577.         resist = self.p_resist_air;
  578.         bouyancy = self.p_bouy_air;
  579.     }
  580.  
  581.     //----- Velocity Dampening -------------------------
  582.     self.velocity = self.velocity * resist;
  583.     self.avelocity = self.avelocity * resist;
  584.  
  585.     //----- Bouyancy and Surface Floating --------------
  586.     if ((!water) || (pointcontents(self.origin + '0 0 2') == conts))
  587.     {
  588.         self.velocity_z = self.velocity_z + bouyancy;
  589.         if (pointcontents(self.origin + '0 0 6') == conts)
  590.             self.p_flags = self.p_flags - (self.p_flags & P_FLOATING);
  591.     }
  592.     else if ((self.velocity_z < 100.0) && (self.velocity_z > -100.0))
  593.     {
  594.         self.velocity_z = (self.velocity_z * 0.5) + 30;
  595.         self.p_flags = (self.p_flags - (self.p_flags & P_FLOATING)) + P_FLOATING;
  596.     }
  597.  
  598.     //----- Use 'Enter Water' Command ------------------
  599.     conts = pointcontents(self.origin);
  600.     if ((conts == CONTENT_WATER) || (conts == CONTENT_SLIME) || (conts == CONTENT_LAVA))
  601.     {
  602.         if (self.p_use_water)
  603.             self.p_use_water();
  604.     }
  605. };
  606.  
  607.  
  608.  
  609. /*
  610. =================================================================
  611. Per-Frame Physics Updates
  612. =================================================================
  613. */
  614. void() P_UpdatePhysics =
  615. {
  616.     local entity    head, oldself;
  617.     oldself = self;
  618.  
  619.     //----- Control Physics Entities ----------------------
  620.     self = find(world, p_enable, "TRUE");
  621.     while(self)
  622.     {
  623.         //----- Apply Rocket Thrust ------------------------
  624.         if (self.p_flags & P_THRUSTER)
  625.             P_RunThrust();
  626.  
  627.         //----- Apply Hover Forces -------------------------
  628.         if (self.p_flags & P_HOVER)
  629.             P_RunHover();
  630.  
  631.         //----- Rotate to Aerodynamic Angle ----------------
  632.         if (self.p_flags & P_AERODYNAMIC)
  633.             P_RunAerodynamics();
  634.  
  635.         //----- Resistance and Bouyancy --------------------
  636.         P_RunMotion();
  637.  
  638.         //----- Next Object --------------------------------
  639.         self = find(self, p_enable, "TRUE");
  640.     }
  641.  
  642.     //----- Control Force Entities ------------------------
  643.     self = find(world, f_enable, "TRUE");
  644.     while(self)
  645.     {
  646.         //----- Iterate Through Physics Objects ------------
  647.         head = find(world, p_enable, "TRUE");
  648.         while (head)
  649.         {
  650.             //----- Spherical Force Entities -------------------
  651.             if (self.f_type == F_SPHERE)
  652.                 F_ApplySphere(head);
  653.  
  654.             head = find(head, p_enable, "TRUE");
  655.         }
  656.  
  657.         //----- Age and Remove Forces ----------------------
  658.         self.f_power = self.f_power - self.f_decay;
  659.         if ((self.f_power > -0.1) && (self.f_power < 0.1))
  660.             F_Deactivate(self);
  661.  
  662.         self = find(self, f_enable, "TRUE");
  663.     }
  664.  
  665.     self = oldself;
  666.     self.nextthink = time + 0.05;
  667. };
  668.  
  669.  
  670.  
  671. /*
  672. =================================================================
  673. Creation of Physics Time-Controller
  674. =================================================================
  675. */
  676. void() P_StartPhysics =
  677. {
  678.     local entity    timer;
  679.  
  680.     timer = spawn();
  681.     timer.think = P_UpdatePhysics;
  682.     timer.nextthink = time + 0.05;
  683. };
  684.  
  685.  
  686.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement