View previous topic :: View next topic |
Author |
Message |
avirox
Joined: 16 Aug 2006 Posts: 109
|
Posted: Fri Jan 01, 2010 8:54 pm Post subject: Tutorial: Rotating Brush Models for QuakeWorld |
|
|
Have you ever wondered how to get entities like this:
.. to become like THIS:
No? Well neither have I until now!
Here is a little tutorial on implementing rotating brush support to QuakeWorld. What are rotating brush models? Well, they're basically things like spinning fans, rotating trains and rotating doors. Basically the stuff you see in quake 2/half-life/every game made after those two. Interestingly, most of this functionality is actually already present within winquake. However, quakeworld lacks the quake 2 references that WQ has, and also QW player traces needs to be accounted for.
First I'd like to credit the sources for this code. Namely: id software, MrG, LordHavoc, Spike, and the little leprechaun that sits on my shoulder and tells me to burn things.
Begin the beguine
Open up sv_phys.c and prepare to make it your bitch. Find SV_Physics_Pusher and add the following function right above it:
Code: |
/*
============
SV_PushRotate
============
*/
void SV_PushRotate (edict_t *pusher, float movetime)
{
int i, e;
edict_t *check, *block;
vec3_t move, a, amove;
vec3_t entorig, pushorig;
int num_moved;
edict_t *moved_edict[MAX_EDICTS];
vec3_t moved_from[MAX_EDICTS];
vec3_t org, org2;
vec3_t forward, right, up;
if (!pusher->v.avelocity[0] && !pusher->v.avelocity[1] && !pusher->v.avelocity[2])
{
pusher->v.ltime += movetime;
return;
}
for (i=0 ; i<3 ; i++)
amove[i] = pusher->v.avelocity[i] * movetime;
VectorSubtract (vec3_origin, amove, a);
AngleVectors (a, forward, right, up);
VectorCopy (pusher->v.angles, pushorig);
// move the pusher to it's final position
VectorAdd (pusher->v.angles, amove, pusher->v.angles);
pusher->v.ltime += movetime;
SV_LinkEdict (pusher, false);
// see if any solid entities are inside the final position
num_moved = 0;
check = NEXT_EDICT(sv.edicts);
for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))
{
if (check->free)
continue;
if (check->v.movetype == MOVETYPE_PUSH
|| check->v.movetype == MOVETYPE_NONE
|| check->v.movetype == MOVETYPE_FOLLOW
|| check->v.movetype == MOVETYPE_NOCLIP)
continue;
// if the entity is standing on the pusher, it will definately be moved
if ( ! ( ((int)check->v.flags & FL_ONGROUND)
&& PROG_TO_EDICT(check->v.groundentity) == pusher) )
{
if ( check->v.absmin[0] >= pusher->v.absmax[0]
|| check->v.absmin[1] >= pusher->v.absmax[1]
|| check->v.absmin[2] >= pusher->v.absmax[2]
|| check->v.absmax[0] <= pusher->v.absmin[0]
|| check->v.absmax[1] <= pusher->v.absmin[1]
|| check->v.absmax[2] <= pusher->v.absmin[2] )
continue;
// see if the ent's bbox is inside the pusher's final position
if (!SV_TestEntityPosition (check))
continue;
}
// remove the onground flag for non-players
if (check->v.movetype != MOVETYPE_WALK)
check->v.flags = (int)check->v.flags & ~FL_ONGROUND;
VectorCopy (check->v.origin, entorig);
VectorCopy (check->v.origin, moved_from[num_moved]);
moved_edict[num_moved] = check;
num_moved++;
// calculate destination position
VectorSubtract (check->v.origin, pusher->v.origin, org);
org2[0] = DotProduct (org, forward);
org2[1] = -DotProduct (org, right);
org2[2] = DotProduct (org, up);
VectorSubtract (org2, org, move);
// try moving the contacted entity
pusher->v.solid = SOLID_NOT;
SV_PushEntity (check, move);
pusher->v.solid = SOLID_BSP;
// if it is still inside the pusher, block
block = SV_TestEntityPosition (check);
if (block)
{ // fail the move
if (check->v.mins[0] == check->v.maxs[0])
continue;
if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)
{ // corpse
check->v.mins[0] = check->v.mins[1] = 0;
VectorCopy (check->v.mins, check->v.maxs);
continue;
}
VectorCopy (entorig, check->v.origin);
SV_LinkEdict (check, true);
VectorCopy (pushorig, pusher->v.angles);
SV_LinkEdict (pusher, false);
pusher->v.ltime -= movetime;
// if the pusher has a "blocked" function, call it
// otherwise, just stay in place until the obstacle is gone
if (pusher->v.blocked)
{
pr_global_struct->self = EDICT_TO_PROG(pusher);
pr_global_struct->other = EDICT_TO_PROG(check);
PR_ExecuteProgram (pusher->v.blocked);
}
// move back any entities we already moved
for (i=0 ; i<num_moved ; i++)
{
VectorCopy (moved_from[i], moved_edict[i]->v.origin);
VectorSubtract (moved_edict[i]->v.angles, amove, moved_edict[i]->v.angles);
SV_LinkEdict (moved_edict[i], false);
}
return;
}
else
{
VectorAdd (check->v.angles, amove, check->v.angles);
}
}
}
|
Now we must edit SV_Physics_Pusher. Compare your SV_Physics_Pusher function with the one below, and add the code in //ROTATE START and //ROTATE END to yours (PS. in some engines it may be possible to just replace your whole function altogether with the one below):
Code: |
void SV_Physics_Pusher (edict_t *ent)
{
float thinktime;
float oldltime;
float movetime;
oldltime = ent->v.ltime;
thinktime = ent->v.nextthink;
if (thinktime < ent->v.ltime + sv_frametime)
{
movetime = thinktime - ent->v.ltime;
if (movetime < 0)
movetime = 0;
}
else
movetime = sv_frametime;
if (movetime)
{
//ROTATE START
if (ent->v.avelocity[0] || ent->v.avelocity[1] || ent->v.avelocity[2])
SV_PushRotate (ent, sv_frametime);
else
//ROTATE END
SV_PushMove (ent, movetime); // advances ent->v.ltime if not blocked
}
if (thinktime > oldltime && thinktime <= ent->v.ltime)
{
ent->v.nextthink = 0;
pr_global_struct->time = sv.time;
pr_global_struct->self = EDICT_TO_PROG(ent);
pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
PR_ExecuteProgram (ent->v.think);
if (ent->free)
return;
}
}
|
We're done with that file. Now on to world.c
Go to SV_LinkEdict and edit it thusly (again, look at //ROTATE START and //ROTATE END references):
Code: |
void SV_LinkEdict (edict_t *ent, qbool touch_triggers)
{
areanode_t *node;
if (ent->area.prev)
SV_UnlinkEdict (ent); // unlink from old position
if (ent == sv.edicts)
return; // don't add the world
if (ent->free)
return;
// set the abs box
// ROTATE START
if (ent->v.solid == SOLID_BSP &&
(ent->v.angles[0] || ent->v.angles[1] || ent->v.angles[2]) )
{ // expand for rotation
float max, v;
int i;
max = DotProduct(ent->v.mins, ent->v.mins);
v = DotProduct(ent->v.maxs, ent->v.maxs);
if (max < v)
max = v;
max = sqrt(max);
for (i=0 ; i<3 ; i++)
{
ent->v.absmin[i] = ent->v.origin[i] - max;
ent->v.absmax[i] = ent->v.origin[i] + max;
}
}
else
// ROTATE END
{
VectorAdd (ent->v.origin, ent->v.mins, ent->v.absmin);
VectorAdd (ent->v.origin, ent->v.maxs, ent->v.absmax);
}
//
// to make items easier to pick up and allow them to be grabbed off
// of shelves, the abs sizes are expanded
//
if ((int)ent->v.flags & FL_ITEM)
{
ent->v.absmin[0] -= 15;
ent->v.absmin[1] -= 15;
ent->v.absmax[0] += 15;
ent->v.absmax[1] += 15;
}
else
{ // because movement is clipped an epsilon away from an actual edge,
// we must fully check even when bounding boxes don't quite touch
ent->v.absmin[0] -= 1;
ent->v.absmin[1] -= 1;
ent->v.absmin[2] -= 1;
ent->v.absmax[0] += 1;
ent->v.absmax[1] += 1;
ent->v.absmax[2] += 1;
}
// link to PVS leafs
if (ent->v.modelindex)
SV_LinkToLeafs (ent);
else
ent->num_leafs = 0;
if (ent->v.solid == SOLID_NOT)
return;
// find the first node that the ent's box crosses
node = sv_areanodes;
while (1)
{
if (node->axis == -1)
break;
if (ent->v.absmin[node->axis] > node->dist)
node = node->children[0];
else if (ent->v.absmax[node->axis] < node->dist)
node = node->children[1];
else
break; // crosses the node
}
// link it in
if (ent->v.solid == SOLID_TRIGGER)
InsertLinkBefore (&ent->area, &node->trigger_edicts);
else
InsertLinkBefore (&ent->area, &node->solid_edicts);
// if touch_triggers, touch all entities at this node and decend for more
if (touch_triggers)
SV_TouchLinks ( ent, sv_areanodes );
}
|
Next in world.c we need SV_ClipMoveToEntity. Find it and change it to look like the following:
Code: |
trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end)
{
trace_t trace;
vec3_t offset;
vec3_t start_l, end_l;
hull_t *hull;
// fill in a default trace
memset (&trace, 0, sizeof(trace_t));
trace.fraction = 1;
trace.allsolid = true;
VectorCopy (end, trace.endpos);
// get the clipping hull
hull = SV_HullForEntity (ent, mins, maxs, offset);
VectorSubtract (start, offset, start_l);
VectorSubtract (end, offset, end_l);
// ROTATE START
// rotate start and end into the models frame of reference
if (ent->v.solid == SOLID_BSP &&
(ent->v.angles[0] || ent->v.angles[1] || ent->v.angles[2]) )
{
vec3_t a;
vec3_t forward, right, up;
vec3_t temp;
AngleVectors (ent->v.angles, forward, right, up);
VectorCopy (start_l, temp);
start_l[0] = DotProduct (temp, forward);
start_l[1] = -DotProduct (temp, right);
start_l[2] = DotProduct (temp, up);
VectorCopy (end_l, temp);
end_l[0] = DotProduct (temp, forward);
end_l[1] = -DotProduct (temp, right);
end_l[2] = DotProduct (temp, up);
}
// ROTATE END
// trace a line through the apropriate clipping hull
//SV_RecursiveHullCheck (hull, hull->firstclipnode, 0, 1, start_l, end_l, &trace);
if (ent->v.solid != SOLID_BSP)
{
ent->v.angles[0]*=-1; //carmack made bsp models rotate wrongly.
trace = CM_HullTrace (hull, start_l, end_l);
ent->v.angles[0]*=-1;
}
else
trace = CM_HullTrace (hull, start_l, end_l);
// ROTATE START
// rotate endpos back to world frame of reference
if (ent->v.solid == SOLID_BSP &&
(ent->v.angles[0] || ent->v.angles[1] || ent->v.angles[2]) )
{
vec3_t a;
vec3_t forward, right, up;
vec3_t temp;
if (trace.fraction != 1)
{
VectorSubtract (vec3_origin, ent->v.angles, a);
AngleVectors (a, forward, right, up);
VectorCopy (trace.endpos, temp);
trace.endpos[0] = DotProduct (temp, forward);
trace.endpos[1] = -DotProduct (temp, right);
trace.endpos[2] = DotProduct (temp, up);
VectorCopy (trace.plane.normal, temp);
trace.plane.normal[0] = DotProduct (temp, forward);
trace.plane.normal[1] = -DotProduct (temp, right);
trace.plane.normal[2] = DotProduct (temp, up);
}
}
// ROTATE END
// fix trace up by the offset
VectorAdd (trace.endpos, offset, trace.endpos);
// did we clip the move?
if (trace.fraction < 1 || trace.startsolid )
trace.e.ent = ent;
return trace;
}
|
Lets add some ints to the physent_t struct. Add these two if they are not already present in the struct:
Code: |
vec3_t angles;
int solid; // xavior hax
|
Now we need to work on player collision. Go to the function AddLinksToPmove in sv_user.c and add the following lines in the if (check->v.solid == SOLID_BSP) { } segment:
Code: |
VectorCopy (check->v.angles, pe->angles); // for rot brushes
pe->solid = SOLID_BSP;
|
Finally we must fix up the player trace. Find PM_PlayerTrace and edit it accordingly:
Code: |
trace_t PM_PlayerTrace (vec3_t start, vec3_t end)
{
trace_t trace, total;
vec3_t offset;
vec3_t start_l, end_l;
hull_t *hull;
int i;
physent_t *pe;
vec3_t mins, maxs, tracemins, tracemaxs;
// fill in a default trace
memset (&total, 0, sizeof(trace_t));
total.fraction = 1;
total.e.entnum = -1;
VectorCopy (end, total.endpos);
PM_TraceBounds(start, end, tracemins, tracemaxs);
for (i=0 ; i< pmove.numphysent ; i++)
{
pe = &pmove.physents[i];
// get the clipping hull
if (pe->model)
{
if (sv_client->is_crouching == 1)
hull = &pmove.physents[i].model->hulls[3];
else
hull = &pmove.physents[i].model->hulls[1];
//if (i > 0 && PM_CullTraceBox(tracemins, tracemaxs, pe->origin, pe->model->mins, pe->model->maxs, hull->clip_mins, hull->clip_maxs))
// continue;
VectorSubtract (hull->clip_mins, player_mins, offset);
VectorAdd (offset, pe->origin, offset);
}
else
{
VectorSubtract (pe->mins, player_maxs, mins);
VectorSubtract (pe->maxs, player_mins, maxs);
if (PM_CullTraceBox(tracemins, tracemaxs, pe->origin, mins, maxs, vec3_origin, vec3_origin))
continue;
hull = CM_HullForBox (mins, maxs);
VectorCopy (pe->origin, offset);
}
VectorSubtract (start, offset, start_l);
VectorSubtract (end, offset, end_l);
// ROTATE START
// rotate start and end into the models frame of reference
if (pe->solid == SOLID_BSP &&
(pe->angles[0] || pe->angles[1] || pe->angles[2]) )
{
vec3_t a;
vec3_t forward, right, up;
vec3_t temp;
AngleVectors (pe->angles, forward, right, up);
VectorCopy (start_l, temp);
start_l[0] = DotProduct (temp, forward);
start_l[1] = -DotProduct (temp, right);
start_l[2] = DotProduct (temp, up);
VectorCopy (end_l, temp);
end_l[0] = DotProduct (temp, forward);
end_l[1] = -DotProduct (temp, right);
end_l[2] = DotProduct (temp, up);
}
// ROTATE END
// trace a line through the apropriate clipping hull
trace = CM_HullTrace (hull, start_l, end_l);
// ROTATE START
// rotate endpos back to world frame of reference
if (pe->solid == SOLID_BSP &&
(pe->angles[0] || pe->angles[1] || pe->angles[2]) )
{
vec3_t a;
vec3_t forward, right, up;
vec3_t temp;
if (trace.fraction != 1)
{
VectorSubtract (vec3_origin, pe->angles, a);
AngleVectors (a, forward, right, up);
VectorCopy (trace.endpos, temp);
trace.endpos[0] = DotProduct (temp, forward);
trace.endpos[1] = -DotProduct (temp, right);
trace.endpos[2] = DotProduct (temp, up);
VectorCopy (trace.plane.normal, temp);
trace.plane.normal[0] = DotProduct (temp, forward);
trace.plane.normal[1] = -DotProduct (temp, right);
trace.plane.normal[2] = DotProduct (temp, up);
}
}
// ROTATE END
// fix trace up by the offset
VectorAdd (trace.endpos, offset, trace.endpos);
if (trace.allsolid)
trace.startsolid = true;
if (trace.startsolid)
trace.fraction = 0;
// did we clip the move?
if (trace.fraction < total.fraction)
{
total = trace;
total.e.entnum = i;
}
}
return total;
}
|
And that's it! You should now have functional rotating brush support in your quakeworld server. If you want to make a test in your QC mod, follow the one at the bottom of this page. Feel free to leave comments/suggestions/death threats. If there is something that's not compiling, also let me know!
Enjoy, and happy new year! |
|
Back to top |
|
 |
