예제 #1
0
/**
 * @brief The client lets the server spawn the actors for a given player by sending their information (models, inventory, etc..) over the network.
 * @param[in] player The player to spawn the actors for.
 * @sa GAME_SendCurrentTeamSpawningInfo
 * @sa clc_teaminfo
 */
void G_ClientTeamInfo (const player_t * player)
{
	const int length = gi.ReadByte(); /* Get the actor amount that the client sent. */
	int i;

	for (i = 0; i < length; i++) {
		const actorSizeEnum_t actorFieldSize = gi.ReadByte();
		/* Search for a spawn point for each entry the client sent */
		if (player->pers.team == TEAM_NO_ACTIVE || !G_ActorSpawnIsAllowed(i, player->pers.team))
			G_ClientSkipActorInfo();
		else {
			edict_t *ent = G_ClientGetFreeSpawnPointForActorSize(player, actorFieldSize);
			if (ent) {
				Com_DPrintf(DEBUG_GAME, "Player: %i - team %i - size: %i\n", player->num, ent->team, ent->fieldSize);

				G_ClientReadCharacter(ent);
				G_ClientReadInventory(ent);
				G_ClientAssignDefaultActorValues(ent);
				G_ActorGiveTimeUnits(ent);
				G_TouchTriggers(ent);
				ent->contentFlags = G_ActorGetContentFlags(ent->origin);
			} else {
				gi.DPrintf("Not enough spawn points for team %i (actorsize: %i)\n", player->pers.team, actorFieldSize);

				G_ClientSkipActorInfo();
			}
		}
	}

	Com_Printf("Used inventory slots client %s spawn: %i\n", player->pers.netname, game.i.GetUsedSlots(&game.i));
}
예제 #2
0
파일: g_move.cpp 프로젝트: jklemmack/ufoai
/**
 * @brief Generates the client events that are send over the netchannel to move an actor
 * @param[in] player Player who is moving an actor
 * @param[in] visTeam The team to check the visibility for - if this is 0 we build the forbidden list
 * above all edicts - for the human controlled actors this would mean that clicking to a grid
 * position that is not reachable because an invisible actor is standing there would not result in
 * a single step - as the movement is aborted before. For AI movement this is in general @c 0 - but
 * not if they e.g. hide.
 * @param[in] ent Edict to move
 * @param[in] to The grid position to walk to
 * @sa CL_ActorStartMove
 * @sa PA_MOVE
 */
void G_ClientMove (const player_t * player, int visTeam, edict_t* ent, const pos3_t to)
{
	int status, initTU;
	dvec_t dvtab[MAX_ROUTE];
	byte numdv, length;
	pos3_t pos;
	float div;
	int oldState;
	int oldHP;
	int oldSTUN;
	bool autoCrouchRequired = false;
	byte crouchingState;

	if (VectorCompare(ent->pos, to))
		return;

	/* check if action is possible */
	if (!G_ActionCheckForCurrentTeam(player, ent, TU_MOVE_STRAIGHT))
		return;

	crouchingState = G_IsCrouched(ent) ? 1 : 0;
	oldState = oldHP = oldSTUN = 0;

	/* calculate move table */
	G_MoveCalc(visTeam, ent, ent->pos, crouchingState, ent->TU);
	length = G_ActorMoveLength(ent, level.pathingMap, to, false);

	/* length of ROUTING_NOT_REACHABLE means not reachable */
	if (length && length >= ROUTING_NOT_REACHABLE)
		return;

	/* Autostand: check if the actor is crouched and player wants autostanding...*/
	if (crouchingState && player->autostand) {
		/* ...and if this is a long walk... */
		if (SHOULD_USE_AUTOSTAND(length)) {
			/* ...make them stand first. If the player really wants them to walk a long
			 * way crouched, he can move the actor in several stages.
			 * Uses the threshold at which standing, moving and crouching again takes
			 * fewer TU than just crawling while crouched. */
			G_ClientStateChange(player, ent, STATE_CROUCHED, true); /* change to stand state */
			crouchingState = G_IsCrouched(ent) ? 1 : 0;
			if (!crouchingState) {
				G_MoveCalc(visTeam, ent, ent->pos, crouchingState, ent->TU);
				length = G_ActorMoveLength(ent, level.pathingMap, to, false);
				autoCrouchRequired = true;
			}
		}
	}

	/* this let the footstep sounds play even over network */
	ent->think = G_PhysicsStep;
	ent->nextthink = level.time;

	/* assemble dvec-encoded move data */
	VectorCopy(to, pos);
	initTU = ent->TU;

	numdv = G_FillDirectionTable(dvtab, lengthof(dvtab), crouchingState, pos);

	/* make sure to end any other pending events - we rely on EV_ACTOR_MOVE not being active anymore */
	G_EventEnd();

	/* everything ok, found valid route? */
	if (VectorCompare(pos, ent->pos)) {
		byte* stepAmount = NULL;
		int usedTUs = 0;
		/* no floor inventory at this point */
		FLOOR(ent) = NULL;
		const int movingModifier = G_ActorGetInjuryPenalty(ent, MODIFIER_MOVEMENT);

		while (numdv > 0) {
			/* A flag to see if we needed to change crouch state */
			int crouchFlag;
			const byte oldDir = ent->dir;

			/* get next dvec */
			numdv--;
			const int dvec = dvtab[numdv];
			/* This is the direction to make the step into */
			const int dir = getDVdir(dvec);

			/* turn around first */
			status = G_ActorDoTurn(ent, dir);
			if (status & VIS_STOP) {
				autoCrouchRequired = false;
				if (ent->moveinfo.steps == 0)
					usedTUs += TU_TURN;
				break;
			}

			if (G_ActorShouldStopInMidMove(ent, status, dvtab, numdv)) {
				/* don't autocrouch if new enemy becomes visible */
				autoCrouchRequired = false;
				/* if something appears on our route that didn't trigger a VIS_STOP, we have to
				 * send the turn event if this is our first step */
				if (oldDir != ent->dir && ent->moveinfo.steps == 0) {
					G_EventActorTurn(ent);
					usedTUs += TU_TURN;
				}
				break;
			}

			/* decrease TUs */
			div = gi.GetTUsForDirection(dir, G_IsCrouched(ent));
			if ((int) (usedTUs + div + movingModifier) > ent->TU)
				break;
			usedTUs += div + movingModifier;

			/* This is now a flag to indicate a change in crouching - we need this for
			 * the stop in mid move call(s), because we need the updated entity position */
			crouchFlag = 0;
			/* Calculate the new position after the decrease in TUs, otherwise the game
			 * remembers the false position if the time runs out */
			PosAddDV(ent->pos, crouchFlag, dvec);

			/* slower if crouched */
			if (G_IsCrouched(ent))
				ent->speed = ACTOR_SPEED_CROUCHED;
			else
				ent->speed = ACTOR_SPEED_NORMAL;
			ent->speed *= g_actorspeed->value;

			if (crouchFlag == 0) { /* No change in crouch */
				G_EdictCalcOrigin(ent);

				const int contentFlags = G_ActorGetContentFlags(ent->origin);

				/* link it at new position - this must be done for every edict
				 * movement - to let the server know about it. */
				gi.LinkEdict(ent);

				/* Only the PHALANX team has these stats right now. */
				if (ent->chr.scoreMission) {
					float truediv = gi.GetTUsForDirection(dir, 0);		/* regardless of crouching ! */
					if (G_IsCrouched(ent))
						ent->chr.scoreMission->movedCrouched += truediv;
					else
						ent->chr.scoreMission->movedNormal += truediv;
				}
				/* write the step to the net */
				G_WriteStep(ent, &stepAmount, dvec, contentFlags);

				status = 0;

				/* Set ent->TU because the reaction code relies on ent->TU being accurate. */
				G_ActorSetTU(ent, initTU - usedTUs);

				edict_t* clientAction = ent->clientAction;
				oldState = ent->state;
				oldHP = ent->HP;
				oldSTUN = ent->STUN;
				/* check triggers at new position */
				if (G_TouchTriggers(ent)) {
					if (!clientAction)
						status |= VIS_STOP;
				}

				/* check if player appears/perishes, seen from other teams */
				G_CheckVis(ent);

				/* check for anything appearing, seen by "the moving one" */
				status |= G_CheckVisTeamAll(ent->team, 0, ent);

				G_TouchSolids(ent, 10.0f);

				/* state has changed - maybe we walked on a trigger_hurt */
				if (oldState != ent->state || oldHP != ent->HP || oldSTUN != ent->STUN)
					status |= VIS_STOP;
			} else if (crouchFlag == 1) {
				/* Actor is standing */
				G_ClientStateChange(player, ent, STATE_CROUCHED, true);
			} else if (crouchFlag == -1) {
				/* Actor is crouching and should stand up */
				G_ClientStateChange(player, ent, STATE_CROUCHED, false);
			}

			/* check for reaction fire */
			if (G_ReactionFireOnMovement(ent)) {
				status |= VIS_STOP;

				autoCrouchRequired = false;
			}

			/* check for death */
			if (((oldHP != 0 && (oldHP != ent->HP || oldSTUN != ent->STUN)) || (oldState != ent->state)) && !G_IsDazed(ent)) {
				/** @todo Handle dazed via trigger_hurt */
				/* maybe this was due to rf - then the G_ActorDie was already called */
				if (!G_IsDead(ent)) {
					G_CheckDeathOrKnockout(ent, NULL, NULL, (oldHP - ent->HP) + (ent->STUN - oldSTUN));
				}
				return;
			}

			if (G_ActorShouldStopInMidMove(ent, status, dvtab, numdv - 1)) {
				/* don't autocrouch if new enemy becomes visible */
				autoCrouchRequired = false;
				break;
			}

			/* Restore ent->TU because the movement code relies on it not being modified! */
			G_ActorSetTU(ent, initTU);
		}

		/* submit the TUs / round down */
		G_ActorSetTU(ent, initTU - usedTUs);

		G_SendStats(ent);

		/* end the move */
		G_GetFloorItems(ent);
		G_EventEnd();
	}

	if (autoCrouchRequired) {
		/* toggle back to crouched state */
		G_ClientStateChange(player, ent, STATE_CROUCHED, true);
	}
}