Exemple #1
0
/**
 * @brief Touch trigger
 * @sa SP_trigger_touch
 */
static bool Touch_TouchTrigger (Edict* self, Edict* activator)
{
	/* these actors should really not be able to trigger this - they don't move anymore */
	assert(!G_IsDead(activator));

	self->_owner = G_EdictsFindTargetEntity(self->target);
	if (!self->owner()) {
		gi.DPrintf("Target '%s' wasn't found for %s\n", self->target, self->classname);
		G_FreeEdict(self);
		return false;
	}

	if (self->owner()->flags & FL_CLIENTACTION) {
		G_ActorSetClientAction(activator, self->owner());
	} else if (!(self->spawnflags & TRIGGER_TOUCH_ONCE) || self->touchedNext == nullptr) {
		if (!self->owner()->use) {
			gi.DPrintf("Owner of %s doesn't have a use function\n", self->classname);
			G_FreeEdict(self);
			return false;
		}
		G_UseEdict(self->owner(), activator);
	}

	return false;
}
Exemple #2
0
static void Reset_TouchTrigger (Edict* self, Edict* activator)
{
	/* fire the use function on leaving the trigger area */
	if (activator != nullptr && (self->owner()->flags & FL_CLIENTACTION))
		G_ActorSetClientAction(activator, nullptr);
	else if ((self->spawnflags & TRIGGER_TOUCH_ONCE) && self->touchedNext == nullptr)
		G_UseEdict(self->owner(), activator);
}
Exemple #3
0
/**
 * @brief This function 'uses' the edict. E.g. it opens the door when the player wants it to open
 * @sa PA_USE_DOOR
 * @param[in] player The player is trying to activate the door
 * @param[in,out] actor The actor the player is using to activate the entity
 * @param[in,out] edict The entity that is to be used
 * @todo Do we have to change the trigger position here, too? I don't think this is really needed.
 * @sa CL_ActorUse
 * @sa G_UseEdict
 */
bool G_ClientUseEdict (const player_t *player, edict_t *actor, edict_t *edict)
{
	/* check whether the actor has sufficient TUs to 'use' this edicts */
	if (!G_ActionCheckForCurrentTeam(player, actor, edict->TU))
		return false;

	if (!G_UseEdict(edict, actor))
		return false;

	/* using a group of edicts only costs TUs once (for the master) */
	G_ActorUseTU(actor, edict->TU);
	/* send the new TUs */
	G_SendStats(actor);

	G_EventEnd();

	return true;
}
Exemple #4
0
/**
 * @brief func_door (0 .5 .8) ?
 * "health" if set, door is destroyable
 * @sa SV_SetModel
 * @sa LM_AddModel
 * @sa G_SendEdictsAndBrushModels
 */
void SP_func_door (edict_t *ent)
{
	edict_t *other;

	ent->classname = "door";
	ent->type = ET_DOOR;
	if (!ent->noise)
		ent->noise = "doors/open_close";

	/* set an inline model */
	gi.SetModel(ent, ent->model);
	ent->solid = SOLID_BSP;
	gi.LinkEdict(ent);
	ent->doorState = STATE_CLOSED;
	ent->dir = YAW;

	if (ent->spawnflags & REVERSE)
		ent->dir |= DOOR_OPEN_REVERSE;

	if (ent->HP)
		ent->flags |= FL_DESTROYABLE;
	ent->flags |= FL_CLIENTACTION;

	/* spawn the trigger entity */
	other = G_TriggerSpawn(ent);
	other->touch = Touch_DoorTrigger;
	other->reset = Reset_DoorTrigger;
	ent->child = other;

	G_ActorSetTU(ent, TU_DOOR_ACTION);
	if (!ent->speed)
		ent->speed = 10;
	ent->use = Door_Use;

	/* the door should start opened */
	if (ent->spawnflags & FL_TRIGGERED)
		G_UseEdict(ent, NULL);

	ent->destroy = Destroy_Breakable;
}
Exemple #5
0
/**
 * @brief Call the 'use' function for the given edict and all its group members
 * @param[in] ent The edict to call the use function for
 * @param[in] activator The edict that uses ent
 * @return qtrue when there is possibility to use edict being parameter.
 * @sa G_ClientUseEdict
 */
qboolean G_UseEdict (edict_t *ent, edict_t* activator)
{
    if (!ent)
        return qfalse;

    /* no use function assigned */
    if (!ent->use)
        return qfalse;

    if (!ent->use(ent, activator))
        return qfalse;

    /* only the master edict is calling the opening for the other group parts */
    if (!(ent->flags & FL_GROUPSLAVE)) {
        edict_t* chain = ent->groupChain;
        while (chain) {
            G_UseEdict(chain, activator);
            chain = chain->groupChain;
        }
    }

    return qtrue;
}
Exemple #6
0
/**
 * @note Think functions are only executed when the match is running
 * or in other word, the game has started
 */
void G_MissionThink (Edict* self)
{
	if (!G_MatchIsRunning())
		return;

	/* when every player has joined the match - spawn the mission target
	 * particle (if given) to mark the trigger */
	if (self->particle) {
		self->link = G_SpawnParticle(self->origin, self->spawnflags, self->particle);

		/* This is automatically freed on map shutdown */
		self->particle = nullptr;
	}

	Edict* chain = self->groupMaster;
	if (!chain)
		chain = self;
	while (chain) {
		if (chain->type == ET_MISSION) {
			if (chain->item) {
				const Item* ic;
				G_GetFloorItems(chain);
				ic = chain->getFloor();
				if (!ic) {
					/* reset the counter if there is no item */
					chain->count = 0;
					return;
				}
				for (; ic; ic = ic->getNext()) {
					const objDef_t* od = ic->def();
					assert(od);
					/* not the item we are looking for */
					if (Q_streq(od->id, chain->item))
						break;
				}
				if (!ic) {
					/* reset the counter if it's not the searched item */
					chain->count = 0;
					return;
				}
			}
			if (chain->time) {
				/* Check that the target zone is still occupied (last defender might have died) */
				if (!chain->item && !G_MissionIsTouched(chain)) {
						chain->count = 0;
				}
				const int endTime = level.actualRound - chain->count;
				const int spawnIndex = (chain->getTeam() + level.teamOfs) % MAX_TEAMS;
				const int currentIndex = (level.activeTeam + level.teamOfs) % MAX_TEAMS;
				/* not every edict in the group chain has
				 * been occupied long enough */
				if (!chain->count || endTime < chain->time ||
						(endTime == chain->time && spawnIndex < currentIndex))
					return;
			}
			if (chain->target && !chain->time && !chain->item) {
				if (!G_MissionIsTouched(chain))
					return;
			}
		}
		chain = chain->groupChain;
	}

	const bool endMission = self->target == nullptr;

	/* store team before the edict is released */
	const int team = self->getTeam();
	chain = self->groupMaster;
	if (!chain)
		chain = self;
	while (chain) {
		if (chain->type == ET_MISSION) {
			G_UseEdict(chain, nullptr);
			if (chain->item != nullptr) {
				Edict* item = G_GetEdictFromPos(chain->pos, ET_ITEM);
				if (item != nullptr) {
					if (!G_InventoryRemoveItemByID(chain->item, item, CID_FLOOR)) {
						Com_Printf("Could not remove item '%s' from floor edict %i\n", chain->item, item->getIdNum());
					} else if (!item->getFloor()) {
						G_EventPerish(*item);
						G_FreeEdict(item);
					}
				}
			}
			if (chain->link != nullptr) {
				Edict* particle = G_GetEdictFromPos(chain->pos, ET_PARTICLE);
				if (particle != nullptr) {
					G_AppearPerishEvent(G_VisToPM(particle->visflags), false, *particle, nullptr);
					G_FreeEdict(particle);
				}
				chain->link = nullptr;
			}

			/* Display mission message */
			if (G_ValidMessage(chain)) {
				const char* msg = chain->message;
				if (msg[0] == '_')
					++msg;
				gi.BroadcastPrintf(PRINT_HUD, "%s", msg);
			}
		}

		Edict* ent = chain->groupChain;
		/* free the group chain */
		G_FreeEdict(chain);
		chain = ent;
	}

	if (endMission)
		G_MatchEndTrigger(team, level.activeTeam == TEAM_ALIEN ? 10 : 3);
}