Baker

Joined: 14 Mar 2006 Posts: 1538
|
Posted: Fri Jan 01, 2010 9:37 pm Post subject: Re: Tutorial: Rotating Brush Models for QuakeWorld |
|
|
Thanks!
Btw, your "modified FuhQuake" has vwep and alpha textures support right?
Future QW tutorial wish list: Animation interpolation tutorial for Quakeworld"(ezQuake has this feature, correct?)
After reading tutorials like this, part of me wants to focus on ripping and borrowing from your modified FuhQuake and ezQuake and up-strength the ZQuake engine's capabilities into a "clean total conversion oriented" all purpose Quake engine. |
|
Back to top |
|
 |
avirox
Joined: 16 Aug 2006 Posts: 109
|
Posted: Sat Jan 02, 2010 10:47 pm Post subject: |
|
|
FuhQuake has interpolation similar to ezquake actually, but it's only applied to specified models (hard-coded, in fact. Why this is, I'm still not sure. I suppose one day I'll modify it to support everything and see how it looks.. |
|
Back to top |
|
 |
frag.machine

Joined: 25 Nov 2006 Posts: 728
|
|
Back to top |
|
 |
goldenboy

Joined: 05 Sep 2008 Posts: 310 Location: Kiel
|
Posted: Sat Jan 02, 2010 11:50 pm Post subject: |
|
|
Quote: | And that's it! You should now have functional rotating brush support in your quakeworld server. If you want to make a test in your QC mod, follow the one at the bottom of this page. Feel free to leave comments/suggestions/death threats. If there is something that's not compiling, also let me know! |
Which engines support this? I assume FTE should support self.avelocity_(x,y,z) based rotation right?
I put this
Code: | void() func_rotating =
{
self.solid = SOLID_BSP;
self.movetype = MOVETYPE_PUSH;
setorigin (self, self.origin);
setmodel (self, self.model);
self.classname = "func_rotating";
setsize (self, self.mins, self.maxs);
if (!self.speed)
self.speed = 100;
if (self.spawnflags & 2) // reverse direction
self.speed = 0 - self.speed;
if (self.spawnflags & 64) // not solid
self.solid = SOLID_NOT;
if (self.spawnflags & 4)
{
self.avelocity_z = self.speed;
self.avelocity_x = 0;
self.avelocity_y = 0;
}
else if (self.spawnflags & 8)
{
self.avelocity_z = 0;
self.avelocity_x = self.speed;
self.avelocity_y = 0;
}
else
{
self.avelocity_z = 0;
self.avelocity_x = 0;
self.avelocity_y = self.speed;
}
}; |
into RMQ, and then I made a testmap with a func_rotating.
I then set the entity's "origin" to the bmodel's origin.
Tried the map in darkplaces and FTE - the bmodel was nowhere to be found, not even when I noclipped around.
Next, I moved the whole map so the func_rotating was centered at 0 0 0. I tried both setting "origin" to that, and settig no origin key.
The brush appeared in the map now, but wasn't rotating.
No spawnflags set.
This whole shit is SO frustrating. I've tried this a number of times now, first with the rotating door code from Quake Life, now with the simple func_rotating code from the tutorial, and NOTHING WORKS.
Edit: Closer investigation reveals that FTE doesn't have this code. Hmm, OK.
A case for a new standard... _________________ ReMakeQuake
The Realm of Blog Magic |
|
Back to top |
|
 |
