/* ============ SpawnItem Sets the clipping size and plants the object on the floor. Items can't be immediately dropped to floor, because they might be on an entity that hasn't spawned yet. ============ */ void SpawnItem (edict_t *ent, gitem_t *item) { if (!ent || !item) // FS: Prevent SP crash { return; } PrecacheItem (item); if (ent->spawnflags) { if (strcmp(ent->classname, "key_power_cube") != 0) { ent->spawnflags = 0; gi.dprintf(DEVELOPER_MSG_GAME, "%s at %s has invalid spawnflags set\n", ent->classname, vtos(ent->s.origin)); } } // some items will be prevented in deathmatch if (deathmatch->value) { if ( (int)dmflags->value & DF_NO_ARMOR ) { if (item->pickup == Pickup_Armor || item->pickup == Pickup_PowerArmor) { G_FreeEdict (ent); return; } } if ( (int)dmflags->value & DF_NO_ITEMS ) { if (item->pickup == Pickup_Powerup) { G_FreeEdict (ent); return; } } if ( (int)dmflags->value & DF_NO_HEALTH ) { if (item->pickup == Pickup_Health || item->pickup == Pickup_Adrenaline) { G_FreeEdict (ent); return; } } if ( (int)dmflags->value & DF_INFINITE_AMMO ) { if (item->flags == IT_AMMO /*|| (strcmp(ent->classname, "weapon_flamethrower") == 0) */) { G_FreeEdict (ent); return; } } } if (coop->value && (strcmp(ent->classname, "key_power_cube") == 0)) { ent->spawnflags |= (1 << (8 + level.power_cubes)); level.power_cubes++; } // don't let them drop items that stay in a coop game if ((coop->value) && (item->flags & IT_STAY_COOP)) { item->drop = NULL; } ent->item = item; ent->nextthink = level.time + 2 * FRAMETIME; // items start after other solids ent->think = droptofloor; ent->s.effects = item->world_model_flags; //faf ent->s.renderfx = RF_GLOW; if (ent->model) gi.modelindex (ent->model); }
static bool Destroy_Camera (Edict* self) { G_SpawnParticle(self->origin, self->spawnflags, self->particle); G_FreeEdict(self); return true; }
/*QUAKED monster_gekk (1 .5 0) (-24 -24 -24) (24 24 24) Ambush Trigger_Spawn Sight Chant GoodGuy NoGib */ void SP_monster_gekk (edict_t *self) { if (deathmatch->value) { G_FreeEdict (self); return; } sound_swing = gi.soundindex ("gek/gk_atck1.wav"); sound_hit = gi.soundindex ("gek/gk_atck2.wav"); sound_hit2 = gi.soundindex ("gek/gk_atck3.wav"); sound_death = gi.soundindex ("gek/gk_deth1.wav"); sound_pain1 = gi.soundindex ("gek/gk_pain1.wav"); sound_sight = gi.soundindex ("gek/gk_sght1.wav"); sound_search = gi.soundindex ("gek/gk_idle1.wav"); sound_step1 = gi.soundindex ("gek/gk_step1.wav"); sound_step2 = gi.soundindex ("gek/gk_step2.wav"); sound_step3 = gi.soundindex ("gek/gk_step3.wav"); sound_thud = gi.soundindex ("mutant/thud1.wav"); sound_chantlow = gi.soundindex ("gek/gek_low.wav"); sound_chantmid = gi.soundindex ("gek/gek_mid.wav"); sound_chanthigh = gi.soundindex ("gek/gek_high.wav"); self->movetype = MOVETYPE_STEP; self->solid = SOLID_BBOX; // Lazarus: special purpose skins if ( self->style ) { PatchMonsterModel("models/monsters/gekk/tris.md2"); self->s.skinnum = self->style * 3; } self->s.modelindex = gi.modelindex ("models/monsters/gekk/tris.md2"); VectorSet (self->mins, -24, -24, -24); VectorSet (self->maxs, 24, 24, 24); gi.modelindex ("models/objects/gekkgib/pelvis/tris.md2"); gi.modelindex ("models/objects/gekkgib/arm/tris.md2"); gi.modelindex ("models/objects/gekkgib/torso/tris.md2"); gi.modelindex ("models/objects/gekkgib/claw/tris.md2"); gi.modelindex ("models/objects/gekkgib/leg/tris.md2"); gi.modelindex ("models/objects/gekkgib/head/tris.md2"); if(!self->health) { if (skill->value == 0) self->health = 120; else self->health = 150; } if(!self->gib_health) self->gib_health = -100; if(!self->mass) self->mass = 300; self->pain = gekk_pain; self->die = gekk_die; self->monsterinfo.stand = gekk_stand; self->monsterinfo.walk = gekk_walk; self->monsterinfo.run = gekk_run_start; self->monsterinfo.dodge = gekk_dodge; self->monsterinfo.attack = gekk_jump; self->monsterinfo.melee = gekk_melee; self->monsterinfo.sight = gekk_sight; self->monsterinfo.search = gekk_search; self->monsterinfo.idle = gekk_idle; self->monsterinfo.checkattack = gekk_checkattack; if (!self->monsterinfo.flies) self->monsterinfo.flies = 0.70; // Lazarus if(self->powerarmor) { if (self->powerarmortype == 1) self->monsterinfo.power_armor_type = POWER_ARMOR_SCREEN; else self->monsterinfo.power_armor_type = POWER_ARMOR_SHIELD; self->monsterinfo.power_armor_power = self->powerarmor; } self->common_name = "Gekk"; if (!self->blood_type) self->blood_type = 1; //Knightmare- set this for blood color gi.linkentity (self); self->monsterinfo.currentmove = &gekk_move_stand; self->monsterinfo.scale = MODEL_SCALE; walkmonster_start (self); if (self->spawnflags & 8) self->monsterinfo.currentmove = &gekk_move_chant; }
/*QUAKED info_null (0 0.5 0) (-4 -4 -4) (4 4 4) Used as a positional target for spotlights, etc. */ void SP_info_null (edict_t *self) { G_FreeEdict (self); }
/*QUAKED info_null (0 0.5 0) (-4 -4 -4) (4 4 4) Used as a positional target for spotlights, etc. */ void G_info_null(g_edict_t *self) { G_FreeEdict(self); }
/* ================== Cmd_Give_f Give items to a client ================== */ void Cmd_Give_f (edict_t *ent) { char *name; gitem_t *it; int index; int i; qboolean give_all; edict_t *it_ent; if (deathmatch->value && !sv_cheats->value) { gi.cprintf (ent, PRINT_HIGH, "You must run the server with '+set cheats 1' to enable this command.\n"); return; } name = gi.args(); if (Q_stricmp(name, "all") == 0) give_all = true; else give_all = false; if (give_all || Q_stricmp(gi.argv(1), "health") == 0) { if (gi.argc() == 3) ent->health = atoi(gi.argv(2)); else ent->health = ent->max_health; if (!give_all) return; } if (give_all || Q_stricmp(name, "weapons") == 0) { for (i=0 ; i<game.num_items ; i++) { it = itemlist + i; if (!it->pickup) continue; if (!(it->flags & IT_WEAPON)) continue; ent->client->pers.inventory[i] += 1; } if (!give_all) return; } if (give_all || Q_stricmp(name, "ammo") == 0) { for (i=0 ; i<game.num_items ; i++) { it = itemlist + i; if (!it->pickup) continue; if (!(it->flags & IT_AMMO)) continue; Add_Ammo (ent, it, 1000); } if (!give_all) return; } if (give_all || Q_stricmp(name, "armor") == 0) { gitem_armor_t *info; it = FindItem("Jacket Armor"); ent->client->pers.inventory[ITEM_INDEX(it)] = 0; it = FindItem("Combat Armor"); ent->client->pers.inventory[ITEM_INDEX(it)] = 0; it = FindItem("Body Armor"); info = (gitem_armor_t *)it->info; ent->client->pers.inventory[ITEM_INDEX(it)] = info->max_count; if (!give_all) return; } if (give_all || Q_stricmp(name, "Power Shield") == 0) { it = FindItem("Power Shield"); it_ent = G_Spawn(); it_ent->classname = it->classname; SpawnItem (it_ent, it); Touch_Item (it_ent, ent, NULL, NULL); if (it_ent->inuse) G_FreeEdict(it_ent); if (!give_all) return; } if (give_all) { for (i=0 ; i<game.num_items ; i++) { it = itemlist + i; if (!it->pickup) continue; if (it->flags & (IT_ARMOR|IT_WEAPON|IT_AMMO)) continue; ent->client->pers.inventory[i] = 1; } return; } it = FindItem (name); if (!it) { name = gi.argv(1); it = FindItem (name); if (!it) { gi.cprintf (ent, PRINT_HIGH, "unknown item\n"); return; } } if (!it->pickup) { gi.cprintf (ent, PRINT_HIGH, "non-pickup item\n"); return; } index = ITEM_INDEX(it); if (it->flags & IT_AMMO) { if (gi.argc() == 3) ent->client->pers.inventory[index] = atoi(gi.argv(2)); else ent->client->pers.inventory[index] += it->quantity; } else { it_ent = G_Spawn(); it_ent->classname = it->classname; SpawnItem (it_ent, it); Touch_Item (it_ent, ent, NULL, NULL); if (it_ent->inuse) G_FreeEdict(it_ent); } }
/*QUAKED monster_makron (1 .5 0) (-30 -30 0) (30 30 90) Ambush Trigger_Spawn Sight */ void SP_monster_makron (edict_t *self) { if (deathmatch->value) { G_FreeEdict (self); return; } MakronPrecache (); self->movetype = MOVETYPE_STEP; self->solid = SOLID_BBOX; self->s.modelindex = gi.modelindex ("models/monsters/boss3/rider/tris.md2"); VectorSet (self->mins, -30, -30, 0); VectorSet (self->maxs, 30, 30, 90); // Lazarus: mapper-configurable health if(!self->health) self->health = 3000; // Lazarus: get around Killed's prevention of health dropping below -999 // if(!self->gib_health) // self->gib_health = -2000; self->gib_health = -900; if(!self->mass) self->mass = 500; self->pain = makron_pain; self->die = makron_die; self->monsterinfo.stand = makron_stand; self->monsterinfo.walk = makron_walk; self->monsterinfo.run = makron_run; self->monsterinfo.dodge = NULL; self->monsterinfo.attack = makron_attack; self->monsterinfo.melee = NULL; self->monsterinfo.sight = makron_sight; self->monsterinfo.checkattack = Makron_CheckAttack; // Knightmare- added sparks and blood type if (!self->blood_type) self->blood_type = 2; //sparks else self->fogclip |= 2; //custom bloodtype flag // Lazarus if(self->powerarmor) { self->monsterinfo.power_armor_type = POWER_ARMOR_SHIELD; self->monsterinfo.power_armor_power = self->powerarmor; } gi.linkentity (self); self->monsterinfo.currentmove = &makron_move_sight; if(self->health < 0) { mmove_t *deathmoves[] = {&makron_move_death2, &makron_move_death3, NULL}; M_SetDeath(self,(mmove_t **)&deathmoves); } self->monsterinfo.scale = MODEL_SCALE; walkmonster_start(self); }
/* ============================== G_UseTargets the global "activator" should be set to the entity that initiated the firing. If self.delay is set, a DelayedUse entity will be created that will actually do the SUB_UseTargets after that many seconds have passed. Centerprints any self.message to the activator. Search for (string)targetname in all entities that match (string)self.target and call their .use function ============================== */ void G_UseTargets (edict_t *ent, edict_t *activator) { edict_t *t; // // check for a delay // if (ent->delay) { // create a temp object to fire at a later time t = G_Spawn(); t->classname = "DelayedUse"; t->nextthink = level.time + ent->delay; t->think = Think_Delay; t->activator = activator; if (!activator) gi.dprintf ("Think_Delay with no activator\n"); t->message = ent->message; t->target = ent->target; t->killtarget = ent->killtarget; return; } // // print the message // if ((ent->message) && !(activator->svflags & SVF_MONSTER)) { gi.centerprintf (activator, "%s", ent->message); if (ent->noise_index) gi.sound (activator, CHAN_AUTO, ent->noise_index, 1, ATTN_NORM, 0); else gi.sound (activator, CHAN_AUTO, gi.soundindex ("misc/talk1.wav"), 1, ATTN_NORM, 0); } // // kill killtargets // if (ent->killtarget) { t = NULL; while ((t = G_Find (t, FOFS(targetname), ent->killtarget))) { G_FreeEdict (t); if (!ent->inuse) { gi.dprintf("entity was removed while using killtargets\n"); return; } } } // // fire targets // if (ent->target) { t = NULL; while ((t = G_Find (t, FOFS(targetname), ent->target))) { // doors fire area portals in a specific way if (!Q_strcasecmp(t->classname, "func_areaportal") && (!Q_strcasecmp(ent->classname, "func_door") || !Q_strcasecmp(ent->classname, "func_door_rotating"))) continue; if (t == ent) { gi.dprintf ("WARNING: Entity used itself.\n"); } else { if (t->use) t->use (t, ent, activator); } if (!ent->inuse) { gi.dprintf("entity was removed while using targets\n"); return; } } } }
qboolean monster_start (edict_t *self) { if (deathmatch->value) { G_FreeEdict (self); return false; } // Lazarus: Already gibbed monsters passed across levels via trigger_transition: if ( (self->max_health > 0) && (self->health <= self->gib_health) && !(self->spawnflags & SF_MONSTER_NOGIB) ) { void SP_gibhead(edict_t *); SP_gibhead(self); return true; } // Lazarus: Good guys if (self->spawnflags & SF_MONSTER_GOODGUY) { self->monsterinfo.aiflags |= AI_GOOD_GUY; if(!self->dmgteam) { self->dmgteam = gi.TagMalloc(8*sizeof(char), TAG_LEVEL); // strncpy(self->dmgteam,"player"); Q_strncpyz(self->dmgteam,"player", 8); } } // Lazarus: Max range for sight/attack if(st.distance) self->monsterinfo.max_range = max(500,st.distance); else self->monsterinfo.max_range = 1280; // Q2 default is 1000. We're mean. // Lazarus: We keep SIGHT to mean what old AMBUSH does, and AMBUSH additionally // now means don't play idle sounds /* if ((self->spawnflags & MONSTER_SIGHT) && !(self->monsterinfo.aiflags & AI_GOOD_GUY)) { self->spawnflags &= ~MONSTER_SIGHT; self->spawnflags |= MONSTER_AMBUSH; } */ if ((self->spawnflags & SF_MONSTER_AMBUSH) && !(self->monsterinfo.aiflags & AI_GOOD_GUY)) self->spawnflags |= SF_MONSTER_SIGHT; // Lazarus: Don't add trigger spawned monsters until they are actually spawned if (!(self->monsterinfo.aiflags & AI_GOOD_GUY) && !(self->spawnflags & SF_MONSTER_TRIGGER_SPAWN)) level.total_monsters++; self->nextthink = level.time + FRAMETIME; self->svflags |= SVF_MONSTER; self->s.renderfx |= RF_FRAMELERP; self->air_finished = level.time + 12; self->use = monster_use; // Lazarus - don't reset max_health unnecessarily if(!self->max_health) self->max_health = self->health; if (self->health < (self->max_health / 2)) self->s.skinnum |= 1; else self->s.skinnum &= ~1; self->clipmask = MASK_MONSTERSOLID; if (self->s.skinnum < 1) // Knightmare added self->s.skinnum = 0; self->deadflag = DEAD_NO; self->svflags &= ~SVF_DEADMONSTER; if(self->monsterinfo.flies > 1.0) { self->s.effects |= EF_FLIES; self->s.sound = gi.soundindex ("infantry/inflies1.wav"); } // Lazarus if(self->health <=0) { self->svflags |= SVF_DEADMONSTER; self->movetype = MOVETYPE_TOSS; self->takedamage = DAMAGE_YES; self->monsterinfo.pausetime = 100000000; self->monsterinfo.aiflags &= ~AI_RESPAWN_FINDPLAYER; if(self->max_health > 0) { // This must be a dead monster who changed levels // via trigger_transition self->nextthink = 0; self->deadflag = DEAD_DEAD; } if(self->s.effects & EF_FLIES && self->monsterinfo.flies <= 1.0) { self->think = M_FliesOff; self->nextthink = level.time + 1 + random()*60; } return true; } else { // make sure red shell is turned off in case medic got confused: self->monsterinfo.aiflags &= ~AI_RESURRECTING; self->svflags &= ~SVF_DEADMONSTER; self->takedamage = DAMAGE_AIM; } if (!self->monsterinfo.checkattack) self->monsterinfo.checkattack = M_CheckAttack; VectorCopy (self->s.origin, self->s.old_origin); if (st.item) { self->item = FindItemByClassname (st.item); if (!self->item) gi.dprintf("%s at %s has bad item: %s\n", self->classname, vtos(self->s.origin), st.item); } // randomize what frame they start on // Lazarus: preserve frame if set for monsters changing levels if (!self->s.frame) { if (self->monsterinfo.currentmove) self->s.frame = self->monsterinfo.currentmove->firstframe + (rand() % (self->monsterinfo.currentmove->lastframe - self->monsterinfo.currentmove->firstframe + 1)); } return true; }
/* * QUAKED monster_flyer (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight */ void SP_monster_flyer(edict_t *self) { if (!self) { return; } if (deathmatch->value) { G_FreeEdict(self); return; } /* fix a map bug in jail5.bsp */ if (!Q_stricmp(level.mapname, "jail5") && (self->s.origin[2] == -104)) { self->targetname = self->target; self->target = NULL; } sound_sight = gi.soundindex("flyer/flysght1.wav"); sound_idle = gi.soundindex("flyer/flysrch1.wav"); sound_pain1 = gi.soundindex("flyer/flypain1.wav"); sound_pain2 = gi.soundindex("flyer/flypain2.wav"); sound_slash = gi.soundindex("flyer/flyatck2.wav"); sound_sproing = gi.soundindex("flyer/flyatck1.wav"); sound_die = gi.soundindex("flyer/flydeth1.wav"); gi.soundindex("flyer/flyatck3.wav"); self->s.modelindex = gi.modelindex("models/monsters/flyer/tris.md2"); VectorSet(self->mins, -16, -16, -24); VectorSet(self->maxs, 16, 16, 16); self->movetype = MOVETYPE_STEP; self->solid = SOLID_BBOX; self->s.sound = gi.soundindex("flyer/flyidle1.wav"); self->health = 50; self->mass = 50; self->pain = flyer_pain; self->die = flyer_die; self->monsterinfo.stand = flyer_stand; self->monsterinfo.walk = flyer_walk; self->monsterinfo.run = flyer_run; self->monsterinfo.attack = flyer_attack; self->monsterinfo.melee = flyer_melee; self->monsterinfo.sight = flyer_sight; self->monsterinfo.idle = flyer_idle; self->monsterinfo.blocked = (void *)flyer_blocked; gi.linkentity(self); self->monsterinfo.currentmove = &flyer_move_stand; self->monsterinfo.scale = MODEL_SCALE; flymonster_start(self); }
//================ //G_ClearSnap // We just run G_SnapFrame, the server just sent the snap to the clients, // it's now time to clean up snap specific data to start the next snap from clean. //================ void G_ClearSnap( void ) { edict_t *ent; game.realtime = trap_Milliseconds(); // level.time etc. might not be real time // clear gametype's clock override gs.gameState.longstats[GAMELONG_CLOCKOVERRIDE] = 0; // clear all events in the snap for( ent = &game.edicts[0]; ENTNUM( ent ) < game.numentities; ent++ ) { if( ISEVENTENTITY( &ent->s ) ) // events do not persist after a snapshot { G_FreeEdict( ent ); continue; } // events only last for a single message ent->s.events[0] = ent->s.events[1] = 0; ent->s.eventParms[0] = ent->s.eventParms[1] = 0; ent->numEvents = 0; ent->eventPriority[0] = ent->eventPriority[1] = qfalse; ent->s.teleported = qfalse; // remove teleported bit. // remove effect bits that are (most likely) added from gametypes ent->s.effects = ( ent->s.effects & (EF_TAKEDAMAGE|EF_CARRIER|EF_FLAG_TRAIL|EF_ROTATE_AND_BOB|EF_STRONG_WEAPON) ); } // recover some info, let players respawn and finally clear the snap structures for( ent = &game.edicts[0]; ENTNUM( ent ) < game.numentities; ent++ ) { if( !GS_MatchPaused() ) { // copy origin to old origin ( this old_origin is for snaps ) if( !( ent->r.svflags & SVF_TRANSMITORIGIN2 ) ) VectorCopy( ent->s.origin, ent->s.old_origin ); G_CheckClientRespawnClick( ent ); } if( GS_MatchPaused() ) ent->s.sound = entity_sound_backup[ENTNUM( ent )]; // clear the snap temp info memset( &ent->snap, 0, sizeof( ent->snap ) ); if( ent->r.client && trap_GetClientState( PLAYERNUM( ent ) ) >= CS_SPAWNED ) { memset( &ent->r.client->resp.snap, 0, sizeof( ent->r.client->resp.snap ) ); // set race stats to invisible ent->r.client->ps.stats[STAT_TIME_SELF] = STAT_NOTSET; ent->r.client->ps.stats[STAT_TIME_BEST] = STAT_NOTSET; ent->r.client->ps.stats[STAT_TIME_RECORD] = STAT_NOTSET; ent->r.client->ps.stats[STAT_TIME_ALPHA] = STAT_NOTSET; ent->r.client->ps.stats[STAT_TIME_BETA] = STAT_NOTSET; } } g_snapStarted = qfalse; }
/* ============== SpawnEntities Creates a server's entity / program execution context by parsing textual entity definitions out of an ent file. ============== */ void SpawnEntities (char *mapname, char *entities, char *spawnpoint) { edict_t *ent; int inhibit; char *com_token; int i; float skill_level; /*freeze*/ static int fStarted = 0; /*freeze*/ skill_level = floor (skill->value); if (skill_level < 0) skill_level = 0; if (skill_level > 3) skill_level = 3; if (skill->value != skill_level) gi.cvar_forceset("skill", va("%f", skill_level)); SaveClientData (); gi.FreeTags (TAG_LEVEL); /*freeze*/ if (fStarted) sl_GameEnd(&gi, level); /*freeze*/ memset (&level, 0, sizeof(level)); memset (g_edicts, 0, game.maxentities * sizeof (g_edicts[0])); strncpy (level.mapname, mapname, sizeof(level.mapname)-1); strncpy (game.spawnpoint, spawnpoint, sizeof(game.spawnpoint)-1); // set client fields on player ents for (i=0 ; i<game.maxclients ; i++) g_edicts[i+1].client = game.clients + i; ent = NULL; inhibit = 0; // parse ents while (1) { // parse the opening brace com_token = COM_Parse (&entities); if (!entities) break; if (com_token[0] != '{') gi.error ("ED_LoadFromFile: found %s when expecting {",com_token); if (!ent) ent = g_edicts; else ent = G_Spawn (); entities = ED_ParseEdict (entities, ent); // yet another map hack if (!Q_stricmp(level.mapname, "command") && !Q_stricmp(ent->classname, "trigger_once") && !Q_stricmp(ent->model, "*27")) ent->spawnflags &= ~SPAWNFLAG_NOT_HARD; // remove things (except the world) from different skill levels or deathmatch if (ent != g_edicts) { if (deathmatch->value) { if ( ent->spawnflags & SPAWNFLAG_NOT_DEATHMATCH ) { G_FreeEdict (ent); inhibit++; continue; } } else { if ( /* ((coop->value) && (ent->spawnflags & SPAWNFLAG_NOT_COOP)) || */ ((skill->value == 0) && (ent->spawnflags & SPAWNFLAG_NOT_EASY)) || ((skill->value == 1) && (ent->spawnflags & SPAWNFLAG_NOT_MEDIUM)) || (((skill->value == 2) || (skill->value == 3)) && (ent->spawnflags & SPAWNFLAG_NOT_HARD)) ) { G_FreeEdict (ent); inhibit++; continue; } } ent->spawnflags &= ~(SPAWNFLAG_NOT_EASY|SPAWNFLAG_NOT_MEDIUM|SPAWNFLAG_NOT_HARD|SPAWNFLAG_NOT_COOP|SPAWNFLAG_NOT_DEATHMATCH); } ED_CallSpawn (ent); } gi.dprintf ("%i entities inhibited\n", inhibit); #ifdef DEBUG i = 1; ent = EDICT_NUM(i); while (i < globals.num_edicts) { if (ent->inuse != 0 || ent->inuse != 1) Com_DPrintf("Invalid entity %d\n", i); i++, ent++; } #endif G_FindTeams (); PlayerTrail_Init (); /*freeze*/ sl_GameStart(&gi, level); { static cvar_t* _log_style_cvar = NULL; if (NULL == _log_style_cvar) _log_style_cvar = gi.cvar("sl_log_style", "0", 0); if (_log_style_cvar && _log_style_cvar->value >= SL_LOG_STYLE_1_2a) fStarted = 1; } /*freeze*/ }
/* =============== Touch_Item =============== */ void Touch_Item (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf) { qboolean taken; float vol; if (!other->client) { if (!ent->playedsound && ent->groundentity) { //gi.dprintf(DEVELOPER_MSG_GAME, "Plonk! %s\n",other->classname); if (ent->item) { //velocity goes from around -250 for normal drop to ~1000 from top of dday2 church stairs //knife ~1 lb 50cal ~50 lbs vol = ((1000+(-1 * ent->velocity[2]))/2000) * ( (ent->item->weight+100)/150 ); if (vol > .9) vol = .9; // gi.dprintf(DEVELOPER_MSG_GAME, "%f %f %f\n", ent->velocity[2], ent->item->weight, vol); // gi.dprintf(DEVELOPER_MSG_GAME, "%f %f %f\n", ((1000+(-1 * ent->velocity[2]))/2000), (ent->item->weight+100)/150, vol); if (ent->item->flags & IT_AMMO || ent->item->position == LOC_GRENADES || ent->item->position == LOC_KNIFE) gi.sound (ent, CHAN_WEAPON, gi.soundindex("weapons/ammodrop.wav"), vol, ATTN_NORM, 0); //gi.positioned_sound (ent->s.origin, g_edicts, CHAN_AUTO, gi.soundindex("weapons/ammodrop.wav"), vol, ATTN_NORM, 0); else if (ent->item->flags & IT_WEAPON) gi.sound (ent, CHAN_WEAPON, gi.soundindex("weapons/gundrop.wav"), vol, ATTN_NORM, 0); //gi.positioned_sound (ent->s.origin, g_edicts, CHAN_AUTO, gi.soundindex("weapons/gundrop.wav"), vol, ATTN_NORM, 0); } ent->playedsound = true; } return; } if (other->health < 1) return; // dead people can't pickup if (!ent->item->pickup) return; // not a grabbable item? if (other->client->resp.autopickup == false && ent->item->classnameb != HGRENADE) return; if (other->client && other->client->resp.mos == MEDIC) { if (!( (ent->item->tag && ent->item->tag == AMMO_TYPE_PISTOL) || (ent->item->position && ent->item->position == LOC_PISTOL) || (ent->item->pickup_name && !Q_stricmp(ent->item->pickup_name,"Knife")) || (ent->item->pickup_name && !Q_stricmp(ent->item->pickup_name,"Helmet")) )) return; } //pbowens: you can only have 1 helmet if (ent->item->pickup_name && !Q_stricmp(ent->item->pickup_name, "Helmet") ) { if (other->client->pers.inventory[ITEM_INDEX(ent->item)]) { // safe_cprintf(other, PRINT_HIGH, "You already have a helmet!\n"); return; } } // you cannot pickup more than 1 team weapon if (ent->item->guninfo && other->client->pers.inventory[ITEM_INDEX(ent->item)]) return; //faf if (ent->item->position != LOC_GRENADES && ent->count > 1 && //faf other->client->pers.inventory[ITEM_INDEX(ent->item)] ) // dont pick up if ammo already //faf return; taken = ent->item->pickup(ent, other); if (taken) { // flash the screen //other->client->bonus_alpha = 0.25; // show icon and name on status bar other->client->ps.stats[STAT_PICKUP_ICON] = gi.imageindex(ent->item->icon); other->client->ps.stats[STAT_PICKUP_STRING] = CS_ITEMS+ITEM_INDEX(ent->item); other->client->pickup_msg_time = level.time + 3.0; // change selected item //if (ent->item->use) // other->client->pers.selected_item = other->client->ps.stats[STAT_SELECTED_ITEM] = ITEM_INDEX(ent->item); gi.sound(other, CHAN_ITEM, gi.soundindex(ent->item->pickup_sound), 1, ATTN_NORM, 0); } if (!(ent->spawnflags & ITEM_TARGETS_USED)) { G_UseTargets (ent, other); ent->spawnflags |= ITEM_TARGETS_USED; } if (!taken) return; if (!((coop->value) && (ent->item->flags & IT_STAY_COOP)) || (ent->spawnflags & (DROPPED_ITEM | DROPPED_PLAYER_ITEM))) { if (ent->flags & FL_RESPAWN) ent->flags &= ~FL_RESPAWN; else G_FreeEdict (ent); } }
void Weapon_Sandbag_Fire (edict_t *ent) { edict_t *sandbag; ent->client->ps.gunframe++; if (ent->client->resp.team_on->index == 0) { if (allied_sandbags >= sandbaglimit->value) { safe_centerprintf(ent, "Your team is at the sandbag limit!\n"); return; } } else if (ent->client->resp.team_on->index == 1) { if (axis_sandbags >= sandbaglimit->value) { safe_centerprintf(ent, "Your team is at the sandbag limit!\n"); return; } } if (VectorCompare (ent->client->sandbag_pos , vec3_origin)) { safe_centerprintf(ent, "There's no space for sandbags there!\n"); return; } ent->client->pers.inventory[ITEM_INDEX(FindItem("Sandbags"))]--; sandbag = G_Spawn(); VectorCopy (ent->client->sandbag_preview->mins, sandbag->mins); VectorCopy (ent->client->sandbag_preview->maxs, sandbag->maxs); VectorCopy (ent->client->sandbag_preview->s.angles, sandbag->s.angles); sandbag->classnameb = SANDBAGS; sandbag->movetype = MOVETYPE_TOSS; sandbag->solid = SOLID_BBOX; sandbag->s.modelindex = gi.modelindex ("models/objects/sandbag/tris.md2"); sandbag->think = sandbag_think; sandbag->nextthink = level.time +.1; // ent->s.frame = rand() % 16; // ent->s.frame = 1; sandbag->mass = 300; sandbag->touch = sandbag_touch; sandbag->health = 2000; sandbag->takedamage = DAMAGE_YES; sandbag->die = sandbag_die; sandbag->s.skinnum = 0; sandbag->s.frame = 0; // VectorSet (sandbag->mins, -19, -9, -10); // VectorSet (sandbag->maxs, 19, 9, 8); VectorCopy (ent->client->sandbag_pos, sandbag->s.origin); sandbag->clipmask = MASK_SHOT; sandbag->spawnflags = 1; if (ent->client->resp.team_on) sandbag->obj_owner = ent->client->resp.team_on->index; if (ent->client->resp.team_on->index == 0) allied_sandbags++; else if (ent->client->resp.team_on->index == 1) axis_sandbags++; sandbag->obj_time = level.time; gi.linkentity (sandbag); if (ent->client->pers.inventory[ITEM_INDEX(FindItem("Sandbags"))] ==0) { ent->client->weaponstate=WEAPON_LOWER; ent->client->ps.gunframe = 20; Use_Weapon (ent, FindItem("fists")); return; } G_FreeEdict (ent->client->sandbag_preview); ent->client->sandbag_preview = NULL; }
void cash_kill( edict_t *self ) { num_cash_items--; G_FreeEdict( self ); }
static void func_explosive_explode( edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, const vec3_t point ) { vec3_t origin, bakorigin; vec3_t chunkorigin; vec3_t size; int count; int mass; // do not explode unless visible if( self->r.svflags & SVF_NOCLIENT ) return; self->takedamage = DAMAGE_NO; // bmodel origins are (0 0 0), we need to adjust that here VectorCopy( self->s.origin, bakorigin ); VectorScale( self->r.size, 0.5, size ); VectorAdd( self->r.absmin, size, origin ); VectorCopy( origin, self->s.origin ); if( self->projectileInfo.maxDamage ) G_RadiusDamage( self, attacker, NULL, NULL, MOD_EXPLOSIVE ); VectorSubtract( self->s.origin, inflictor->s.origin, self->velocity ); VectorNormalize( self->velocity ); VectorScale( self->velocity, 150, self->velocity ); // start chunks towards the center VectorScale( size, 0.5, size ); mass = self->projectileInfo.radius * 0.75; if( !mass ) mass = 75; // big chunks if( self->count > 0 ) { if( mass >= 100 ) { count = mass / 100; if( count > 8 ) count = 8; while( count-- ) { chunkorigin[0] = origin[0] + crandom() * size[0]; chunkorigin[1] = origin[1] + crandom() * size[1]; chunkorigin[2] = origin[2] + crandom() * size[2]; ThrowDebris( self, self->count, 1, chunkorigin ); } } } // small chunks if( self->viewheight > 0 ) { count = mass / 25; if( count > 16 ) count = 16; if( count < 1 ) count = 1; while( count-- ) { chunkorigin[0] = origin[0] + crandom() * size[0]; chunkorigin[1] = origin[1] + crandom() * size[1]; chunkorigin[2] = origin[2] + crandom() * size[2]; ThrowDebris( self, self->viewheight, 2, chunkorigin ); } } G_UseTargets( self, attacker ); if( self->projectileInfo.maxDamage ) { edict_t *explosion; explosion = G_Spawn(); VectorCopy( self->s.origin, explosion->s.origin ); explosion->projectileInfo = self->projectileInfo; BecomeExplosion1( explosion ); } if( self->use == NULL ) { G_FreeEdict( self ); return; } self->health = self->max_health; self->r.solid = SOLID_NOT; self->r.svflags |= SVF_NOCLIENT; VectorCopy( bakorigin, self->s.origin ); VectorClear( self->velocity ); GClip_LinkEntity( self ); }
void SpawnTotem(edict_t *ent, int abilityID) { int talentLevel, cost=TOTEM_COST; edict_t *totem; int totemType; vec3_t start;//GHz 4.32 // cost is doubled if you are a flyer or cacodemon below skill level 5 if ((ent->mtype == MORPH_FLYER && ent->myskills.abilities[FLYER].current_level < 5) || (ent->mtype == MORPH_CACODEMON && ent->myskills.abilities[CACODEMON].current_level < 5)) cost *= 2; if(!V_CanUseAbilities(ent, abilityID, cost, true)) return; if (ctf->value && abilityID == FIRE_TOTEM && (CTF_DistanceFromBase(ent, NULL, CTF_GetEnemyTeam(ent->teamnum)) < CTF_BASE_DEFEND_RANGE)) { safe_cprintf(ent, PRINT_HIGH, "Can't build in enemy base!\n"); return; } //Determine the totem type. switch(abilityID) { case FIRE_TOTEM: totemType = TOTEM_FIRE; break; case WATER_TOTEM: totemType = TOTEM_WATER; break; case AIR_TOTEM: totemType = TOTEM_AIR; break; case EARTH_TOTEM: totemType = TOTEM_EARTH; break; case DARK_TOTEM: totemType = TOTEM_DARKNESS; break; case NATURE_TOTEM: totemType = TOTEM_NATURE; break; default: return; } //Can't create too many totems. if(ent->totem1) { //Can't have more than one totem without the talent. /*if(getTalentLevel(ent, TALENT_TOTEM) < 1) { safe_cprintf(ent, PRINT_HIGH, "You already have a totem active.\n"); return; } //Can't have more than two totems. else*/ if(ent->totem2) { safe_cprintf(ent, PRINT_HIGH, "You already have two totems active.\n"); return; } //Can't have two totems of opposite alignment. else { int opposite = 0; switch(ent->totem1->mtype) { case TOTEM_FIRE: opposite = TOTEM_WATER; break; case TOTEM_WATER: opposite = TOTEM_FIRE; break; case TOTEM_AIR: opposite = TOTEM_EARTH; break; case TOTEM_EARTH: opposite = TOTEM_AIR; break; case TOTEM_DARKNESS: opposite = TOTEM_NATURE; break; case TOTEM_NATURE: opposite = TOTEM_DARKNESS; break; } if(totemType == opposite) { safe_cprintf(ent, PRINT_HIGH, "You can't create two totems of opposite elemental alignment.\n"); return; } else if(totemType == ent->totem1->mtype) { safe_cprintf(ent, PRINT_HIGH, "You can't create totems of the same type.\n"); return; } } } //Drop a totem. totem = DropTotem(ent); totem->mtype = totemType; totem->monsterinfo.level = ent->myskills.abilities[abilityID].current_level; totem->classname = "totem"; /*totem->owner =*/ totem->activator = ent; totem->think = totem_general_think; totem->touch = totem_touch; totem->nextthink = level.time + FRAMETIME*2; totem->delay = level.time + 0.5; totem->die = totem_die; //TODO: update this with the new model. totem->s.modelindex = gi.modelindex("models/items/mega_h/tris.md2"); //totem->s.angles[ROLL] = 270; VectorSet (totem->mins, -8, -8, -12); VectorSet (totem->maxs, 8, 8, 16); VectorCopy(ent->s.origin, totem->s.origin); totem->health = TOTEM_HEALTH_BASE + TOTEM_HEALTH_MULT * totem->monsterinfo.level; //Talent: Totemic Focus - increases totem health if((talentLevel = getTalentLevel(ent, TALENT_TOTEM)) > 0) totem->health *= 1 + 0.1666 * talentLevel; if (totemType == TOTEM_FIRE) { // fire totem is much tougher totem->health *= 2; // fire totem has a longer delay totem->delay = level.time + 2.0; } totem->max_health = totem->health*2; //Not sure if this stuff is needed (Archer) totem->svflags |= SVF_MONSTER; totem->takedamage = DAMAGE_AIM; totem->clipmask = MASK_MONSTERSOLID; //Back to stuff we need totem->mass = 200; totem->movetype = MOVETYPE_TOSS;//MOVETYPE_WALK; totem->deadflag = DEAD_NO; totem->svflags &= ~SVF_DEADMONSTER; totem->solid = SOLID_BBOX; //Graphical effects //TODO: update this to make it look better. totem->s.effects |= EF_PLASMA | EF_COLOR_SHELL | EF_SPHERETRANS; switch(totemType) { case TOTEM_FIRE: totem->s.effects |= 262144; //red radius light totem->s.renderfx |= RF_SHELL_RED; break; case TOTEM_WATER: totem->s.effects |= 524288; //blue radius light totem->s.renderfx |= RF_SHELL_CYAN; break; case TOTEM_AIR: totem->s.effects |= 64; //bright light radius totem->s.renderfx |= RF_SHELL_RED | RF_SHELL_BLUE | RF_SHELL_GREEN; break; case TOTEM_EARTH: totem->s.renderfx |= RF_SHELL_YELLOW; break; case TOTEM_DARKNESS: totem->s.effects |= 2147483648; //strange darkness effect //totem->s.renderfx |= RF_SHELL_RED | RF_SHELL_BLUE; break; case TOTEM_NATURE: totem->s.effects |= 128; //green radius light totem->s.renderfx |= RF_SHELL_GREEN; break; } //GHz 4.32 if (!G_GetSpawnLocation(ent, 64, totem->mins, totem->maxs, start)) { G_FreeEdict(totem); return; } VectorCopy(start, totem->s.origin); gi.linkentity(totem); //GHz if(!ent->totem1) ent->totem1 = totem; else ent->totem2 = totem; ent->client->pers.inventory[ITEM_INDEX(Fdi_POWERCUBE)] -= cost; // calling entity made a sound, used to alert monsters ent->lastsound = level.framenum; ent->client->ability_delay = level.time + 1.3; }
//QUAKED light_mine (0 1 0) (-2 -2 -12) (2 2 12) void SP_light_mine( edict_t *ent ) { G_FreeEdict( ent ); }
/*QUAKED monster_brain (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight */ void SP_monster_brain (edict_t *self) { if (deathmatch->value) { G_FreeEdict (self); return; } sound_chest_open = gi.soundindex ("brain/brnatck1.wav"); sound_tentacles_extend = gi.soundindex ("brain/brnatck2.wav"); sound_tentacles_retract = gi.soundindex ("brain/brnatck3.wav"); sound_death = gi.soundindex ("brain/brndeth1.wav"); sound_idle1 = gi.soundindex ("brain/brnidle1.wav"); sound_idle2 = gi.soundindex ("brain/brnidle2.wav"); sound_idle3 = gi.soundindex ("brain/brnlens1.wav"); sound_pain1 = gi.soundindex ("brain/brnpain1.wav"); sound_pain2 = gi.soundindex ("brain/brnpain2.wav"); sound_sight = gi.soundindex ("brain/brnsght1.wav"); sound_search = gi.soundindex ("brain/brnsrch1.wav"); sound_melee1 = gi.soundindex ("brain/melee1.wav"); sound_melee2 = gi.soundindex ("brain/melee2.wav"); sound_melee3 = gi.soundindex ("brain/melee3.wav"); self->movetype = MOVETYPE_STEP; self->solid = SOLID_BBOX; self->s.modelindex = gi.modelindex ("models/monsters/brain/tris.md2"); VectorSet (self->mins, -16, -16, -24); VectorSet (self->maxs, 16, 16, 32); self->health = 300; self->gib_health = -150; self->mass = 400; self->pain = brain_pain; self->die = brain_die; self->monsterinfo.stand = brain_stand; self->monsterinfo.walk = brain_walk; self->monsterinfo.run = brain_run; // PMM self->monsterinfo.dodge = M_MonsterDodge; self->monsterinfo.duck = brain_duck; self->monsterinfo.unduck = monster_duck_up; // self->monsterinfo.dodge = brain_dodge; // pmm // self->monsterinfo.attack = brain_attack; self->monsterinfo.melee = brain_melee; self->monsterinfo.sight = brain_sight; self->monsterinfo.search = brain_search; self->monsterinfo.idle = brain_idle; self->monsterinfo.power_armor_type = POWER_ARMOR_SCREEN; self->monsterinfo.power_armor_power = 100; gi.linkentity (self); self->monsterinfo.currentmove = &brain_move_stand; self->monsterinfo.scale = MODEL_SCALE; walkmonster_start (self); }
//QUAKED misc_model (1 .5 .25) (-16 -16 -16) (16 16 16) //Generic placeholder for inserting .md3 models in game. Requires compilation of map geometry to be added to level. //-------- KEYS -------- //angle: direction in which model will be oriented. //model : path/name of model to use (eg: models/mapobjects/teleporter/teleporter.md3). void SP_misc_model( edict_t *ent ) { G_FreeEdict( ent ); }
/* ================= debris ================= */ void debris_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) { G_FreeEdict (self); }
/* * @brief Creates a server's entity / program execution context by * parsing textual entity definitions out of an ent file. */ void G_SpawnEntities(const char *name, const char *entities) { g_edict_t *ent; int32_t inhibit; char *com_token; int32_t i; gi.FreeTag(Z_TAG_GAME_LEVEL); memset(&g_level, 0, sizeof(g_level)); memset(g_game.edicts, 0, g_max_entities->value * sizeof(g_game.edicts[0])); g_strlcpy(g_level.name, name, sizeof(g_level.name)); // set client fields on player ents for (i = 0; i < sv_max_clients->integer; i++) { g_game.edicts[i + 1].client = g_game.clients + i; } ge.num_edicts = sv_max_clients->integer + 1; ent = NULL; inhibit = 0; // parse ents while (true) { // parse the opening brace com_token = ParseToken(&entities); if (!entities) break; if (com_token[0] != '{') gi.Error("Found \"%s\" when expecting \"{\"", com_token); if (!ent) ent = g_game.edicts; else ent = G_Spawn(); entities = G_ParseEntity(entities, ent); // some ents don't belong in deathmatch if (ent != g_game.edicts) { // legacy levels may require this if (ent->locals.spawn_flags & SF_NOT_DEATHMATCH) { G_FreeEdict(ent); inhibit++; continue; } // emits and models are client sided if (!g_strcmp0(ent->class_name, "misc_emit") || !g_strcmp0(ent->class_name, "misc_model")) { G_FreeEdict(ent); inhibit++; continue; } // lights aren't even used if (!g_strcmp0(ent->class_name, "light") || !g_strcmp0(ent->class_name, "light_spot")) { G_FreeEdict(ent); inhibit++; continue; } // strip away unsupported flags ent->locals.spawn_flags &= ~(SF_NOT_EASY | SF_NOT_MEDIUM | SF_NOT_HARD | SF_NOT_COOP | SF_NOT_DEATHMATCH); } // retain the map-specified origin for respawns VectorCopy(ent->s.origin, ent->locals.map_origin); G_SpawnEntity(ent); if (g_level.gameplay > 1 && ent->locals.item) { // now that we've spawned them, hide them ent->sv_flags |= SVF_NO_CLIENT; ent->solid = SOLID_NOT; ent->locals.next_think = 0; } } gi.Debug("%i entities inhibited\n", inhibit); G_InitEntityTeams(); G_InitMedia(); G_ResetTeams(); G_ResetVote(); }
/*QUAKED func_explosive (0 .5 .8) ? Trigger_Spawn ANIMATED ANIMATED_FAST Any brush that you want to explode or break apart. If you want an ex0plosion, set dmg and it will do a radius explosion of that amount at the center of the bursh. If targeted it will not be shootable. health defaults to 100. mass defaults to 75. This determines how much debris is emitted when it explodes. You get one large chunk per 100 of mass (up to 8) and one small chunk per 25 of mass (up to 16). So 800 gives the most. */ void func_explosive_explode (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) { vec3_t origin; vec3_t chunkorigin; vec3_t size; int count; int mass; // bmodel origins are (0 0 0), we need to adjust that here VectorScale (self->size, 0.5, size); VectorAdd (self->absmin, size, origin); VectorCopy (origin, self->s.origin); self->takedamage = DAMAGE_NO; if (self->dmg) T_RadiusDamage (self, attacker, self->dmg, NULL, self->dmg+40, MOD_EXPLOSIVE); VectorSubtract (self->s.origin, inflictor->s.origin, self->velocity); VectorNormalize (self->velocity); VectorScale (self->velocity, 150, self->velocity); // start chunks towards the center VectorScale (size, 0.5, size); mass = self->mass; if (!mass) mass = 75; // big chunks if (mass >= 100) { count = mass / 100; if (count > 8) count = 8; while(count--) { chunkorigin[0] = origin[0] + crandom() * size[0]; chunkorigin[1] = origin[1] + crandom() * size[1]; chunkorigin[2] = origin[2] + crandom() * size[2]; ThrowDebris (self, "models/objects/debris1/tris.md2", 1, chunkorigin); } } // small chunks count = mass / 25; if (count > 16) count = 16; while(count--) { chunkorigin[0] = origin[0] + crandom() * size[0]; chunkorigin[1] = origin[1] + crandom() * size[1]; chunkorigin[2] = origin[2] + crandom() * size[2]; ThrowDebris (self, "models/objects/debris2/tris.md2", 2, chunkorigin); } G_UseTargets (self, attacker); if (self->dmg) BecomeExplosion1 (self); else G_FreeEdict (self); }
void SP_misc_viper (edict_t *ent) { if (!ent->target) { gi.dprintf ("misc_viper without a target at %s\n", vtos(ent->absmin)); G_FreeEdict (ent); return; } if (ent->spawnflags & 1) { ent->s.effects |= EF_ROCKET; ent->spawnflags &= ~1; // turn this off so that it doesn't mess up the trains } if (!ent->speed) ent->speed = 300; ent->movetype = MOVETYPE_PUSH; if (ent->spawnflags & 2) { ent->solid = SOLID_BBOX; } else { ent->solid = SOLID_NOT; } if(ent->model) { ent->s.modelindex = gi.modelindex (ent->model); } else { ent->s.modelindex = gi.modelindex ("models/ships/viper/tris.md2"); } if(ent->model2) { ent->s.modelindex2 = gi.modelindex (ent->model2); } if(ent->model3) { ent->s.modelindex3 = gi.modelindex (ent->model3); } if(ent->model4) { ent->s.modelindex4 = gi.modelindex (ent->model4); } if (!(ent->spawnflags & 4)) { VectorSet (ent->mins, -16, -16, 0); VectorSet (ent->maxs, 16, 16, 32); } ent->think = func_train_find; ent->nextthink = level.time + FRAMETIME; ent->use = misc_viper_use; ent->svflags |= SVF_NOCLIENT; ent->moveinfo.accel = ent->moveinfo.decel = ent->moveinfo.speed = ent->speed; gi.linkentity (ent); }
/* ============== SpawnEntities Creates a server's entity / program execution context by parsing textual entity definitions out of an ent file. ============== */ void SpawnEntities (char *mapname, char *entities, char *spawnpoint) { edict_t *ent; int inhibit; char *com_token; int i; float skill_level; skill_level = floor (skill->value); if (skill_level < 0) skill_level = 0; if (skill_level > 3) skill_level = 3; if (skill->value != skill_level) gi.cvar_forceset("skill", va("%f", skill_level)); SaveClientData (); gi.FreeTags (TAG_LEVEL); memset (&level, 0, sizeof(level)); memset (g_edicts, 0, game.maxentities * sizeof (g_edicts[0])); strncpy (level.mapname, mapname, sizeof(level.mapname)-1); strncpy (game.spawnpoint, spawnpoint, sizeof(game.spawnpoint)-1); // set client fields on player ents for (i=0 ; i<game.maxclients ; i++) g_edicts[i+1].client = game.clients + i; ent = NULL; inhibit = 0; // parse ents while (1) { // parse the opening brace com_token = COM_Parse (&entities); if (!entities) break; if (com_token[0] != '{') gi.error ("ED_LoadFromFile: found %s when expecting {",com_token); if (!ent) ent = g_edicts; else ent = G_Spawn (); entities = ED_ParseEdict (entities, ent); // yet another map hack if (!stricmp(level.mapname, "command") && !stricmp(ent->classname, "trigger_once") && !stricmp(ent->model, "*27")) ent->spawnflags &= ~SPAWNFLAG_NOT_HARD; // remove things (except the world) from different skill levels or deathmatch if (ent != g_edicts) { if (deathmatch->value) { if ( ent->spawnflags & SPAWNFLAG_NOT_DEATHMATCH ) { G_FreeEdict (ent); inhibit++; continue; } } else { if ( /* ((coop->value) && (ent->spawnflags & SPAWNFLAG_NOT_COOP)) || */ ((skill->value == 0) && (ent->spawnflags & SPAWNFLAG_NOT_EASY)) || ((skill->value == 1) && (ent->spawnflags & SPAWNFLAG_NOT_MEDIUM)) || (((skill->value == 2) || (skill->value == 3)) && (ent->spawnflags & SPAWNFLAG_NOT_HARD)) ) { G_FreeEdict (ent); inhibit++; continue; } } ent->spawnflags &= ~(SPAWNFLAG_NOT_EASY|SPAWNFLAG_NOT_MEDIUM|SPAWNFLAG_NOT_HARD|SPAWNFLAG_NOT_COOP|SPAWNFLAG_NOT_DEATHMATCH); } ED_CallSpawn (ent); } gi.dprintf ("%i entities inhibited\n", inhibit); G_FindTeams (); PlayerTrail_Init (); //ZOID CTFSpawn(); //ZOID }
/*QUAKED target_crosslevel_trigger (.5 .5 .5) (-8 -8 -8) (8 8 8) trigger1 trigger2 trigger3 trigger4 trigger5 trigger6 trigger7 trigger8 Once this trigger is touched/used, any trigger_crosslevel_target with the same trigger number is automatically used when a level is started within the same unit. It is OK to check multiple triggers. Message, delay, target, and killtarget also work. */ void trigger_crosslevel_trigger_use (edict_t *self, edict_t *other, edict_t *activator) { game.serverflags |= self->spawnflags; G_FreeEdict (self); }
void pendulum_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point) { // Mostly copied from func_explosive_explode. We can't use that function because // the origin is a bit different. vec3_t origin; vec3_t forward, left, up; vec3_t chunkorigin; vec3_t size; int count; int mass; // Particles originate from business end of pendulum AngleVectors(self->s.angles, forward, left, up); VectorScale(forward, self->move_origin[0], forward); VectorScale(left, -self->move_origin[1], left); VectorScale(up, self->move_origin[2], up); VectorAdd(self->s.origin, forward, origin); VectorAdd(origin, left, origin); VectorAdd(origin, up, origin); self->mass *= 2; self->takedamage = DAMAGE_NO; VectorSubtract(origin, self->enemy->s.origin, self->velocity); VectorNormalize(self->velocity); VectorScale(self->velocity, 150, self->velocity); // start chunks towards the center VectorScale(size, 0.5, size); mass = self->mass; if (!mass) { mass = 75; } // big chunks if (mass >= 100) { count = mass / 100; if (count > 8) { count = 8; } while (count--) { chunkorigin[0] = origin[0] + crandom() * size[0]; chunkorigin[1] = origin[1] + crandom() * size[1]; chunkorigin[2] = origin[2] + crandom() * size[2]; ThrowDebris(self, "models/objects/debris1/tris.md2", 1, chunkorigin, 0, 0); } } // small chunks count = mass / 25; if (count > 16) { count = 16; } while (count--) { chunkorigin[0] = origin[0] + crandom() * size[0]; chunkorigin[1] = origin[1] + crandom() * size[1]; chunkorigin[2] = origin[2] + crandom() * size[2]; ThrowDebris(self, "models/objects/debris2/tris.md2", 2, chunkorigin, 0, 0); } G_FreeEdict(self); }
/*QUAKED dm_props_banner (.5 0 1) (-4 -4 -4) (4 4 4) Temp banner for teamplay style = team (1 / 2) scale = scale the size up/down (2 = double size) model="models\props\temp\triangle\small.md2" */ void SP_dm_props_banner (edict_t *self) { // vec3_t end, bestnorm, bestend; // float bestdist; // int x,y; // trace_t tr; if (!deathmatch_value || !teamplay->value) { // remove G_FreeEdict (self); return; } if (!self->style) { gi.dprintf( "%s has invalid style (should be 1 or 2) at %s\n", self->classname, vtos(self->s.origin) ); G_FreeEdict (self); return; } /* // trace a line back, to get the wall, then go out { bestdist = 9999; for (x=-256; x<300; x+= 256) { VectorCopy( self->s.origin, end ); end[0] = self->s.origin[0] + x; tr = gi.trace( self->s.origin, NULL, NULL, end, NULL, MASK_SOLID ); if (tr.fraction < bestdist) { VectorCopy( tr.plane.normal, bestnorm ); VectorCopy( tr.endpos, bestend ); bestdist = tr.fraction; } } for (y=-256; y<300; y+= 256) { VectorCopy( self->s.origin, end ); end[1] = self->s.origin[1] + y; tr = gi.trace( self->s.origin, NULL, NULL, end, NULL, MASK_SOLID ); if (tr.fraction < bestdist) { VectorCopy( tr.plane.normal, bestnorm ); VectorCopy( tr.endpos, bestend ); bestdist = tr.fraction; } } vectoangles( bestnorm, self->s.angles ); VectorMA( bestend, 40 * self->cast_info.scale, bestnorm, self->s.origin ); } */ // Ridah, 1-jun-99, use flag models for now #if 1 { void think_flag (edict_t *self); // self->solid = SOLID_BBOX; self->movetype = MOVETYPE_NONE; if (self->style == 2) { self->model = "models/props/flag/flag1.md2"; } else { self->model = "models/props/flag/flag3.md2"; } self->s.modelindex = gi.modelindex (self->model); self->s.renderfx2 |= RF2_NOSHADOW; self->s.renderfx |= RF_MINLIGHT; if (!self->cast_info.scale) self->cast_info.scale = 1; self->s.scale = (self->cast_info.scale - 1); // VectorMA( bestend, 40 * self->cast_info.scale, bestnorm, self->s.origin ); self->cast_info.scale *= 0.3; gi.linkentity (self); self->s.effects |= EF_ANIM_ALLFAST_NEW; self->s.renderfx2 |= RF2_MODULUS_FRAME; self->s.renderfx2 |= RDF_NOLERP; // Disabled, doesn't animate much, and uses bandwidth // self->nextthink = level.time + FRAMETIME *2; // self->think = think_flag; } #else // TRIANGULAR ROTATING ICONS self->solid = SOLID_NOT; self->movetype = MOVETYPE_NONE; self->s.skinnum = self->style - 1; self->s.renderfx2 |= RF2_NOSHADOW; self->s.renderfx |= RF_MINLIGHT; if (!self->cast_info.scale) self->cast_info.scale = 1; self->s.scale = self->cast_info.scale - 1; self->s.modelindex = gi.modelindex ("models/props/temp/triangle/small.md2"); gi.linkentity (self); { edict_t *arm; arm = G_Spawn(); arm->solid = self->solid; arm->movetype = self->movetype; arm->s.renderfx2 |= RF2_NOSHADOW; arm->s.scale = self->s.scale; VectorCopy( self->s.origin, arm->s.origin ); VectorCopy( self->s.angles, arm->s.angles ); arm->s.modelindex = gi.modelindex ("models/props/temp/triangle/arm.md2"); gi.linkentity (arm); } VectorCopy( self->s.angles, self->last_step_pos ); VectorClear( self->move_angles ); #endif }
void Think_Delay (edict_t *ent) { G_UseTargets (ent, ent->activator); G_FreeEdict (ent); }
/* ================ droptofloor ================ */ void droptofloor (edict_t *ent) { trace_t tr; vec3_t dest; float *v; v = tv(-15,-15,-15); VectorCopy (v, ent->mins); v = tv(15,15,15); VectorCopy (v, ent->maxs); if (ent->model) gi.setmodel (ent, ent->model); else gi.setmodel (ent, ent->item->world_model); ent->solid = SOLID_TRIGGER; ent->movetype = MOVETYPE_TOSS; ent->touch = Touch_Item; v = tv(0,0,-128); VectorAdd (ent->s.origin, v, dest); tr = gi.trace (ent->s.origin, ent->mins, ent->maxs, dest, ent, MASK_SOLID); if (tr.startsolid) { gi.dprintf(DEVELOPER_MSG_GAME, "droptofloor: %s startsolid at %s\n", ent->classname, vtos(ent->s.origin)); G_FreeEdict (ent); return; } VectorCopy (tr.endpos, ent->s.origin); if (ent->team) { ent->flags &= ~FL_TEAMSLAVE; ent->chain = ent->teamchain; ent->teamchain = NULL; ent->svflags |= SVF_NOCLIENT; ent->solid = SOLID_NOT; if (ent == ent->teammaster) { ent->nextthink = level.time + FRAMETIME; ent->think = DoRespawn; } } if (ent->spawnflags & ITEM_NO_TOUCH) { ent->solid = SOLID_BBOX; ent->touch = NULL; ent->s.effects &= ~EF_ROTATE; ent->s.renderfx &= ~RF_GLOW; } if (ent->spawnflags & ITEM_TRIGGER_SPAWN) { ent->svflags |= SVF_NOCLIENT; ent->solid = SOLID_NOT; ent->use = Use_Item; } gi.linkentity (ent); }