// [30/7/2012] Added Monster_CheckBottom ~hogsy bool Monster_CheckBottom(edict_t *ent) { vec3_t mins,maxs,start,stop; trace_t trace; int x,y; float mid,bottom; Math_VectorAdd(ent->v.origin,ent->v.mins,mins); Math_VectorAdd(ent->v.origin,ent->v.maxs,maxs); /* If all of the points under the corners are solid world, don't bother with the tougher checks the corners must be within 16 of the midpoint */ start[2] = mins[2]-1; for(x = 0; x <= 1; x++) for(y = 0; y <= 1; y++) { start[0] = x ? maxs[0] : mins[0]; start[1] = y ? maxs[1] : mins[1]; if(Engine.Server_PointContents(start) != BSP_CONTENTS_SOLID) { start[2] = mins[2]; // The midpoint must be within 16 of the bottom start[0] = stop[0] = (mins[0]+maxs[0])*0.5f; start[1] = stop[1] = (mins[1]+maxs[1])*0.5f; stop[2] = start[2]-2*MONSTER_STEPSIZE; trace = Engine.Server_Move(start,mv3Origin,mv3Origin,stop,true,ent); if(trace.fraction == 1.0) return false; mid = bottom = trace.endpos[2]; // The corners must be within 16 of the midpoint for(x = 0; x <= 1; x++) for(y = 0; y <= 1; y++) { start[0] = stop[0] = x ? maxs[0] : mins[0]; start[1] = stop[1] = x ? maxs[1] : mins[1]; trace = Engine.Server_Move(start,mv3Origin,mv3Origin,stop,true,ent); if(trace.fraction != 1.0 && trace.endpos[2] > bottom) bottom = trace.endpos[2]; if(trace.fraction == 1.0 || mid-trace.endpos[2] > MONSTER_STEPSIZE) return false; } } } return true; }
void Sky_DrawFace (int axis) { glpoly_t *p; MathVector3f_t verts[4]; int i, j, start; float di,qi,dj,qj; MathVector3f_t v_up, v_right, temp, temp2; Sky_SetBoxVert(-1.0f,-1.0f,axis,verts[0]); Sky_SetBoxVert(-1.0f,1.0f,axis,verts[1]); Sky_SetBoxVert(1.0f,1.0f,axis,verts[2]); Sky_SetBoxVert(1.0f,-1.0f,axis,verts[3]); start = Hunk_LowMark (); p = (glpoly_t*)Hunk_Alloc(sizeof(glpoly_t)); Math_VectorSubtract(verts[2],verts[3], v_up); Math_VectorSubtract(verts[2],verts[1], v_right); di = Math_Max((int)r_sky_quality.value,1); qi = 1.0f/di; dj = (axis < 4) ? di*2 : di; // Subdivide vertically more than horizontally on skybox sides qj = 1.0f/dj; for (i=0; i<di; i++) { for (j=0; j<dj; j++) { if (i*qi < skymins[0][axis]/2+0.5 - qi || i*qi > skymaxs[0][axis]/2+0.5 || j*qj < skymins[1][axis]/2+0.5 - qj || j*qj > skymaxs[1][axis]/2+0.5) continue; //if (i&1 ^ j&1) continue; //checkerboard test Math_VectorScale(v_right, qi*i, temp); Math_VectorScale(v_up, qj*j, temp2); Math_VectorAdd(temp,temp2,temp); Math_VectorAdd(verts[0],temp,p->verts[0]); Math_VectorScale(v_up, qj, temp); Math_VectorAdd(p->verts[0],temp,p->verts[1]); Math_VectorScale(v_right, qi, temp); Math_VectorAdd(p->verts[1],temp,p->verts[2]); Math_VectorAdd(p->verts[0],temp,p->verts[3]); Sky_DrawFaceQuad(p); } } Hunk_FreeToLowMark(start); }
bool Monster_IsVisible(edict_t *ent,edict_t *target) { trace_t tTrace; vec3_t vStart,vEnd; // [10/4/2013] TODO: Rework for new FOV system ~hogsy // [2/1/2013] Simplified ~hogsy Math_VectorAdd(ent->v.origin,ent->v.view_ofs,vStart); Math_VectorAdd(target->v.origin,target->v.view_ofs,vEnd); tTrace = Traceline(ent,vStart,vEnd,true); // [10/4/2013] Simplified ~hogsy if(!(tTrace.bOpen && tTrace.bWater) && tTrace.fraction == 1.0f) return true; return false; }
void Brush_Move (brush_t *b, vec3_t move) { int i; face_t *f; for (f=b->brush_faces ; f ; f=f->next) for (i=0 ; i<3 ; i++) Math_VectorAdd(f->planepts[i],move,f->planepts[i]); Brush_Build(b); }
/* draw bounding boxes -- the server-side boxes, not the renderer cullboxes */ void Video_ShowBoundingBoxes(void) { extern ServerEntity_t *sv_player; MathVector3f_t mins, maxs; ClientEntity_t *clEntity; ServerEntity_t *ed; int i; if (!r_showbboxes.value || (cl.maxclients > 1) || !r_drawentities.value || (!sv.active && !g_state.embedded)) return; VideoLayer_Disable(VIDEO_DEPTH_TEST | VIDEO_TEXTURE_2D); VideoLayer_Enable(VIDEO_BLEND); for (i=0, ed=NEXT_EDICT(sv.edicts) ; i<sv.num_edicts ; i++, ed=NEXT_EDICT(ed)) { if(ed == sv_player && !chase_active.value) continue; glColor3f(1,1,1); R_EmitWirePoint (ed->v.origin); Math_VectorAdd(ed->v.mins,ed->v.origin,mins); Math_VectorAdd(ed->v.maxs,ed->v.origin,maxs); glColor4f(0, 0.5f, 0, 0.5f); R_EmitWireBox(mins,maxs, 1, 1, 1); } // Cycle through client-side entities. for (i = 0, clEntity = cl_entities; i < cl.num_entities; i++, clEntity++) Video_DrawClientBoundingBox(clEntity); for (i = 0, clEntity = cl_temp_entities; i < cl_numvisedicts; i++, clEntity++) Video_DrawClientBoundingBox(clEntity); VideoLayer_Disable(VIDEO_BLEND); VideoLayer_Enable(VIDEO_TEXTURE_2D | VIDEO_DEPTH_TEST); }
bool R_CullModelForEntity(entity_t *e) { vec3_t mins, maxs; if(e == &cl.viewent) return false; if(e->angles[PITCH] || e->angles[ROLL]) { Math_VectorAdd (e->origin, e->model->rmins, mins); Math_VectorAdd (e->origin, e->model->rmaxs, maxs); } else if(e->angles[YAW]) { Math_VectorAdd (e->origin, e->model->ymins, mins); Math_VectorAdd (e->origin, e->model->ymaxs, maxs); } else //no rotation { Math_VectorAdd(e->origin,e->model->mins,mins); Math_VectorAdd(e->origin,e->model->maxs,maxs); } return R_CullBox(mins, maxs); }
void Video_DrawClientBoundingBox(ClientEntity_t *clEntity) { MathVector3f_t vMins, vMaxs; if (!clEntity->model || ((clEntity == &cl_entities[cl.viewentity]) && !chase_active.bValue) || (clEntity == &cl.viewent)) return; Math_VectorAdd(clEntity->model->rmins, clEntity->origin, vMins); Math_VectorAdd(clEntity->model->rmaxs, clEntity->origin, vMaxs); switch (clEntity->model->type) { case MODEL_TYPE_LEVEL: // Only draw wires for the BSP, since otherwise it's difficult to see anything else. glColor4f(0, 0, 0, 0); R_EmitWireBox(vMins, vMaxs, 0, 1, 0); break; default: glColor4f(0.5f, 0, 0, 0.5f); R_EmitWireBox(vMins, vMaxs, 1, 0, 0); } }
/* Damage entities within a specific radius. */ void Entity_RadiusDamage(edict_t *eInflictor,float fRadius,int iDamage,int iDamageType) { int i; float fDistance; vec3_t vOrigin; edict_t *eTarget = Engine.Server_FindRadius(eInflictor->v.origin,fRadius); Engine.WriteByte(MSG_BROADCAST,SVC_TEMPENTITY); Engine.WriteByte(MSG_BROADCAST,CTE_EXPLOSION); for(i = 0; i < 3; i++) Engine.WriteCoord(MSG_BROADCAST,eInflictor->v.origin[i]); do { if(eTarget->v.bTakeDamage) { int i; for(i = 0; i < 3; i++) vOrigin[i] = eTarget->v.origin[i]+(eTarget->v.mins[i]+eTarget->v.maxs[i])*0.5f; Math_VectorSubtract(eInflictor->v.origin,vOrigin,vOrigin); fDistance = 0.5f*(float)Math_VectorLength(vOrigin); if(fDistance > 0) { Math_VectorInverse(vOrigin); Math_VectorAdd(eTarget->v.velocity,vOrigin,eTarget->v.velocity); // [15/7/2013] Reduce the damage by distance ~hogsy fDistance = (float)iDamage-(100.0f/fDistance); // [15/8/2013] Less damage for the inflictor ~hogsy if(eTarget == eInflictor) fDistance = fDistance/2.0f; if(fDistance > 0) if(Entity_CanDamage(eInflictor,eTarget, iDamageType)) MONSTER_Damage(eTarget,eInflictor,(int)fDistance,iDamageType); } } eTarget = eTarget->v.chain; } while(eTarget); }
/* Damage entities within a specific radius. */ void Entity_RadiusDamage(ServerEntity_t *eInflictor, float fRadius, int iDamage, int iDamageType) { int i; float fDistance; MathVector3f_t vOrigin; ServerEntity_t *eTarget = Engine.Server_FindRadius(eInflictor->v.origin, fRadius); do { if(eTarget->v.bTakeDamage) { for(i = 0; i < 3; i++) vOrigin[i] = eTarget->v.origin[i]+(eTarget->v.mins[i]+eTarget->v.maxs[i])*0.5f; Math_VectorSubtract(eInflictor->v.origin,vOrigin,vOrigin); fDistance = 0.5f*(float)Math_VectorLength(vOrigin); if(fDistance > 0) { Math_VectorInverse(vOrigin); Math_VectorAdd(eTarget->v.velocity,vOrigin,eTarget->v.velocity); // Reduce the damage by distance. fDistance = (float)iDamage-(100.0f/fDistance); // Less damage for the inflictor. if(eTarget == eInflictor) fDistance = fDistance/2.0f; if(fDistance > 0) Entity_Damage(eTarget,eInflictor,(int)fDistance,iDamageType); } } eTarget = eTarget->v.chain; } while(eTarget); }
/* Does not change the entities velocity at all */ trace_t SV_PushEntity (edict_t *ent, vec3_t push) { trace_t trace; vec3_t end; Math_VectorAdd (ent->v.origin, push, end); if (ent->v.movetype == (MOVETYPE_FLYMISSILE || MOVETYPE_FLYBOUNCE)) trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_MISSILE, ent); else if (ent->Physics.iSolid == SOLID_TRIGGER || ent->Physics.iSolid == SOLID_NOT) // only clip against bmodels trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NOMONSTERS, ent); else trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent); Math_VectorCopy (trace.endpos, ent->v.origin); SV_LinkEdict(ent,true); if(trace.ent) Physics_Impact(ent,trace.ent); return trace; }
/* Does not change the entities velocity at all */ trace_t Physics_PushEntity(ServerEntity_t *eEntity, MathVector3f_t mvPush) { trace_t trace; MathVector3f_t end; Math_VectorAdd(eEntity->v.origin, mvPush, end); if (eEntity->v.movetype == (MOVETYPE_FLYMISSILE || MOVETYPE_FLYBOUNCE)) trace = Engine.Server_Move(eEntity->v.origin, eEntity->v.mins, eEntity->v.maxs, end, MOVE_MISSILE, eEntity); else if (eEntity->Physics.iSolid == SOLID_TRIGGER || eEntity->Physics.iSolid == SOLID_NOT) // only clip against bmodels trace = Engine.Server_Move(eEntity->v.origin, eEntity->v.mins, eEntity->v.maxs, end, MOVE_NOMONSTERS, eEntity); else trace = Engine.Server_Move(eEntity->v.origin, eEntity->v.mins, eEntity->v.maxs, end, MOVE_NORMAL, eEntity); Math_VectorCopy(trace.endpos, eEntity->v.origin); Entity_Link(eEntity, true); if (trace.ent) Physics_Impact(eEntity, trace.ent); return trace; }
winding_t *BasePolyForPlane (plane_t *p) { int i, x; vec_t max, v; vec3_t org, vright, vup; winding_t *w; // find the major axis max = -BOGUS_RANGE; x = -1; for (i=0 ; i<3; i++) { v = fabs(p->normal[i]); if (v > max) { x = i; max = v; } } if (x==-1) Error("BasePolyForPlane: no axis found"); Math_VectorCopy(vec3_origin,vup); switch (x) { case 0: case 1: vup[2] = 1; break; case 2: vup[0] = 1; break; } v = Math_DotProduct(vup,p->normal); Math_VectorMA(vup,-v,p->normal,vup); Math_VectorNormalize(vup); Math_VectorScale(p->normal,p->dist,org); Math_CrossProduct(vup,p->normal,vright); Math_VectorScale(vup,8192,vup); Math_VectorScale(vright,8192,vright); // project a really big axis aligned box onto the plane w = NewWinding (4); Math_VectorSubtract(org,vright,w->points[0]); Math_VectorAdd(w->points[0],vup,w->points[0]); Math_VectorAdd(org,vright,w->points[1]); Math_VectorAdd(w->points[1],vup,w->points[1]); Math_VectorAdd(org,vright,w->points[2]); Math_VectorSubtract(w->points[2],vup,w->points[2]); Math_VectorSubtract(org,vright,w->points[3]); Math_VectorSubtract(w->points[3],vup,w->points[3]); w->numpoints = 4; return w; }
// [18/5/2013] TODO: Merge with SV_PushMove ~hogsy static void Server_PushRotate(edict_t *pusher,float movetime) { int i,e,num_moved,slaves_moved; edict_t *check,*block,*moved_edict[MAX_EDICTS],*ground,*slave,*master; vec3_t move,a,amove,entorig,pushorig,moved_from[MAX_EDICTS],org,org2,forward,right,up; bool bMoveIt; for (i = 0; i < 3; i++) amove[i] = pusher->v.avelocity[i] * movetime; Math_VectorNegate(amove,a); Math_AngleVectors(a,forward,right,up); Math_VectorCopy(pusher->v.angles,pushorig); // move the pusher to it's final position Math_VectorAdd(pusher->v.angles,amove,pusher->v.angles); pusher->v.ltime += movetime; SV_LinkEdict (pusher, false); slaves_moved = 0; master = pusher; while(master->v.aiment) { slave = PROG_TO_EDICT(master->v.aiment); slaves_moved++; Math_VectorCopy (slave->v.angles, moved_from[MAX_EDICTS - slaves_moved]); moved_edict[MAX_EDICTS - slaves_moved] = slave; if (slave->v.movedir[PITCH]) slave->v.angles[PITCH] = master->v.angles[PITCH]; else slave->v.angles[PITCH] += slave->v.avelocity[PITCH] * movetime; if (slave->v.movedir[YAW]) slave->v.angles[YAW] = master->v.angles[YAW]; else slave->v.angles[YAW] += slave->v.avelocity[YAW] * movetime; if (slave->v.movedir[ROLL]) slave->v.angles[ROLL] = master->v.angles[ROLL]; else slave->v.angles[ROLL] += slave->v.avelocity[ROLL] * movetime; slave->v.ltime = master->v.ltime; SV_LinkEdict(slave,false); master = slave; } // 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_NOCLIP) continue; // if the entity is standing on the pusher, it will definitely be moved bMoveIt = false; ground = check->v.groundentity; if(check->v.flags & FL_ONGROUND) { if (ground == pusher) bMoveIt = true; else { for (i = 0; i < slaves_moved; i++) { if (ground == moved_edict[MAX_EDICTS - i - 1]) { bMoveIt = true; break; } } } } if(!bMoveIt) { 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]) { for (i = 0; i < slaves_moved; i++) { slave = moved_edict[MAX_EDICTS-i-1]; if( check->v.absmin[0] >= slave->v.absmax[0] || check->v.absmin[1] >= slave->v.absmax[1] || check->v.absmin[2] >= slave->v.absmax[2] || check->v.absmax[0] <= slave->v.absmin[0] || check->v.absmax[1] <= slave->v.absmin[1] || check->v.absmax[2] <= slave->v.absmin[2] ) continue; } if (i == slaves_moved) 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 = check->v.flags & ~FL_ONGROUND; Math_VectorCopy(check->v.origin,entorig); Math_VectorCopy(check->v.origin,moved_from[num_moved]); moved_edict[num_moved] = check; num_moved++; // calculate destination position Math_VectorSubtract(check->v.origin,pusher->v.origin,org); org2[0] = Math_DotProduct(org,forward); org2[1] = -Math_DotProduct(org,right); org2[2] = Math_DotProduct(org,up); Math_VectorSubtract (org2,org,move); // try moving the contacted entity pusher->Physics.iSolid = SOLID_NOT; SV_PushEntity (check, move); //@@TODO: do we ever want to do anybody's angles? maybe just yaw??? if(check->monster.iType != 1) { #if 0 vec3_t vYaw; vYaw[YAW] = Math_AngleMod(pusher->v.angles[YAW]+check->v.angles[YAW]); Con_Printf("%i %i\n",(int)check->v.angles[YAW],(int)vYaw[YAW]); //check->v.angles[YAW] = vYaw[YAW]; //check->v.angles[YAW] = Math_AngleMod(vYaw[YAW]); #endif // move back any entities we already moved for (i = 0; i < num_moved; i++) { Math_VectorAdd(moved_edict[i]->v.angles, amove, moved_edict[i]->v.angles); moved_edict[i]->v.angles[YAW] += amove[YAW]/2.0f; SV_LinkEdict(moved_edict[i],false); } } pusher->Physics.iSolid = 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->Physics.iSolid == SOLID_NOT || check->Physics.iSolid == SOLID_TRIGGER) { // corpse check->v.mins[0] = check->v.mins[1] = 0; Math_VectorCopy(check->v.mins,check->v.maxs); continue; } Math_VectorCopy(entorig,check->v.origin); SV_LinkEdict(check,true); Math_VectorCopy(pushorig,pusher->v.angles); SV_LinkEdict(pusher,false); pusher->v.ltime -= movetime; for(i = 0; i < slaves_moved; i++) { slave = moved_edict[MAX_EDICTS - i - 1]; Math_VectorCopy(moved_from[MAX_EDICTS - i - 1], slave->v.angles); SV_LinkEdict(slave,false); slave->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) pusher->v.blocked(pusher,check); // move back any entities we already moved for (i = 0; i < num_moved; i++) { Math_VectorCopy (moved_from[i], moved_edict[i]->v.origin); //@@TODO:: see above // if (!((int)moved_edict[i]->v.flags & (FL_CLIENT | FL_MONSTER))) Math_VectorSubtract (moved_edict[i]->v.angles, amove, moved_edict[i]->v.angles); moved_edict[i]->v.angles[YAW] -= amove[YAW]; SV_LinkEdict(moved_edict[i],false); } return; } } }
void SV_PushMove (edict_t *pusher, float movetime) { int i, e; edict_t *check, *block; vec3_t mins, maxs, move; vec3_t entorig, pushorig; int num_moved; edict_t **moved_edict; //johnfitz -- dynamically allocate vec3_t *moved_from; //johnfitz -- dynamically allocate int mark; //johnfitz if(!pusher->v.velocity[0] && !pusher->v.velocity[1] && !pusher->v.velocity[2]) { pusher->v.ltime += movetime; return; } for (i=0 ; i<3 ; i++) { move[i] = pusher->v.velocity[i] * movetime; mins[i] = pusher->v.absmin[i] + move[i]; maxs[i] = pusher->v.absmax[i] + move[i]; } Math_VectorCopy (pusher->v.origin, pushorig); // move the pusher to it's final position Math_VectorAdd (pusher->v.origin, move, pusher->v.origin); pusher->v.ltime += movetime; SV_LinkEdict(pusher,false); //johnfitz -- dynamically allocate mark = Hunk_LowMark (); moved_edict = (edict_t**)Hunk_Alloc(sv.num_edicts*sizeof(edict_t*)); moved_from = (vec3_t(*))Hunk_Alloc (sv.num_edicts*sizeof(vec3_t)); //johnfitz // 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_NOCLIP) continue; // if the entity is standing on the pusher, it will definately be moved if(!((check->v.flags & FL_ONGROUND) && check->v.groundentity == pusher)) { if ( check->v.absmin[0] >= maxs[0] || check->v.absmin[1] >= maxs[1] || check->v.absmin[2] >= maxs[2] || check->v.absmax[0] <= mins[0] || check->v.absmax[1] <= mins[1] || check->v.absmax[2] <= mins[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 = check->v.flags & ~FL_ONGROUND; Math_VectorCopy(check->v.origin,entorig); Math_VectorCopy(check->v.origin,moved_from[num_moved]); moved_edict[num_moved] = check; num_moved++; // try moving the contacted entity pusher->Physics.iSolid = SOLID_NOT; SV_PushEntity (check, move); pusher->Physics.iSolid = 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->Physics.iSolid == SOLID_NOT || check->Physics.iSolid == SOLID_TRIGGER) { // corpse check->v.mins[0] = check->v.mins[1] = 0; Math_VectorCopy(check->v.mins,check->v.maxs); continue; } Math_VectorCopy(entorig,check->v.origin); SV_LinkEdict(check,true); Math_VectorCopy(pushorig,pusher->v.origin); 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.eOther = check; pusher->v.blocked(pusher,check); } // move back any entities we already moved for (i=0 ; i<num_moved ; i++) { Math_VectorCopy(moved_from[i],moved_edict[i]->v.origin); SV_LinkEdict (moved_edict[i], false); } Hunk_FreeToLowMark (mark); //johnfitz return; } } Hunk_FreeToLowMark (mark); //johnfitz }
// [30/7/2012] Added Monster_MoveStep ~hogsy // [30/7/2012] TODO: Revised ~hogsy bool Monster_MoveStep(edict_t *ent,vec3_t move,bool bRelink) { float dz; vec3_t oldorg,vNewOrigin,end; trace_t trace; int i; Math_VectorClear(vNewOrigin); // Flying monsters don't step up if(ent->v.flags & (FL_SWIM|FL_FLY)) { // Try one move with vertical motion, then one without for(i = 0; i < 2; i++) { Math_VectorAdd(ent->v.origin,move,vNewOrigin); if(i == 0) { dz = ent->v.origin[2]-ent->monster.vTarget[2]; if(dz > 40) vNewOrigin[2] -= 8; else if(dz < 30) vNewOrigin[2] += 8; } trace = Engine.Server_Move(ent->v.origin,ent->v.mins,ent->v.maxs,vNewOrigin,false,ent); if(trace.fraction == 1.0f) { if((ent->v.flags & FL_SWIM) && (Engine.Server_PointContents(trace.endpos) == BSP_CONTENTS_EMPTY)) return false; Math_VectorCopy(trace.endpos,ent->v.origin); if(bRelink) Engine.LinkEntity(ent,true); return true; } } return false; } // Push down from a step height above the wished position vNewOrigin[2] += MONSTER_STEPSIZE; Math_VectorCopy(vNewOrigin,end); end[2] -= MONSTER_STEPSIZE*2; trace = Engine.Server_Move(vNewOrigin,ent->v.mins,ent->v.maxs,end,false,ent); if(trace.bAllSolid) return false; else if(trace.bStartSolid) { vNewOrigin[2] -= MONSTER_STEPSIZE; trace = Engine.Server_Move(vNewOrigin,ent->v.mins,ent->v.maxs,end,false,ent); if(trace.bAllSolid || trace.bStartSolid) return false; } if(trace.fraction == 1) { // If monster had the ground pulled out, go ahead and fall if(ent->v.flags & FL_PARTIALGROUND) { Math_VectorAdd(ent->v.origin,move,ent->v.origin); if(bRelink) Engine.LinkEntity(ent,true); ent->v.flags &= ~FL_ONGROUND; return true; } // Walked off an edge return false; } // Check point traces down for dangling corners Math_VectorCopy(trace.endpos,ent->v.origin); if(!Monster_CheckBottom(ent)) { if(ent->v.flags & FL_PARTIALGROUND) { /* Entity had floor mostly pulled out from underneath it and is trying to correct */ if(bRelink) Engine.LinkEntity(ent,true); return true; } Math_VectorCopy(ent->v.origin,oldorg); return false; } if(ent->v.flags & FL_PARTIALGROUND) ent->v.flags &= ~FL_PARTIALGROUND; ent->v.groundentity = trace.ent; if(bRelink) Engine.LinkEntity(ent,true); return true; }
void Sky_ProcessEntities(void) { int i,k,mark; unsigned int j; float dot; bool bRotated; ClientEntity_t *e; msurface_t *s; glpoly_t *p; MathVector3f_t vTemp, forward, right, up; if (!r_drawentities.value) return; for (i=0 ; i<cl_numvisedicts ; i++) { e = cl_visedicts[i]; if (e->model->type != MODEL_TYPE_LEVEL) continue; if(R_CullModelForEntity(e)) continue; if(e->alpha == ENTALPHA_ZERO) continue; Math_VectorSubtract (r_refdef.vieworg, e->origin, modelorg); if(e->angles[0] || e->angles[1] || e->angles[2]) { bRotated = true; Math_AngleVectors(e->angles, forward, right, up); Math_VectorCopy(modelorg,vTemp); modelorg[0] = Math_DotProduct(vTemp,forward); modelorg[1] = -Math_DotProduct(vTemp,right); modelorg[2] = Math_DotProduct(vTemp,up); } else bRotated = false; s = &e->model->surfaces[e->model->firstmodelsurface]; for (j=0 ; j<e->model->nummodelsurfaces ; j++, s++) { if (s->flags & SURF_DRAWSKY) { dot = Math_DotProduct (modelorg, s->plane->normal) - s->plane->dist; if (((s->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) || (!(s->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON))) { //copy the polygon and translate manually, since Sky_ProcessPoly needs it to be in world space mark = Hunk_LowMark(); p = (glpoly_t*)Hunk_Alloc (sizeof(*s->polys)); //FIXME: don't allocate for each poly p->numverts = s->polys->numverts; for (k=0; k<p->numverts; k++) { if(bRotated) { p->verts[k][0] = e->origin[0] + s->polys->verts[k][0] * forward[0] - s->polys->verts[k][1] * right[0] + s->polys->verts[k][2] * up[0]; p->verts[k][1] = e->origin[1] + s->polys->verts[k][0] * forward[1] - s->polys->verts[k][1] * right[1] + s->polys->verts[k][2] * up[1]; p->verts[k][2] = e->origin[2] + s->polys->verts[k][0] * forward[2] - s->polys->verts[k][1] * right[2] + s->polys->verts[k][2] * up[2]; } else Math_VectorAdd(s->polys->verts[k], e->origin, p->verts[k]); } Sky_ProcessPoly (p); Hunk_FreeToLowMark (mark); } } } } }
/* Update sky bounds */ void Sky_ProjectPoly (int nump, MathVector3f_t vecs) { int i,j; MathVector3f_t v, av; float s, t, dv; int axis; float *vp; // decide which face it maps to Math_VectorCopy (g_mvOrigin3f, v); for (i=0, vp=vecs ; i<nump ; i++, vp+=3) Math_VectorAdd (vp, v, v); av[0] = fabs(v[0]); av[1] = fabs(v[1]); av[2] = fabs(v[2]); if (av[0] > av[1] && av[0] > av[2]) { if (v[0] < 0) axis = 1; else axis = 0; } else if (av[1] > av[2] && av[1] > av[0]) { if (v[1] < 0) axis = 3; else axis = 2; } else { if (v[2] < 0) axis = 5; else axis = 4; } // project new texture coords for (i=0 ; i<nump ; i++, vecs+=3) { j = vec_to_st[axis][2]; if (j > 0) dv = vecs[j - 1]; else dv = -vecs[-j - 1]; j = vec_to_st[axis][0]; if (j < 0) s = -vecs[-j -1] / dv; else s = vecs[j-1] / dv; j = vec_to_st[axis][1]; if (j < 0) t = -vecs[-j -1] / dv; else t = vecs[j-1] / dv; if (s < skymins[0][axis]) skymins[0][axis] = s; if (t < skymins[1][axis]) skymins[1][axis] = t; if (s > skymaxs[0][axis]) skymaxs[0][axis] = s; if (t > skymaxs[1][axis]) skymaxs[1][axis] = t; } }