avirox
Joined: 16 Aug 2006 Posts: 109
|
Posted: Sun Jan 03, 2010 12:35 am Post subject: |
|
|
FTE has rotating brush ents, actually, but it looks different in code Also, you need to compile your map's rotating entity with an origin brush. |
|
Back to top |
|
 |
Spike
Joined: 05 Nov 2004 Posts: 944 Location: UK
|
Posted: Sun Jan 03, 2010 1:56 am Post subject: |
|
|
velocity and thus avelocity only work on MOVETYPE_PUSH entities if they have a valid nextthink. _________________ What's a signature? |
|
Back to top |
|
 |
goldenboy

Joined: 05 Sep 2008 Posts: 310 Location: Kiel
|
Posted: Sun Jan 03, 2010 2:37 am Post subject: |
|
|
Spike wrote: | velocity and thus avelocity only work on MOVETYPE_PUSH entities if they have a valid nextthink. |
OK. That seems to do something
Code: | self.nextthink = time; |
and it's rotating, yay - although DP dumps me back in the console with "QC function self.think is missing", which is kinda logical -
It works when I just point self.think at func_rotating. There must be a better way though...
And I just noticed that what I have now rotates in DP, but not in FTE :-/ aaargh.
xavior, there are no Q1 map compilers that support origin brushes, so I just put "origin" "x y z" manually in the map editor. That seems a little weird, too, because what I get in the engine is something else (64 units lower) than what I get in the editor...
Anyway, the qc from the quakesrc.org tutorial does not work - it works in DP when I add
Code: | self.think = func_rotating;
self.nextthink = time; |
but not in FTE.
Example code for a func_rotating that works in DP and FTE would be much appreciated. _________________ ReMakeQuake
The Realm of Blog Magic
Last edited by goldenboy on Sun Jan 03, 2010 3:05 am; edited 1 time in total |
|
Back to top |
|
 |
Baker

Joined: 14 Mar 2006 Posts: 1538
|
Posted: Sun Jan 03, 2010 2:45 am Post subject: |
|
|
2 questions:
1. Can someone upload a map sample that works with this or am I going to have to use a Half-Life map?
2. Does ANY existing map compiler for Q1 support origin brushes? Just wondering. |
|
Back to top |
|
 |
goldenboy

Joined: 05 Sep 2008 Posts: 310 Location: Kiel
|
Posted: Sun Jan 03, 2010 3:06 am Post subject: |
|
|
1. Yes, shortly, but only works in DP with the above QC code;
2. No. _________________ ReMakeQuake
The Realm of Blog Magic |
|
Back to top |
|
 |
goldenboy

Joined: 05 Sep 2008 Posts: 310 Location: Kiel
|
Posted: Sun Jan 03, 2010 3:10 am Post subject: |
|
|
Code: | /*QUAKED func_rotating (0 .5 .8) ? x REVERSE Z_AXIS X_AXIS x x NONSOLID
Origin-rotating bmodel - experimental
"speed" rotation speed (100 default)
"origin" origin vector, x y z
*/
void() func_rotating =
{
self.solid = SOLID_BSP;
self.movetype = MOVETYPE_PUSH;
self.think = func_rotating;
setorigin (self, self.origin);
setmodel (self, self.model);
self.classname = "func_rotating";
setsize (self, self.mins, self.maxs);
if (!self.speed)
self.speed = 100;
if (self.spawnflags & 2) // reverse direction
self.speed = 0 - self.speed;
if (self.spawnflags & 64) // not solid
self.solid = SOLID_NOT;
if (self.spawnflags & 4)
{
self.avelocity_z = self.speed;
self.avelocity_x = 0;
self.avelocity_y = 0;
}
else if (self.spawnflags & 8)
{
self.avelocity_z = 0;
self.avelocity_x = self.speed;
self.avelocity_y = 0;
}
else
{
self.avelocity_z = 0;
self.avelocity_x = 0;
self.avelocity_y = self.speed;
}
self.nextthink = time; // next frame;
}; |
http://www.quaketastic.com/upload/files/single_player/maps/origin.zip
The map contains a func_rotating in the form of a cube.
The qc and map combination works in DP (rotates).
"origin" was set manually.
http://www.4shared.com/file/187101836/6a6182e6/origin.html
Small vid of a happily spinning yellow block - in DP. _________________ ReMakeQuake
The Realm of Blog Magic |
|
Back to top |
|
 |
r00k
Joined: 13 Nov 2004 Posts: 483
|
Posted: Sun Jan 03, 2010 5:57 am Post subject: |
|
|
Nice! |
|
Back to top |
|
 |
Spike
Joined: 05 Nov 2004 Posts: 944 Location: UK
|
Posted: Sun Jan 03, 2010 6:41 am Post subject: |
|
|
at spawn, time = 0
self.nextthink = time = 0; does nothing.
use:
self.think = SUB_Null;
self.nextthink = self.ltime + 9999999;
(the self.ltime term is optional, yeah, okay, it'll be 0, but hey, it highlights the difference between movetype_push and any other ent). _________________ What's a signature? |
|
Back to top |
|
 |
goldenboy

Joined: 05 Sep 2008 Posts: 310 Location: Kiel
|
Posted: Sun Jan 03, 2010 9:02 am Post subject: |
|
|
No luck. With the new qc, it still spins in DP, but not in FTE.
It's drawn in the correct place, just doesn't start to rotate
I tried a bit of stuff like self.nextthink = time + 0.1 and similar, but no luck. _________________ ReMakeQuake
The Realm of Blog Magic |
|
Back to top |
|
 |
r00k
Joined: 13 Nov 2004 Posts: 483
|
Posted: Sun Jan 03, 2010 9:40 am Post subject: |
|
|
you dont need to .think back to the function. the physics code will rotate if the avelocity != 0. You DO need to set self.ltime = time + 0.1; maybe ?
Here's how Hipnotic is doing it....
Code: |
void () RotateTargets =
{
local entity ent;
local vector vx;
local vector vy;
local vector vz;
local vector org;
makevectors (self.angles);
ent = find (world, targetname, self.target);
while (ent)
{
if ((ent.rotate_type == OBJECT_SETORIGIN))
{
org = ent.oldorigin;
vx = (v_forward * org_x);
vy = (v_right * org_y);
vy = (vy * CONTENT_EMPTY);
vz = (v_up * org_z);
ent.neworigin = ((vx + vy) + vz);
setorigin (ent, (ent.neworigin + self.origin));
}
else
{
if ((ent.rotate_type == OBJECT_ROTATE))
{
ent.angles = self.angles;
org = ent.oldorigin;
vx = (v_forward * org_x);
vy = (v_right * org_y);
vy = (vy * CONTENT_EMPTY);
vz = (v_up * org_z);
ent.neworigin = ((vx + vy) + vz);
setorigin (ent, (ent.neworigin + self.origin));
}
else
{
org = ent.oldorigin;
vx = (v_forward * org_x);
vy = (v_right * org_y);
vy = (vy * CONTENT_EMPTY);
vz = (v_up * org_z);
ent.neworigin = ((vx + vy) + vz);
ent.neworigin = ((self.origin - self.oldorigin) + (ent.neworigin - ent.oldorigin));
ent.velocity = ((ent.neworigin - ent.origin) * 25);
}
}
ent = find (ent, targetname, self.target);
}
};
void () RotateTargetsFinal =
{
local entity ent;
ent = find (world, targetname, self.target);
while (ent)
{
ent.velocity = VEC_ORIGIN;
if ((ent.rotate_type == OBJECT_ROTATE))
{
ent.angles = self.angles;
}
ent = find (ent, targetname, self.target);
}
};
void () SetTargetOrigin =
{
local entity ent;
ent = find (world, targetname, self.target);
while (ent)
{
if ((ent.rotate_type == OBJECT_MOVEWALL))
{
setorigin (ent, ((self.origin - self.oldorigin) + (ent.neworigin - ent.oldorigin)));
}
else
{
setorigin (ent, (ent.neworigin + self.origin));
}
ent = find (ent, targetname, self.target);
}
};
void () LinkRotateTargets =
{
local entity ent;
local vector tempvec;
self.oldorigin = self.origin;
ent = find (world, targetname, self.target);
while (ent)
{
if ((ent.classname == "rotate_object"))
{
ent.rotate_type = OBJECT_ROTATE;
ent.oldorigin = (ent.origin - self.oldorigin);
ent.neworigin = (ent.origin - self.oldorigin);
ent.owner = self;
}
else
{
if ((ent.classname == "func_movewall"))
{
ent.rotate_type = OBJECT_MOVEWALL;
tempvec = ((ent.absmin + ent.absmax) * 0.5);
ent.oldorigin = (tempvec - self.oldorigin);
ent.neworigin = ent.oldorigin;
ent.owner = self;
}
else
{
ent.rotate_type = OBJECT_SETORIGIN;
ent.oldorigin = (ent.origin - self.oldorigin);
ent.neworigin = (ent.origin - self.oldorigin);
}
}
ent = find (ent, targetname, self.target);
}
};
void () rotate_object =
{
self.classname = "rotate_object";
self.solid = SOLID_NOT;
self.movetype = MOVETYPE_NONE;
setmodel (self, self.model);
setsize (self, self.mins, self.maxs);
self.think = SUB_Null;
};
void () rotate_door_think2 =
{
local float t;
t = (time - self.ltime);
self.ltime = time;
self.frame = (TRUE - self.frame);
self.angles = self.dest;
if ((self.state == STATE_OPENING))
{
self.state = STATE_OPEN;
}
else
{
if ((self.spawnflags & STAYOPEN))
{
rotate_door_group_reversedirection ();
return;
}
self.state = STATE_CLOSED;
}
sound (self, CHAN_VOICE, self.noise3, TRUE, ATTN_NORM);
self.think = SUB_Null;
RotateTargetsFinal ();
};
void () rotate_door_think =
{
local float t;
t = (time - self.ltime);
self.ltime = time;
if ((time < self.endtime))
{
self.angles = (self.angles + (self.rotate * t));
RotateTargets ();
}
else
{
self.angles = self.dest;
RotateTargets ();
self.think = rotate_door_think2;
}
self.nextthink = (time + 0.01);
};
void () rotate_door_reversedirection =
{
local vector start;
self.frame = (TRUE - self.frame);
if ((self.state == STATE_CLOSING))
{
start = self.dest1;
self.dest = self.dest2;
self.state = STATE_OPENING;
}
else
{
start = self.dest2;
self.dest = self.dest1;
self.state = STATE_CLOSING;
}
sound (self, CHAN_VOICE, self.noise2, TRUE, ATTN_NORM);
self.rotate = ((self.dest - start) * (TRUE / self.speed));
self.think = rotate_door_think;
self.nextthink = (time + 0.02);
self.endtime = ((time + self.speed) - (self.endtime - time));
self.ltime = time;
};
void () rotate_door_group_reversedirection =
{
local string name;
if (self.group)
{
name = self.group;
self = find (world, group, name);
while (self)
{
rotate_door_reversedirection ();
self = find (self, group, name);
}
}
else
{
rotate_door_reversedirection ();
}
};
void () rotate_door_use =
{
local entity t;
local vector start;
if (((self.state != STATE_OPEN) && (self.state != STATE_CLOSED)))
{
return;
}
if (!self.cnt)
{
self.cnt = TRUE;
LinkRotateTargets ();
}
self.frame = (TRUE - self.frame);
if ((self.state == STATE_CLOSED))
{
start = self.dest1;
self.dest = self.dest2;
self.state = STATE_OPENING;
}
else
{
start = self.dest2;
self.dest = self.dest1;
self.state = STATE_CLOSING;
}
sound (self, CHAN_VOICE, self.noise2, TRUE, ATTN_NORM);
self.rotate = ((self.dest - start) * (TRUE / self.speed));
self.think = rotate_door_think;
self.nextthink = (time + 0.01);
self.endtime = (time + self.speed);
self.ltime = time;
};
void () func_rotate_door =
{
if (!self.target)
{
objerror ("rotate_door without target.");
}
self.dest1 = VEC_ORIGIN;
self.dest2 = self.angles;
self.angles = self.dest1;
if (!self.speed)
{
self.speed = FL_SWIM;
}
self.cnt = FALSE;
if (!self.dmg)
{
self.dmg = FL_SWIM;
}
else
{
if ((self.dmg < FALSE))
{
self.dmg = FALSE;
}
}
if ((self.sounds == FALSE))
{
self.sounds = TRUE;
}
if ((self.sounds == TRUE))
{
precache_sound ("doors/latch2.wav");
precache_sound ("doors/winch2.wav");
precache_sound ("doors/drclos4.wav");
self.noise1 = "doors/latch2.wav";
self.noise2 = "doors/winch2.wav";
self.noise3 = "doors/drclos4.wav";
}
if ((self.sounds == FL_SWIM))
{
precache_sound ("doors/airdoor1.wav");
precache_sound ("doors/airdoor2.wav");
self.noise2 = "doors/airdoor1.wav";
self.noise1 = "doors/airdoor2.wav";
self.noise3 = "doors/airdoor2.wav";
}
if ((self.sounds == MOVETYPE_WALK))
{
precache_sound ("doors/basesec1.wav");
precache_sound ("doors/basesec2.wav");
self.noise2 = "doors/basesec1.wav";
self.noise1 = "doors/basesec2.wav";
self.noise3 = "doors/basesec2.wav";
}
self.solid = SOLID_NOT;
self.movetype = MOVETYPE_NONE;
setmodel (self, self.model);
setorigin (self, self.origin);
setsize (self, self.mins, self.maxs);
self.state = STATE_CLOSED;
self.use = rotate_door_use;
self.think = SUB_Null;
};
|
|
|
Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2004 phpBB Group
|