00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "g_local.h"
00026
00027 #define ACTOR_SPEED_NORMAL 100
00028 #define ACTOR_SPEED_CROUCHED (ACTOR_SPEED_NORMAL / 2)
00029 static const float FALLING_DAMAGE_FACTOR = 10.0f;
00030
00035 static pos_t *forbiddenList[MAX_FORBIDDENLIST];
00036 static int forbiddenListLength;
00037
00050 static void G_BuildForbiddenList (int team, const edict_t *movingActor)
00051 {
00052 edict_t *ent = NULL;
00053 int visMask;
00054
00055 forbiddenListLength = 0;
00056
00057
00058 if (team)
00059 visMask = G_TeamToVisMask(team);
00060 else
00061 visMask = TEAM_ALL;
00062
00063 while ((ent = G_EdictsGetNextInUse(ent))) {
00064
00065 if (G_IsBlockingMovementActor(ent) && (G_IsAI(movingActor) || (ent->visflags & visMask))) {
00066 forbiddenList[forbiddenListLength++] = ent->pos;
00067 forbiddenList[forbiddenListLength++] = (byte*) &ent->fieldSize;
00068 } else if (ent->type == ET_SOLID) {
00069 int j;
00070 for (j = 0; j < ent->forbiddenListSize; j++) {
00071 forbiddenList[forbiddenListLength++] = ent->forbiddenListPos[j];
00072 forbiddenList[forbiddenListLength++] = (byte*) &ent->fieldSize;
00073 }
00074 }
00075 }
00076
00077 if (forbiddenListLength > MAX_FORBIDDENLIST)
00078 gi.Error("G_BuildForbiddenList: list too long\n");
00079 }
00080
00093 void G_MoveCalc (int team, const edict_t *movingActor, const pos3_t from, byte crouchingState, int distance)
00094 {
00095 G_MoveCalcLocal(&level.pathingMap, team, movingActor, from, crouchingState, distance);
00096 }
00097
00109 void G_MoveCalcLocal (pathing_t *pt, int team, const edict_t *movingActor, const pos3_t from, byte crouchingState, int distance)
00110 {
00111 G_BuildForbiddenList(team, movingActor);
00112 gi.MoveCalc(gi.routingMap, movingActor->fieldSize, pt, from, crouchingState, distance,
00113 forbiddenList, forbiddenListLength);
00114 }
00115
00121 edict_t *G_GetActorFromPos (const pos3_t pos)
00122 {
00123 edict_t *actor = G_GetEdictFromPos(pos, ET_ACTOR);
00124 if (actor == NULL)
00125 actor = G_GetEdictFromPos(pos, ET_ACTOR2x2);
00126 if (actor == NULL)
00127 actor = G_GetEdictFromPos(pos, ET_ACTORHIDDEN);
00128
00129 return actor;
00130 }
00131
00137 void G_ActorFall (edict_t *ent)
00138 {
00139 edict_t* entAtPos;
00140 const int oldZ = ent->pos[2];
00141
00142 ent->pos[2] = gi.GridFall(gi.routingMap, ent->fieldSize, ent->pos);
00143
00144 entAtPos = G_GetEdictFromPos(ent->pos, ET_NULL);
00145 if (entAtPos != NULL && (G_IsBreakable(entAtPos) || G_IsBlockingMovementActor(entAtPos))) {
00146 const int diff = oldZ - ent->pos[2];
00147 G_TakeDamage(entAtPos, (int)(FALLING_DAMAGE_FACTOR * (float)diff));
00148 }
00149
00150 G_EdictCalcOrigin(ent);
00151 gi.LinkEdict(ent);
00152
00153 G_CheckVis(ent, qtrue);
00154
00155 G_EventActorFall(ent);
00156
00157 gi.EndEvents();
00158 }
00159
00166 static qboolean G_ActorShouldStopInMidMove (const edict_t *ent, int visState, byte* dvtab, int max)
00167 {
00168 if (visState & VIS_STOP)
00169 return qtrue;
00170
00171
00172
00173 if (visState & VIS_APPEAR) {
00174 pos3_t pos;
00175 VectorCopy(ent->pos, pos);
00176 while (max >= 0) {
00177 int tmp = 0;
00178 const edict_t *blockEdict;
00179
00180 PosAddDV(pos, tmp, dvtab[max]);
00181 max--;
00182 blockEdict = G_GetEdictFromPos(pos, ET_NULL);
00183
00184 if (blockEdict && G_IsBlockingMovementActor(blockEdict)) {
00185 const qboolean visible = G_IsVisibleForTeam(blockEdict, ent->team);
00186 if (visible)
00187 return qtrue;
00188 }
00189 }
00190 }
00191 return qfalse;
00192 }
00193
00207 void G_ClientMove (const player_t * player, int visTeam, edict_t* ent, const pos3_t to)
00208 {
00209 int status, initTU;
00210 byte dvtab[MAX_DVTAB];
00211 int dv, dir;
00212 byte numdv, length;
00213 pos3_t pos;
00214 float div, truediv;
00215 int contentFlags;
00216 vec3_t pointTrace;
00217 byte* stepAmount = NULL;
00218 qboolean triggers = qfalse;
00219 int oldState;
00220 qboolean autoCrouchRequired = qfalse;
00221 byte crouchingState;
00222
00223
00224 if (!G_ActionCheckForCurrentTeam(player, ent, TU_MOVE_STRAIGHT))
00225 return;
00226
00227 crouchingState = G_IsCrouched(ent) ? 1 : 0;
00228 oldState = 0;
00229
00230
00231 G_MoveCalc(visTeam, ent, ent->pos, crouchingState, ent->TU);
00232 length = gi.MoveLength(&level.pathingMap, to, crouchingState, qfalse);
00233
00234
00235 if (length && length >= ROUTING_NOT_REACHABLE)
00236 return;
00237
00238
00239 if (crouchingState && player->autostand) {
00240
00241 if (SHOULD_USE_AUTOSTAND(length)) {
00242
00243
00244
00245
00246 G_ClientStateChange(player, ent, STATE_CROUCHED, qtrue);
00247 crouchingState = G_IsCrouched(ent) ? 1 : 0;
00248 if (!crouchingState) {
00249 G_MoveCalc(visTeam, ent, ent->pos, crouchingState, ent->TU);
00250 length = gi.MoveLength(&level.pathingMap, to, crouchingState, qfalse);
00251 autoCrouchRequired = qtrue;
00252 }
00253 }
00254 }
00255
00256
00257 ent->think = G_PhysicsStep;
00258 ent->nextthink = level.time;
00259
00260
00261 VectorCopy(to, pos);
00262 numdv = 0;
00263 initTU = ent->TU;
00264
00265 while ((dv = gi.MoveNext(&level.pathingMap, pos, crouchingState))
00266 != ROUTING_UNREACHABLE) {
00267 const int oldZ = pos[2];
00268
00269
00270 PosSubDV(pos, crouchingState, dv);
00271
00272 dvtab[numdv++] = NewDVZ(dv, oldZ);
00273 if (numdv >= lengthof(dvtab))
00274 break;
00275 }
00276
00277
00278 gi.EndEvents();
00279
00280
00281 if (VectorCompare(pos, ent->pos)) {
00282 int usedTUs = 0;
00283
00284 FLOOR(ent) = NULL;
00285
00286 while (numdv > 0) {
00287
00288 int crouchFlag;
00289 const byte oldDir = ent->dir;
00290
00291
00292 numdv--;
00293 dv = dvtab[numdv];
00294
00295 dir = getDVdir(dv);
00296
00297
00298 status = G_ActorDoTurn(ent, dir);
00299 if (status & VIS_STOP) {
00300 autoCrouchRequired = qfalse;
00301 if (ent->moveinfo.steps == 0)
00302 usedTUs += TU_TURN;
00303 break;
00304 }
00305
00306 if (G_ActorShouldStopInMidMove(ent, status, dvtab, numdv)) {
00307
00308 autoCrouchRequired = qfalse;
00309
00310
00311 if (oldDir != ent->dir && ent->moveinfo.steps == 0) {
00312 G_EventActorTurn(ent);
00313 usedTUs += TU_TURN;
00314 }
00315 break;
00316 }
00317
00318
00319 div = gi.GetTUsForDirection(dir);
00320 truediv = div;
00321 if (G_IsCrouched(ent) && dir < CORE_DIRECTIONS)
00322 div *= TU_CROUCH_MOVING_FACTOR;
00323 if ((int) (usedTUs + div) > ent->TU)
00324 break;
00325 usedTUs += div;
00326
00327
00328
00329 crouchFlag = 0;
00330
00331
00332 PosAddDV(ent->pos, crouchFlag, dv);
00333
00334
00335 if (G_IsCrouched(ent))
00336 ent->speed = ACTOR_SPEED_CROUCHED;
00337 else
00338 ent->speed = ACTOR_SPEED_NORMAL;
00339 ent->speed *= g_actorspeed->value;
00340
00341 if (crouchFlag == 0) {
00342 edict_t* clientAction;
00343
00344 G_EdictCalcOrigin(ent);
00345 VectorCopy(ent->origin, pointTrace);
00346 pointTrace[2] += PLAYER_MIN;
00347
00348 contentFlags = gi.PointContents(pointTrace);
00349
00350
00351
00352 gi.LinkEdict(ent);
00353
00354
00355 if (ent->chr.scoreMission) {
00356 if (G_IsCrouched(ent))
00357 ent->chr.scoreMission->movedCrouched += truediv;
00358 else
00359 ent->chr.scoreMission->movedNormal += truediv;
00360 }
00361
00362
00363 if (gi.GetEvent() != EV_ACTOR_MOVE) {
00364 gi.AddEvent(G_VisToPM(ent->visflags), EV_ACTOR_MOVE);
00365 gi.WriteShort(ent->number);
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375 stepAmount = gi.WriteDummyByte(0);
00376
00377 gi.WriteDummyByte(0);
00378 gi.WriteDummyByte(0);
00379 gi.WriteDummyByte(0);
00380 } else if (!stepAmount) {
00381 gi.DPrintf("Event %i activate and no stepAmount pointer set\n", gi.GetEvent());
00382 break;
00383 }
00384
00385
00386 if (ent->moveinfo.steps >= MAX_DVTAB) {
00387 ent->moveinfo.steps = 0;
00388 ent->moveinfo.currentStep = 0;
00389 }
00390 ent->moveinfo.contentFlags[ent->moveinfo.steps] = contentFlags;
00391 ent->moveinfo.visflags[ent->moveinfo.steps] = ent->visflags;
00392 ent->moveinfo.steps++;
00393
00394
00395 (*stepAmount)++;
00396
00397 *(stepAmount + 1) = ent->pos[0];
00398 *(stepAmount + 2) = ent->pos[1];
00399 *(stepAmount + 3) = ent->pos[2];
00400
00401
00402
00403 gi.WriteByte(dv);
00404 gi.WriteShort(ent->speed);
00405 gi.WriteShort(contentFlags);
00406
00407
00408 G_CheckVis(ent, qtrue);
00409
00410
00411 status = G_CheckVisTeamAll(ent->team, qfalse, ent);
00412
00413
00414 G_ActorSetTU(ent, max(0, initTU - usedTUs));
00415
00416 clientAction = ent->clientAction;
00417 oldState = ent->state;
00418
00419 if (G_TouchTriggers(ent)) {
00420 triggers = qtrue;
00421 if (!clientAction)
00422 status |= VIS_STOP;
00423 }
00424
00425 if (oldState != ent->state)
00426 status |= VIS_STOP;
00427 } else if (crouchFlag == 1) {
00428
00429 G_ClientStateChange(player, ent, STATE_CROUCHED, qtrue);
00430 } else if (crouchFlag == -1) {
00431
00432 G_ClientStateChange(player, ent, STATE_CROUCHED, qfalse);
00433 }
00434
00435
00436 if (G_ReactionFireOnMovement(ent)) {
00437 status |= VIS_STOP;
00438
00439 autoCrouchRequired = qfalse;
00440 }
00441
00442
00443 G_ActorSetTU(ent, initTU);
00444
00445
00446 if (oldState != ent->state && !G_IsDazed(ent)) {
00448
00449 if (!G_IsDead(ent)) {
00450 G_PrintActorStats(ent, NULL, NULL);
00451
00452 G_ActorDieOrStun(ent, NULL);
00453 }
00454 return;
00455 }
00456
00457 if (G_ActorShouldStopInMidMove(ent, status, dvtab, numdv - 1)) {
00458
00459 autoCrouchRequired = qfalse;
00460 break;
00461 }
00462 }
00463
00464
00465 if (g_notu != NULL && g_notu->integer)
00466 G_ActorSetTU(ent, initTU);
00467 else
00468 G_ActorSetTU(ent, max(0, initTU - usedTUs));
00469
00470 G_SendStats(ent);
00471
00472
00473 G_GetFloorItems(ent);
00474 gi.EndEvents();
00475 }
00476
00477 if (autoCrouchRequired) {
00478
00479 G_ClientStateChange(player, ent, STATE_CROUCHED, qtrue);
00480 }
00481 }