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
00032 qboolean G_IsLivingActor (const edict_t *ent)
00033 {
00034 return G_IsActor(ent) && (G_IsStunned(ent) || !G_IsDead(ent));
00035 }
00036
00044 void G_ActorUseDoor (edict_t *actor, edict_t *door)
00045 {
00046 edict_t *closeActor = NULL;
00047
00048 G_ClientUseEdict(G_PLAYER_FROM_ENT(actor), actor, door);
00049
00050 while ((closeActor = G_FindRadius(closeActor, door->origin, UNIT_SIZE * 3, ET_ACTOR))) {
00051
00052
00053 G_TouchTriggers(closeActor);
00054 }
00055 }
00056
00062 qboolean G_ActorIsInRescueZone (const edict_t* actor)
00063 {
00064 return actor->inRescueZone;
00065 }
00066
00072 void G_ActorSetInRescueZone (edict_t* actor, qboolean inRescueZone)
00073 {
00074 if (inRescueZone == G_ActorIsInRescueZone(actor))
00075 return;
00076
00077 if (inRescueZone)
00078 G_ClientPrintf(G_PLAYER_FROM_ENT(actor), PRINT_HUD, _("Soldier entered the rescue zone\n"));
00079 else
00080 G_ClientPrintf(G_PLAYER_FROM_ENT(actor), PRINT_HUD, _("Soldier left the rescue zone\n"));
00081
00082 actor->inRescueZone = inRescueZone;
00083 }
00084
00090 void G_ActorSetClientAction (edict_t *actor, edict_t *ent)
00091 {
00092 if (actor->clientAction == ent)
00093 return;
00094
00095 actor->clientAction = ent;
00096 if (ent == NULL) {
00097 G_EventResetClientAction(actor);
00098 } else {
00099 G_EventSetClientAction(actor);
00100 }
00101 }
00102
00108 int G_ActorGetReservedTUs (const edict_t *ent)
00109 {
00110 const chrReservations_t *res = &ent->chr.reservedTus;
00111 return res->reaction + res->shot + res->crouch;
00112 }
00113
00120 int G_ActorUsableTUs (const edict_t *ent)
00121 {
00122 if (!ent)
00123 return 0;
00124
00125 return ent->TU - G_ActorGetReservedTUs(ent);
00126 }
00127
00134 int G_ActorGetTUForReactionFire (const edict_t *ent)
00135 {
00136 const invList_t *invlistWeapon;
00137 const chrFiremodeSettings_t *fm = &ent->chr.RFmode;
00138 const fireDef_t *fd;
00139
00140 invlistWeapon = ACTOR_GET_INV(ent, fm->hand);
00141 assert(invlistWeapon);
00142 assert(invlistWeapon->item.t);
00143
00144 fd = FIRESH_FiredefForWeapon(&invlistWeapon->item);
00145 assert(fd);
00146 return fd[fm->fmIdx].time;
00147 }
00148
00156 void G_ActorReserveTUs (edict_t *ent, int resReaction, int resShot, int resCrouch)
00157 {
00158 if (ent->TU >= resReaction + resShot + resCrouch) {
00159 ent->chr.reservedTus.reaction = resReaction;
00160 ent->chr.reservedTus.shot = resShot;
00161 ent->chr.reservedTus.crouch = resCrouch;
00162 }
00163
00164 G_EventActorSendReservations(ent);
00165 }
00166
00173 edict_t *G_ActorGetByUCN (const int ucn, const int team)
00174 {
00175 edict_t *ent = NULL;
00176
00177 while ((ent = G_EdictsGetNextActor(ent)))
00178 if (team == ent->team && ent->chr.ucn == ucn)
00179 return ent;
00180
00181 return NULL;
00182 }
00183
00191 int G_ActorDoTurn (edict_t * ent, byte dir)
00192 {
00193 float angleDiv;
00194 const byte *rot;
00195 int i, num;
00196 int status;
00197
00198 assert(ent->dir < CORE_DIRECTIONS);
00199 assert(dir < PATHFINDING_DIRECTIONS);
00200
00201
00202
00203
00204
00208 if (dir >= CORE_DIRECTIONS && dir < FLYING_DIRECTIONS)
00209 return 0;
00210
00211
00212 dir &= (CORE_DIRECTIONS - 1);
00213 assert(dir < CORE_DIRECTIONS);
00214
00215
00216 if (ent->dir == dir)
00217 return 0;
00218
00219
00220 angleDiv = directionAngles[dir] - directionAngles[ent->dir];
00221 if (angleDiv > 180.0)
00222 angleDiv -= 360.0;
00223 if (angleDiv < -180.0)
00224 angleDiv += 360.0;
00225
00226
00227
00228
00229
00230 if (angleDiv > 0) {
00231 const int angleStep = (360.0 / CORE_DIRECTIONS);
00232 rot = dvleft;
00233 num = (angleDiv + angleStep / 2) / angleStep;
00234 } else {
00235 const int angleStep = (360.0 / CORE_DIRECTIONS);
00236 rot = dvright;
00237 num = (-angleDiv + angleStep / 2) / angleStep;
00238 }
00239
00240
00241 status = 0;
00242
00243
00244
00245
00246 for (i = 0; i < num; i++) {
00247 ent->dir = rot[ent->dir];
00248 assert(ent->dir < CORE_DIRECTIONS);
00249 status |= G_CheckVisTeamAll(ent->team, qfalse, ent);
00250 }
00251
00252 if (status & VIS_STOP) {
00253
00254 G_EventActorTurn(ent);
00255 }
00256
00257 return status;
00258 }
00259
00266 void G_ActorSetMaxs (edict_t* ent)
00267 {
00268 if (G_IsCrouched(ent))
00269 VectorSet(ent->maxs, PLAYER_WIDTH, PLAYER_WIDTH, PLAYER_CROUCH);
00270 else if (G_IsDead(ent))
00271 VectorSet(ent->maxs, PLAYER_WIDTH, PLAYER_WIDTH, PLAYER_DEAD);
00272 else
00273 VectorSet(ent->maxs, PLAYER_WIDTH, PLAYER_WIDTH, PLAYER_STAND);
00274
00275
00276 gi.LinkEdict(ent);
00277 }
00278
00283 void G_ActorGiveTimeUnits (edict_t *ent)
00284 {
00285 const int tus = G_IsDazed(ent) ? 0 : GET_TU(ent->chr.score.skills[ABILITY_SPEED]);
00286 G_ActorSetTU(ent, tus);
00287 G_RemoveDazed(ent);
00288 }
00289
00290 void G_ActorSetTU (edict_t *ent, int tus)
00291 {
00292 ent->TU = max(tus, 0);
00293 }
00294
00295 void G_ActorUseTU (edict_t *ent, int tus)
00296 {
00297 G_ActorSetTU(ent, ent->TU - tus);
00298 }
00299
00300 static void G_ActorStun (edict_t * ent, const edict_t *attacker)
00301 {
00302
00303 ent->state = STATE_STUN;
00304 if (attacker != NULL)
00305 level.num_stuns[attacker->team][ent->team]++;
00306 }
00307
00308 static void G_ActorRevitalise (edict_t *ent)
00309 {
00310 if (G_IsStunned(ent)) {
00311 G_RemoveStunned(ent);
00314 level.num_alive[ent->team]++;
00315
00316 G_GetFloorItems(ent);
00317 }
00318 G_ActorSetMaxs(ent);
00319
00320
00321 G_CheckVis(ent, qtrue);
00322
00323
00324 G_CheckVisTeamAll(ent->team, qfalse, ent);
00325 }
00326
00327 void G_ActorCheckRevitalise (edict_t *ent)
00328 {
00329 if (G_IsStunned(ent) && ent->STUN < ent->HP) {
00330 G_ActorRevitalise(ent);
00331 G_EventActorRevitalise(ent);
00332 G_SendStats(ent);
00333 }
00334 }
00335
00336 static void G_ActorDie (edict_t * ent, const edict_t *attacker)
00337 {
00338 G_RemoveStunned(ent);
00339 G_SetState(ent, 1 + rand() % MAX_DEATH);
00340 if (attacker != NULL)
00341 level.num_kills[attacker->team][ent->team]++;
00342 G_ActorSetMaxs(ent);
00343 }
00344
00353 void G_ActorDieOrStun (edict_t * ent, edict_t *attacker)
00354 {
00355 if (ent->HP == 0)
00356 G_ActorDie(ent, attacker);
00357 else
00358 G_ActorStun(ent, attacker);
00359
00360 level.num_alive[ent->team]--;
00361
00362 G_EventActorDie(ent);
00363
00364
00365 G_InventoryToFloor(ent);
00366
00367
00368 G_CheckVis(ent, qtrue);
00369
00370
00371 if (attacker)
00372 G_CheckVis(attacker, qtrue);
00373
00374
00375 G_CheckVisTeamAll(ent->team, qfalse, attacker);
00376
00377
00378 FLOOR(ent) = NULL;
00379 }
00380
00393 void G_ActorInvMove (edict_t *ent, const invDef_t * from, invList_t *fItem, const invDef_t * to, int tx,
00394 int ty, qboolean checkaction)
00395 {
00396 player_t *player;
00397 edict_t *floor;
00398 qboolean newFloor;
00399 invList_t *ic;
00400 item_t item;
00401 int mask;
00402 inventory_action_t ia;
00403 invList_t fItemBackup;
00404 int fx, fy;
00405 int originalTU, reservedTU = 0;
00406
00407 player = G_PLAYER_FROM_ENT(ent);
00408
00409 assert(fItem);
00410 assert(fItem->item.t);
00411
00412
00413 fItemBackup = *fItem;
00414
00415
00416 INVSH_GetFirstShapePosition(fItem, &fx, &fy);
00417 fx += fItem->x;
00418 fy += fItem->y;
00419
00420
00421
00422 if (checkaction && !G_ActionCheckForCurrentTeam(player, ent, 1))
00423 return;
00424
00425
00426 floor = G_GetFloorItems(ent);
00427 if (INV_IsFloorDef(to) && !floor) {
00428
00429 floor = G_SpawnFloor(ent->pos);
00430 newFloor = qtrue;
00431 } else if (INV_IsFloorDef(from) && !floor) {
00432
00433 gi.DPrintf("G_ClientInvMove: No source-floor found.\n");
00434 return;
00435 } else {
00436
00437 newFloor = qfalse;
00438 }
00439
00440
00441 if (tx == NONE) {
00442 ic = INVSH_SearchInInventory(&ent->chr.i, from, fItem->x, fItem->y);
00443 if (ic)
00444 INVSH_FindSpace(&ent->chr.i, &ic->item, to, &tx, &ty, fItem);
00445 if (tx == NONE)
00446 return;
00447 }
00448
00450
00451
00452 originalTU = ent->TU;
00453 reservedTU = G_ActorGetReservedTUs(ent);
00454
00455 G_ActorUseTU(ent, reservedTU);
00456
00457 ia = game.i.MoveInInventory(&game.i, &ent->chr.i, from, fItem, to, tx, ty, checkaction ? &ent->TU : NULL, &ic);
00458
00459 G_ActorSetTU(ent, originalTU - (originalTU - reservedTU - ent->TU));
00460
00461 switch (ia) {
00462 case IA_NONE:
00463
00464 return;
00465 case IA_NOTIME:
00466 G_ClientPrintf(player, PRINT_HUD, _("Can't perform action - not enough TUs!\n"));
00467 return;
00468 case IA_NORELOAD:
00469 G_ClientPrintf(player, PRINT_HUD,
00470 _("Can't perform action - weapon already fully loaded with the same ammunition!\n"));
00471 return;
00472 default:
00473
00474 break;
00475 }
00476
00477
00478 if (INV_IsFloorDef(from)) {
00479
00480
00481 assert(!newFloor);
00482 if (FLOOR(ent)) {
00483
00484 FLOOR(floor) = FLOOR(ent);
00485 G_EventInventoryDelete(floor, G_VisToPM(floor->visflags), from, fx, fy);
00486 } else {
00487
00488
00489 if (!INV_IsFloorDef(to)) {
00490 G_EventPerish(floor);
00491 G_FreeEdict(floor);
00492 }
00493 }
00494 } else {
00495 G_EventInventoryDelete(ent, G_TeamToPM(ent->team), from, fx, fy);
00496 }
00497
00498
00499 G_SendStats(ent);
00500
00501 assert(ic);
00502 item = ic->item;
00503
00504 if (ia == IA_RELOAD || ia == IA_RELOAD_SWAP) {
00505
00506 if (INV_IsFloorDef(to))
00507 mask = G_VisToPM(floor->visflags);
00508 else
00509 mask = G_TeamToPM(ent->team);
00510
00511 G_EventInventoryReload(INV_IsFloorDef(to) ? floor : ent, mask, &item, to, ic);
00512
00513 if (ia == IA_RELOAD) {
00514 gi.EndEvents();
00515 return;
00516 } else {
00517 item = fItemBackup.item;
00518 to = from;
00519 tx = fItemBackup.x;
00520 ty = fItemBackup.y;
00521 }
00522 }
00523
00524
00525 if (INV_IsFloorDef(to)) {
00526
00527
00528
00529 FLOOR(floor) = FLOOR(ent);
00530
00531 if (newFloor) {
00532
00533 G_CheckVis(floor, qtrue);
00534 } else {
00535
00536
00537 G_EventInventoryAdd(floor, G_VisToPM(floor->visflags), 1);
00538 G_WriteItem(&fItemBackup.item, to, tx, ty);
00539 }
00540 } else {
00541 G_EventInventoryAdd(ent, G_TeamToPM(ent->team), 1);
00542 G_WriteItem(&item, to, tx, ty);
00543 }
00544
00545 G_ReactionFireUpdate(ent, ent->chr.RFmode.fmIdx, ent->chr.RFmode.hand, ent->chr.RFmode.weapon);
00546
00547
00548 mask = G_VisToPM(ent->visflags) & ~G_TeamToPM(ent->team);
00549 if (mask) {
00550 if (INV_IsRightDef(from) || INV_IsLeftDef(from)) {
00551 G_EventInventoryDelete(ent, mask, from, fx, fy);
00552 }
00553 if (INV_IsRightDef(to) || INV_IsLeftDef(to)) {
00554 G_EventInventoryAdd(ent, mask, 1);
00555 G_WriteItem(&item, to, tx, ty);
00556 }
00557 }
00558 gi.EndEvents();
00559 }
00560
00567 void G_ActorReload (edict_t* ent, const invDef_t *invDef)
00568 {
00569 invList_t *ic;
00570 invList_t *icFinal;
00571 objDef_t *weapon;
00572 int tu;
00573 containerIndex_t containerID;
00574 invDef_t *bestContainer;
00575
00576
00577 icFinal = NULL;
00578 tu = 100;
00579 bestContainer = NULL;
00580
00581 if (CONTAINER(ent, invDef->id)) {
00582 weapon = CONTAINER(ent, invDef->id)->item.t;
00583 } else if (INV_IsLeftDef(invDef) && RIGHT(ent)->item.t->holdTwoHanded) {
00584
00585 invDef = INVDEF(gi.csi->idRight);
00586 weapon = CONTAINER(ent, invDef->id)->item.t;
00587 } else
00588 return;
00589
00590 assert(weapon);
00591
00592
00593
00594
00595
00596
00597 for (containerID = 0; containerID < gi.csi->numIDs; containerID++) {
00598 if (INVDEF(containerID)->out < tu) {
00599
00600
00601
00602
00603 for (ic = CONTAINER(ent, containerID); ic; ic = ic->next)
00604 if (INVSH_LoadableInWeapon(ic->item.t, weapon)) {
00605 icFinal = ic;
00606 bestContainer = INVDEF(containerID);
00607 tu = bestContainer->out;
00608 break;
00609 }
00610 }
00611 }
00612
00613
00614 if (bestContainer)
00615 G_ActorInvMove(ent, bestContainer, icFinal, invDef, 0, 0, qtrue);
00616 }