Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- =================================================================
- Gyro - The QuakeC Physics Plugin
- Version 1.0
- By Quake Matt (rogermelon@yahoo.com)
- =================================================================
- ----- Introduction -----
- Welcome to Gyro!
- Packaged into a single .qc file, Gyro is designed for anybody
- wishing to add some simple physics to their mods without getting
- bogged down with code rewrites and lots of nasty maths. With just
- a couple of extra lines of code, it's easy to have your rockets
- deflected by explosions, have gibs float smoothly on the water
- surface or, if you really want to, have your grenades hover above
- the ground and repulse incoming nails!
- All of the processing is done transparently to existing code so,
- more often than not, no changes need to made - only a few physics
- initialisation routines need to be called and the rest just slots
- into place!
- ----- Installation -----
- 1. Add "physics.qc" into your progs.src file, just between
- "subs.qc" and "fight.qc".
- 2. In world.qc, find the worldspawn() function. You need
- to add the line "P_StartPhysics();" somewhere in here.
- I usually put it just after "W_Precache();", but it
- shouldn't make any difference where you put it.
- 3. Before you can see any physics running, you need to run
- one or more 'activation macros' on your entities. At the
- very least, you must use "P_ActivatePhysics(targ, weight)"
- on an entity, as this will declare it to be part of the
- physics system. All the activation macros are given below.
- 4. With the P_* macros, you can get all sorts of effects,
- such as bouyancy and thrust, but you'll still be missing
- one important part of the system - the forces, such as
- the shockwave of an explosion. Forces are typically just
- a single line and integrate perfectly with physics-enabled
- objects!
- ----- Physics Macros -----
- P_Deactivate(entity) =
- Deactivates all physics on an entity.
- P_ActivatePhysics(entity, float weight) =
- Activates basic physics on and binds an entity to Gyro.
- No other activations will take effect without this! The
- weight value is given in units approximating grams, so
- a grenade would weigh between about 500-1000 units. This
- macro will also set air resistance, based on weight.
- P_ActivateBouyancy(entity, float bouyancy) =
- Bouyancy is how well an object will float in water and is
- set in the same units as the weight. Basically, if the
- bouyancy is less than the weight, the object will sink
- and, if greater than the weight, the object will float.
- Water resistance is also set, plus lava and slime will
- behave differently.
- P_ActivateAerodynamics(entity, float aerodynamics) =
- An aerodynamic object will attempt to face the direction
- it's travelling, which is handy for rockets and other
- streamlined objects. A higher aerodynamics value (100+
- is good for rockets) will make the object turn faster.
- P_ActivateThrust(entity, float thrust) =
- This makes an object constantly emit a thrust out of
- it's back end, like the thrust on a rocket, for example.
- The units pretty much equate to grams again, so a thrust
- greater than the weight can keep an object airbourne.
- P_ActivateHover(entity, float power, float range) =
- Perhaps just a gimmick, a hovering object will be pushed
- up and away from the ground. The range of the hover force
- is given in standard Quake distance units while power is,
- of course, given in the same units as weight. You might
- need to experiment with this to get the results you want!
- By passing an input of zero, these macros can also be used to
- deactivate features. For added fun, you could even try passing
- some negative values. Additionally, can set parameters manually if
- you need to, say to negate air resistance on a thrust-less object.
- Take a look at the entit fields in the code below to see what you
- need!
- ----- Force Macros -----
- F_Deactive(entity) =
- Removes all force effects from an object.
- F_ActivateSphere(entity, float power, float range, float lifespan) =
- A basic, yet useful, spherical force. This can be used for
- explosions, gravity wells, repulsor shields, etc. The power
- indicates the strength of the force, but doesn't (yet)
- correspond to the standard weight units. Basically,
- somewhere in the region of 200-300 is fine for an explosion.
- The range gives the radius of the force, ands should be fairly
- easy to figure out, while the lifespan determines how long
- the force lasts. During the lifespan, the power of the force
- will decay, unless the lifespan is set to zero or less, in
- which case the force will remain, at full power, until
- deactivated.
- The above macros deal with adding a force to an entity, yet this isn't
- always want you want. To create a stationary force in the air, replace
- "Activate" with "Spawn" (eg. F_SpawnSphere) and give a position vector
- rather than an entity. Be warned, though, that forces created in this
- manner cannot be removed by hand, only by setting a lifespan!
- ----- Physics Feedback -----
- Occasionally, it's necessary for an object to know when physics are
- being applied to it. Perhaps a nail needs to stop flying and start
- bouncing when it gets caught in an explosion, or a rocket burns out
- when it hits water? No problem, since Gyro lets you define two extra
- entity voids: ".p_use_force" and ".p_use_water"
- These are called whenever an object is subjected to either water or
- a force (like an explosion), and can be very handy for changing how
- objects behave without needing to check for conditions yourself.
- ----- Hints and Tips -----
- - Remember that you can make negative forces, to suck things in
- - Check out the modified weapons.qc to see how things work
- - Use impulse 101 and 102 in the above mod to see something special
- - Bouyancy combined with aerodynamics makes floating objects better
- - Setting a thrust can keep deflected rockets moving properly
- - New versions are on the way, with some fancy new forces
- - Gyro can be plugged into even non-FPS mods
- ----- Known Bugs -----
- - Too many splashing noises on some engines
- - Flying/floating objects can sometimes get stuck to floor
- - Weight system not 100% perfect (bouyancy, etc)
- ----- Next Version -----
- - F_ActivateDampen (sphere, increases air resistance)
- - F_ActivateTurbine (cyclic force, like a whirlwind)
- - Turbulence, particularly to emulate waves in water
- - More feedback control
- - More macros
- ----- Copyright and Distribution -----
- Gyro is Copyright (C) 2005, Matthew Lawrence
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation. Just let me know when you do!
- Thanks for reading!
- =================================================================
- WARNING: BAD CODING BEGINS NOW
- =================================================================
- */
- /*
- =================================================================
- Physics Entity Fields and Constant Declarations
- =================================================================
- */
- .string f_enable;
- .float f_type;
- .float f_range;
- .float f_power;
- .float f_decay;
- float F_SPHERE = 1;
- .string p_enable;
- .float p_weight;
- .float p_thrust;
- .float p_flags;
- .float p_aero;
- .float p_bouy_air;
- .float p_bouy_water;
- .float p_bouy_slime;
- .float p_bouy_lava;
- .float p_resist_air;
- .float p_resist_water;
- .float p_resist_slime;
- .float p_resist_lava;
- .float p_hover_range;
- .float p_hover_power;
- .void() p_use_force;
- .void() p_use_water;
- float P_BOUYANT = 1;
- float P_AERODYNAMIC = 2;
- float P_THRUSTER = 4;
- float P_FLOATING = 8;
- float P_HOVER = 16;
- /*
- =================================================================
- Entity-Physics Initialisation Macros
- =================================================================
- */
- void(entity ent) P_Deactivate =
- {
- ent.p_enable = "FALSE";
- ent.p_weight = 0;
- ent.p_thrust = 0;
- ent.p_flags = 0;
- ent.p_aero = 0;
- ent.p_bouy_air = 0;
- ent.p_bouy_water = 0;
- ent.p_bouy_slime = 0;
- ent.p_bouy_lava = 0;
- ent.p_resist_air = 0;
- ent.p_resist_water = 0;
- ent.p_resist_slime = 0;
- ent.p_resist_lava = 0;
- ent.p_hover_range = 0;
- ent.p_hover_power = 0;
- ent.p_use_force = SUB_Null;
- ent.p_use_water = SUB_Null;
- };
- void(entity ent, float weight) P_ActivatePhysics =
- {
- if (weight == 0)
- {
- ent.p_enable = "FALSE";
- return;
- }
- ent.p_enable = "TRUE";
- ent.p_weight = weight;
- ent.p_resist_air = 1.0 - (1.0 / (weight * 0.8));
- ent.p_bouy_air = 0.0;
- };
- void(entity ent, float bouyancy) P_ActivateBouyancy =
- {
- if (bouyancy == 0)
- {
- ent.p_flags = ent.p_flags - (ent.p_flags & P_BOUYANT);
- return;
- }
- ent.p_flags = (ent.p_flags - (ent.p_flags & P_BOUYANT)) + P_BOUYANT;
- ent.p_resist_water = 1.0 - (1.0 / (ent.p_weight * 0.028));
- ent.p_resist_slime = 1.0 - (1.0 / (ent.p_weight * 0.026));
- ent.p_resist_lava = 1.0 - (1.0 / (ent.p_weight * 0.016));
- ent.p_bouy_water = (bouyancy / ent.p_weight) * 40.0;
- ent.p_bouy_slime = (bouyancy / ent.p_weight) * 46.0;
- ent.p_bouy_lava = (bouyancy / ent.p_weight) * 54.0;
- if (ent.p_resist_water < 0.0)
- ent.p_resist_water = 0.0;
- if (ent.p_resist_slime < 0.0)
- ent.p_resist_slime = 0.0;
- if (ent.p_resist_lava < 0.0)
- ent.p_resist_lava = 0.0;
- };
- void(entity ent, float aero) P_ActivateAerodynamics =
- {
- if (aero == 0)
- {
- ent.p_flags = ent.p_flags - (ent.p_flags & P_AERODYNAMIC);
- return;
- }
- ent.p_flags = (ent.p_flags - (ent.p_flags & P_AERODYNAMIC)) + P_AERODYNAMIC;
- ent.p_aero = aero * 0.001;
- };
- void(entity ent, float thrust) P_ActivateThrust =
- {
- if (thrust == 0)
- {
- ent.p_flags = ent.p_flags - (ent.p_flags & P_THRUSTER);
- return;
- }
- ent.p_flags = (ent.p_flags - (ent.p_flags & P_THRUSTER)) + P_THRUSTER;
- ent.p_thrust = (thrust / ent.p_weight) * 40.0;
- };
- void(entity ent, float power, float range) P_ActivateHover =
- {
- if ((power == 0) || (range == 0))
- {
- ent.p_flags = ent.p_flags - (ent.p_flags & P_HOVER);
- return;
- }
- ent.p_flags = (ent.p_flags - (ent.p_flags & P_HOVER)) + P_HOVER;
- ent.p_hover_power = (power / ent.p_weight) * 40.0;
- ent.p_hover_range = range;
- };
- /*
- =================================================================
- Force Creation Macros
- =================================================================
- */
- void(entity ent) F_Deactivate =
- {
- ent.f_enable = "FALSE";
- };
- void(entity ent, float power, float range, float lifespan) F_ActivateSphere =
- {
- ent.f_enable = "TRUE";
- ent.f_type = F_SPHERE;
- ent.f_range = range;
- ent.f_power = power;
- if (lifespan <= 0.0)
- ent.f_decay = 0.0;
- else
- ent.f_decay = power / (lifespan * 20.0);
- };
- void(vector org, float power, float range, float lifespan) F_SpawnSphere =
- {
- local entity force;
- force = spawn();
- force.origin = org;
- force.think = SUB_Remove;
- force.nextthink = time + lifespan;
- F_ActivateSphere(force, power, range, lifespan);
- };
- /*
- =================================================================
- Force Application and Control
- =================================================================
- */
- void(entity targ) F_ApplySphere =
- {
- if (self == targ)
- return;
- local float dist, power;
- dist = vlen(targ.origin - self.origin);
- if (dist > self.f_range)
- return;
- traceline (self.origin, targ.origin, FALSE, self);
- if (trace_fraction != 1.0)
- return;
- local entity temp;
- local vector dir;
- dir = normalize(targ.origin - self.origin);
- power = ((1.0 - (dist / self.f_range)) * self.f_power) / (targ.p_weight*0.001);
- targ.velocity = targ.velocity + (dir*power);
- if (targ.flags & FL_ONGROUND)
- {
- targ.flags = targ.flags - FL_ONGROUND;
- targ.origin = targ.origin + '0 0 4';
- if (power > 0)
- targ.velocity_z = power;
- else
- targ.velocity_z = 0 - power;
- }
- if (targ.p_use_force)
- {
- temp = self;
- self = targ;
- targ.p_use_force();
- self = temp;
- }
- };
- /*
- =================================================================
- Basic Entity-Physics Control
- =================================================================
- */
- void() P_RunThrust =
- {
- local vector thrust;
- makevectors(self.angles);
- //----- Correct Vector Pitch -----------------------
- thrust = v_forward * self.p_thrust;
- thrust_z = thrust_z * (-1);
- //----- Apply Thrust to Velocity -------------------
- self.velocity = self.velocity + thrust;
- };
- void(vector targ, float mul, float damper) P_ApplyHoverForce =
- {
- traceline(self.origin, targ, TRUE, self);
- if (trace_fraction == 1.0)
- return;
- if (damper)
- self.velocity_z = self.velocity_z * ((trace_fraction * 0.1) + 0.9);
- targ = normalize(self.origin - targ);
- targ = (1-trace_fraction) * targ * self.p_hover_power * mul;
- self.velocity = self.velocity + targ;
- };
- void() P_RunHover =
- {
- local vector offx, offy, offs;
- offx = '1 0 0' * (self.p_hover_range * 0.5);
- offy = '0 1 0' * (self.p_hover_range * 0.5);
- offs = self.origin - (self.p_hover_range * '0 0 1');
- P_ApplyHoverForce(offs, 0.2, TRUE);
- P_ApplyHoverForce(offs + offx, 0.22, FALSE);
- P_ApplyHoverForce(offs - offx, 0.22, FALSE);
- P_ApplyHoverForce(offs + offy, 0.22, FALSE);
- P_ApplyHoverForce(offs - offy, 0.22, FALSE);
- };
- void() P_RunAerodynamics =
- {
- if (!self.velocity)
- return;
- local vector moveangle, turnangle;
- local float mul;
- //----- Get Motion Angles --------------------------
- moveangle = vectoangles(self.velocity);
- //----- Find Velocity Influence --------------------
- mul = vlen(self.velocity) * self.p_aero;
- if (mul > 1.0)
- mul = 1.0;
- //----- Check if Object is Floating ----------------
- if (self.p_flags & P_FLOATING)
- {
- moveangle_x = 0.0;
- mul = 0.4;
- }
- //----- Compute Angular Difference -----------------
- turnangle = moveangle - self.angles;
- //----- Bring into -180..180 Range -----------------
- if (turnangle_x > 180)
- turnangle_x = turnangle_x - 360;
- else if (turnangle_x < -180)
- turnangle_x = turnangle_x + 360;
- if (turnangle_y > 180)
- turnangle_y = turnangle_y - 360;
- else if (turnangle_y < -180)
- turnangle_y = turnangle_y + 360;
- if (turnangle_z > 180)
- turnangle_z = turnangle_z - 360;
- else if (turnangle_z < -180)
- turnangle_z = turnangle_z + 360;
- //----- Compute Angluar Velocity -------------------
- turnangle = turnangle * mul;
- self.avelocity = self.avelocity * (1 - self.p_aero);
- self.avelocity = self.avelocity + turnangle;
- };
- void() P_RunMotion =
- {
- local float conts, water, resist, bouyancy;
- local vector testpos;
- conts = pointcontents(self.origin);
- //----- No Water Behaviour -------------------------
- if (!(self.p_flags & P_BOUYANT))
- conts = CONTENT_EMPTY;
- //----- Retrieve Content Parameters ----------------
- if (conts == CONTENT_WATER)
- {
- resist = self.p_resist_water;
- bouyancy = self.p_bouy_water;
- water = TRUE;
- }
- else if (conts == CONTENT_SLIME)
- {
- resist = self.p_resist_slime;
- bouyancy = self.p_bouy_slime;
- water = TRUE;
- }
- else if (conts == CONTENT_LAVA)
- {
- resist = self.p_resist_lava;
- bouyancy = self.p_bouy_lava;
- water = TRUE;
- }
- else
- {
- resist = self.p_resist_air;
- bouyancy = self.p_bouy_air;
- }
- //----- Velocity Dampening -------------------------
- self.velocity = self.velocity * resist;
- self.avelocity = self.avelocity * resist;
- //----- Bouyancy and Surface Floating --------------
- if ((!water) || (pointcontents(self.origin + '0 0 2') == conts))
- {
- self.velocity_z = self.velocity_z + bouyancy;
- if (pointcontents(self.origin + '0 0 6') == conts)
- self.p_flags = self.p_flags - (self.p_flags & P_FLOATING);
- }
- else if ((self.velocity_z < 100.0) && (self.velocity_z > -100.0))
- {
- self.velocity_z = (self.velocity_z * 0.5) + 30;
- self.p_flags = (self.p_flags - (self.p_flags & P_FLOATING)) + P_FLOATING;
- }
- //----- Use 'Enter Water' Command ------------------
- conts = pointcontents(self.origin);
- if ((conts == CONTENT_WATER) || (conts == CONTENT_SLIME) || (conts == CONTENT_LAVA))
- {
- if (self.p_use_water)
- self.p_use_water();
- }
- };
- /*
- =================================================================
- Per-Frame Physics Updates
- =================================================================
- */
- void() P_UpdatePhysics =
- {
- local entity head, oldself;
- oldself = self;
- //----- Control Physics Entities ----------------------
- self = find(world, p_enable, "TRUE");
- while(self)
- {
- //----- Apply Rocket Thrust ------------------------
- if (self.p_flags & P_THRUSTER)
- P_RunThrust();
- //----- Apply Hover Forces -------------------------
- if (self.p_flags & P_HOVER)
- P_RunHover();
- //----- Rotate to Aerodynamic Angle ----------------
- if (self.p_flags & P_AERODYNAMIC)
- P_RunAerodynamics();
- //----- Resistance and Bouyancy --------------------
- P_RunMotion();
- //----- Next Object --------------------------------
- self = find(self, p_enable, "TRUE");
- }
- //----- Control Force Entities ------------------------
- self = find(world, f_enable, "TRUE");
- while(self)
- {
- //----- Iterate Through Physics Objects ------------
- head = find(world, p_enable, "TRUE");
- while (head)
- {
- //----- Spherical Force Entities -------------------
- if (self.f_type == F_SPHERE)
- F_ApplySphere(head);
- head = find(head, p_enable, "TRUE");
- }
- //----- Age and Remove Forces ----------------------
- self.f_power = self.f_power - self.f_decay;
- if ((self.f_power > -0.1) && (self.f_power < 0.1))
- F_Deactivate(self);
- self = find(self, f_enable, "TRUE");
- }
- self = oldself;
- self.nextthink = time + 0.05;
- };
- /*
- =================================================================
- Creation of Physics Time-Controller
- =================================================================
- */
- void() P_StartPhysics =
- {
- local entity timer;
- timer = spawn();
- timer.think = P_UpdatePhysics;
- timer.nextthink = time + 0.05;
- };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement