g_func.c

Go to the documentation of this file.
00001 
00006 /*
00007 All original material Copyright (C) 2002-2010 UFO: Alien Invasion.
00008 
00009 Original file from Quake 2 v3.21: quake2-2.31/game/g_spawn.c
00010 Copyright (C) 1997-2001 Id Software, Inc.
00011 
00012 This program is free software; you can redistribute it and/or
00013 modify it under the terms of the GNU General Public License
00014 as published by the Free Software Foundation; either version 2
00015 of the License, or (at your option) any later version.
00016 
00017 This program is distributed in the hope that it will be useful,
00018 but WITHOUT ANY WARRANTY; without even the implied warranty of
00019 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00020 
00021 See the GNU General Public License for more details.
00022 
00023 You should have received a copy of the GNU General Public License
00024 along with this program; if not, write to the Free Software
00025 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00026 
00027 */
00028 
00029 
00030 #include "g_local.h"
00031 
00039 static qboolean Touch_Breakable (edict_t *self, edict_t *activator)
00040 {
00041     /* not yet broken */
00042     if (self->HP != 0)
00043         return qfalse;
00044 
00045     if (G_IsActor(activator))
00046         G_ActorFall(activator);
00047 
00048     return qfalse;
00049 }
00050 
00051 static qboolean Destroy_Breakable (edict_t *self)
00052 {
00053     vec3_t origin;
00054     int i;
00055 
00056     VectorCenterFromMinsMaxs(self->absmin, self->absmax, origin);
00057 
00058     /* the HP value is used to decide whether this was a triggered call or a
00059      * call during a fight - a triggered call will be handled differently in
00060      * terms of timing and the related particle effects in the client code */
00061     if (self->HP == 0)
00062         gi.AddEvent(PM_ALL, EV_MODEL_EXPLODE_TRIGGERED);
00063     else
00064         gi.AddEvent(PM_ALL, EV_MODEL_EXPLODE);
00065     gi.WriteShort(self->number);
00066     if (self->particle)
00067         G_SpawnParticle(origin, self->spawnflags, self->particle);
00068 
00069     switch (self->material) {
00070     case MAT_GLASS:
00071         G_EventSpawnSound(self, origin, "misc/breakglass+");
00072         break;
00073     case MAT_METAL:
00074         G_EventSpawnSound(self, origin, "misc/breakmetal+");
00075         break;
00076     case MAT_ELECTRICAL:
00077         G_EventSpawnSound(self, origin, "misc/breakelectric+");
00078         break;
00079     case MAT_WOOD:
00080         G_EventSpawnSound(self, origin, "misc/breakwood+");
00081         break;
00082     case MAT_MAX:
00083         break;
00084     }
00085 
00086 
00087     /* unlink to update the routing */
00088     gi.UnlinkEdict(self);
00089     self->inuse = qfalse;
00090     self->HP = 0;
00091 
00092     /* check whether the removal changes the vis mask
00093      * for the teams that were seeing this edict */
00094     for (i = 0; i < MAX_TEAMS; i++)
00095         if (level.num_alive[i] && self->visflags & i)
00096             G_CheckVisTeam(i, self, qfalse, self);
00097 
00098     G_RecalcRouting(self);
00099     G_TouchEdicts(self, 10.0f);
00100 
00101     /* now we can destroy the edict completely */
00102     G_EventPerish(self);
00103     G_FreeEdict(self);
00104 
00105     return qtrue;
00106 }
00107 
00119 void SP_func_breakable (edict_t *ent)
00120 {
00121     ent->classname = "breakable";
00122     ent->type = ET_BREAKABLE;
00123 
00124     ent->flags |= FL_DESTROYABLE;
00125 
00126     /* set an inline model */
00127     gi.SetModel(ent, ent->model);
00128     ent->solid = SOLID_BSP;
00129     gi.LinkEdict(ent);
00130 
00131     Com_DPrintf(DEBUG_GAME, "func_breakable: model (%s) num: %i mins: %i %i %i maxs: %i %i %i origin: %i %i %i\n",
00132             ent->model, ent->mapNum, (int)ent->mins[0], (int)ent->mins[1], (int)ent->mins[2],
00133             (int)ent->maxs[0], (int)ent->maxs[1], (int)ent->maxs[2],
00134             (int)ent->origin[0], (int)ent->origin[1], (int)ent->origin[2]);
00135 
00136     ent->destroy = Destroy_Breakable;
00137     ent->touch = Touch_Breakable;
00138 }
00139 
00140 /*
00141 =============================================================================
00142 DOOR FUNCTIONS
00143 =============================================================================
00144 */
00145 
00152 static qboolean Door_Use (edict_t *door, edict_t *activator)
00153 {
00154     if (door->doorState == STATE_CLOSED) {
00155         door->doorState = STATE_OPENED;
00156 
00157         /* change rotation and relink */
00158         door->angles[YAW] += DOOR_ROTATION_ANGLE;
00159         gi.LinkEdict(door);
00160 
00161         /* maybe the server called this because the door starts opened */
00162         if (G_MatchIsRunning()) {
00163             /* let everybody know, that the door opens */
00164             gi.AddEvent(PM_ALL, EV_DOOR_OPEN);
00165             gi.WriteShort(door->number);
00166             if (door->noise[0] != '\0')
00167                 G_EventSpawnSound(door, door->origin, door->noise);
00168         }
00169     } else if (door->doorState == STATE_OPENED) {
00170         door->doorState = STATE_CLOSED;
00171 
00172         /* change rotation and relink */
00173         door->angles[YAW] -= DOOR_ROTATION_ANGLE;
00174         gi.LinkEdict(door);
00175 
00176         /* closed is the standard, opened is handled above - we need an active
00177          * team here already, otherwise this is a bug */
00178         assert(G_MatchIsRunning());
00179         /* let everybody know, that the door closes */
00180         gi.AddEvent(PM_ALL, EV_DOOR_CLOSE);
00181         gi.WriteShort(door->number);
00182         if (door->noise[0] != '\0')
00183             G_EventSpawnSound(door, door->origin, door->noise);
00184     } else
00185         return qfalse;
00186 
00187     /* Update model orientation */
00188     gi.SetInlineModelOrientation(door->model, door->origin, door->angles);
00189     Com_DPrintf(DEBUG_GAME, "Server processed door movement.\n");
00190 
00191     /* Update path finding table */
00192     G_RecalcRouting(door);
00193 
00194     if (activator && G_IsLivingActor(activator)) {
00195         /* Check if the player appears/perishes, seen from other teams. */
00196         G_CheckVis(activator, qtrue);
00197 
00198         /* Calc new vis for the activator. */
00199         G_CheckVisTeamAll(activator->team, qfalse, activator);
00200     }
00201 
00202     return qtrue;
00203 }
00204 
00212 static qboolean Touch_DoorTrigger (edict_t *self, edict_t *activator)
00213 {
00214     if (!self->owner)
00215         return qfalse;
00216 
00217     if (G_IsAI(activator)) {
00218         /* let the ai interact with the door */
00219         if (self->flags & FL_GROUPSLAVE)
00220             self = self->groupMaster;
00221         if (AI_CheckUsingDoor(activator, self->owner))
00222             G_ActorUseDoor(activator, self->owner);
00223         /* we don't want the client action stuff to be send for ai actors */
00224         return qfalse;
00225     } else {
00226         /* prepare for client action */
00227         G_ActorSetClientAction(activator, self->owner);
00228         return qtrue;
00229     }
00230 }
00231 
00237 static void Reset_DoorTrigger (edict_t *self, edict_t *activator)
00238 {
00239     if (activator->clientAction == self)
00240         G_ActorSetClientAction(activator, NULL);
00241 }
00242 
00250 void SP_func_door (edict_t *ent)
00251 {
00252     edict_t *other;
00253 
00254     ent->classname = "door";
00255     ent->type = ET_DOOR;
00256     if (!ent->noise)
00257         ent->noise = "doors/open_close";
00258 
00259     /* set an inline model */
00260     gi.SetModel(ent, ent->model);
00261     ent->solid = SOLID_BSP;
00262     gi.LinkEdict(ent);
00263     ent->doorState = STATE_CLOSED;
00264 
00265     if (ent->HP)
00266         ent->flags |= FL_DESTROYABLE;
00267 
00268     /* spawn the trigger entity */
00269     other = G_TriggerSpawn(ent);
00270     other->touch = Touch_DoorTrigger;
00271     other->reset = Reset_DoorTrigger;
00272 
00273     G_ActorSetTU(ent, TU_DOOR_ACTION);
00274     ent->use = Door_Use;
00275     ent->child = other;
00276 
00277     /* the door should start opened */
00278     if (ent->spawnflags & FL_TRIGGERED)
00279         G_UseEdict(ent, NULL);
00280 
00281     Com_DPrintf(DEBUG_GAME, "func_door: model (%s) num: %i solid:%i mins: %i %i %i maxs: %i %i %i absmins: %i %i %i absmaxs: %i %i %i origin: %i %i %i\n",
00282             ent->model, ent->mapNum, ent->solid,
00283             (int)ent->mins[0], (int)ent->mins[1], (int)ent->mins[2],
00284             (int)ent->maxs[0], (int)ent->maxs[1], (int)ent->maxs[2],
00285             (int)ent->absmin[0], (int)ent->absmin[1], (int)ent->absmin[2],
00286             (int)ent->absmax[0], (int)ent->absmax[1], (int)ent->absmax[2],
00287             (int)ent->origin[0], (int)ent->origin[1], (int)ent->origin[2]);
00288 
00289     ent->destroy = Destroy_Breakable;
00290 }
00291 
00297 void SP_func_rotating (edict_t *ent)
00298 {
00299     ent->classname = "rotating";
00300     ent->type = ET_ROTATING;
00301 
00302     /* set an inline model */
00303     gi.SetModel(ent, ent->model);
00304     ent->solid = SOLID_BSP;
00305     gi.LinkEdict(ent);
00306 
00307     /* the lower, the faster */
00308     if (!ent->speed)
00309         ent->speed = 50;
00310 
00311     if (ent->HP)
00312         ent->flags |= FL_DESTROYABLE;
00313 
00314     Com_DPrintf(DEBUG_GAME, "func_rotating: model (%s) num: %i mins: %i %i %i maxs: %i %i %i origin: %i %i %i\n",
00315             ent->model, ent->mapNum, (int)ent->mins[0], (int)ent->mins[1], (int)ent->mins[2],
00316             (int)ent->maxs[0], (int)ent->maxs[1], (int)ent->maxs[2],
00317             (int)ent->origin[0], (int)ent->origin[1], (int)ent->origin[2]);
00318 }

Generated by  doxygen 1.6.2