void LoadMap(void) { // Need to do this anyway, otherwise teleporters will be broken CreateItemMarkers(); if (!(isRACE () || isCTF ())) { // If we have a .bot file, use that if (LoadBotRoutingFromFile ()) { map_supported = true; CustomiseFrogbotMap (); AssignVirtualGoals (); AllMarkersLoaded (); return; } } // At this point it's an unsupported map CustomiseFrogbotMap (); if (FrogbotOptionEnabled (FB_OPTION_EDITOR_MODE)) { gedict_t* e; // We don't want spawnpoint markers or powerups to mess with colours for (e = world; (e = nextent (e)); ) { e->s.v.effects = (int)e->s.v.effects & ~(EF_BLUE | EF_GREEN | EF_RED); } AssignGoalNumbers (); } }
/* ============ T_RadiusDamage ============ */ void T_RadiusDamage( gedict_t * inflictor, gedict_t * attacker, float damage, gedict_t * ignore, deathType_t dtype ) { float points; gedict_t *head; vec3_t org; head = trap_findradius( world, inflictor->s.v.origin, damage + 40 ); while ( head ) { if ( head != ignore ) { if ( head->s.v.takedamage ) { org[0] = inflictor->s.v.origin[0] - ( head->s.v.origin[0] + ( head->s.v.mins[0] + head->s.v.maxs[0] ) * 0.5 ); org[1] = inflictor->s.v.origin[1] - ( head->s.v.origin[1] + ( head->s.v.mins[1] + head->s.v.maxs[1] ) * 0.5 ); org[2] = inflictor->s.v.origin[2] - ( head->s.v.origin[2] + ( head->s.v.mins[2] + head->s.v.maxs[2] ) * 0.5 ); points = 0.5 * vlen( org ); if ( points < 0 ) points = 0; points = damage - points; if ( head == attacker ) points = points * 0.5; // no out of water discharge damage if k_dis 2 else if ( cvar("k_dis") == 2 && dtLG_DIS == dtype && !head->s.v.waterlevel ) points = 0; if ( points > 0 ) { if ( CanDamage( head, inflictor ) ) { head->deathtype = dtype; dmg_is_splash = 1; // mark damage as splash if ( cvar("k_instagib") || isRACE() ) // in instagib splash applied to inflictor only, for coil jump { if ( head == attacker ) T_Damage( head, inflictor, attacker, points ); } else { // shamblers only take half damage from rocket/grenade explosions if ( streq(head->s.v.classname, "monster_shambler") && !cvar("k_bloodfest") ) points = points / 2; T_Damage( head, inflictor, attacker, points ); } dmg_is_splash = 0; // unmark splash } } } } head = trap_findradius( head, inflictor->s.v.origin, damage + 40 ); } }
void GibPlayer() { qbool bloodfest_round_connect = ( k_bloodfest && !self->ready ); // in case of bloodfest and connecion during round. gedict_t *p; self->vw_index = 0; if ( isRACE() || bloodfest_round_connect ) ThrowHead( "", self->s.v.health ); else ThrowHead( "progs/h_player.mdl", self->s.v.health ); if ( bloodfest_round_connect ) return; // do not spawn sounds and gibs, preventing abuse. if( match_in_progress == 2 ) { ThrowGib( "progs/gib1.mdl", self->s.v.health ); ThrowGib( "progs/gib2.mdl", self->s.v.health ); ThrowGib( "progs/gib3.mdl", self->s.v.health ); } if ( isRACE() && race.status ) return; // spawn temporary entity. p = spawn(); setorigin( p, PASSVEC3( self->s.v.origin ) ); p->s.v.nextthink = g_globalvars.time + 0.1; p->think = ( func_t ) SUB_Remove; if ( TELEDEATH( self ) ) { sound( p, CHAN_VOICE, "player/teledth1.wav", 1, ATTN_NONE ); } else { sound( p, CHAN_VOICE, (g_random() < 0.5 ? "player/gib.wav" : "player/udeath.wav"), 1, ATTN_NONE ); } }
void ToggleFallBunny () { if (match_in_progress) { return; } if (isRACE()) { G_sprint(self, 2, "Command blocked because race mode is active\n"); return; } if ( k_yawnmode ) { G_sprint(self, 2, "Command blocked because yawnmode is active\n"); return; } cvar_toggle_msg( self, "k_fallbunny", redtext("fallbunny") ); }
void T_Damage( gedict_t * targ, gedict_t * inflictor, gedict_t * attacker, float damage ) { vec3_t dir; gedict_t *oldself; float save; float take; int i, c1 = 8, c2 = 4, hdp; float dmg_dealt = 0, virtual_take = 0; float non_hdp_damage; // save damage before handicap apply for kickback calculation float native_damage = damage; // save damage before apply any modificator char *attackerteam, *targteam, *attackername, *victimname; qbool tp4teamdmg = false; //midair and instagib float playerheight = 0, midheight = 0; qbool midair = false, inwater = false, do_dmg = false, rl_dmg = false, stomp_dmg = false; // can't apply damage to dead if ( !targ->s.v.takedamage || ISDEAD( targ ) ) return; // can't damage other players in race if ( isRACE() && ( attacker != targ ) ) { if ( targ->ct == ctPlayer || attacker->ct == ctPlayer ) return; } // ignore almost all damage in CA while coutdown if ( isCA() && match_in_progress && ra_match_fight != 2 ) { if ( !( dtTELE1 == targ->deathtype // always do tele damage || dtTELE2 == targ->deathtype // always do tele damage || dtTELE3 == targ->deathtype // always do tele damage || dtSUICIDE == targ->deathtype // do suicide damage anyway ) ) return; } // used by buttons and triggers to set activator for target firing damage_attacker = attacker; damage_inflictor = inflictor; attackerteam = getteam( attacker ); targteam = getteam( targ ); if ( (int)cvar("k_midair") ) midair = true; // in bloodfest boss damage factor. if ( k_bloodfest && attacker->bloodfest_boss ) { damage *= 4; } // check for quad damage powerup on the attacker // midair quad makes rockets fast, but no change to damage if ( attacker->super_damage_finished > g_globalvars.time && strneq( inflictor->s.v.classname, "door" ) && dtSTOMP != targ->deathtype && !midair ) damage *= ( deathmatch == 4 ? 8 : 4 ); // in dmm4 quad is octa actually // ctf strength rune if ( attacker->ctf_flag & CTF_RUNE_STR ) damage *= 2; // ctf resistance rune if ( targ->ctf_flag & CTF_RUNE_RES ) { damage /= 2; ResistanceSound( targ ); } // did we hurt enemy flag carrier? if ( (targ->ctf_flag & CTF_FLAG) && (!streq(targteam, attackerteam)) ) { attacker->carrier_hurt_time = g_globalvars.time; } // in teamplay 4 we do no armor or health damage to teammates (unless telefrag), but do apply velocity changes if ( tp_num() == 4 && streq(targteam, attackerteam) && ( isCA() || targ != attacker ) && !TELEDEATH(targ) ) { tp4teamdmg = true; } if ( midair || cvar("k_instagib") ) { traceline( PASSVEC3(targ->s.v.origin), targ->s.v.origin[0], targ->s.v.origin[1], targ->s.v.origin[2] - 2048, true, targ ); playerheight = targ->s.v.absmin[2] - g_globalvars.trace_endpos[2] + ( cvar("k_instagib") ? 1 : 0 ); } // get some data before apply damage in mid air mode if ( midair ) { inwater = ( ((int)targ->s.v.flags & FL_INWATER) && targ->s.v.waterlevel > 1 ); if ( streq( inflictor->s.v.classname, "rocket" )) midheight = targ->s.v.origin[2] - inflictor->s.v.oldorigin[2]; rl_dmg = ( targ->ct == ctPlayer && dtRL == targ->deathtype ); stomp_dmg = ( targ->ct == ctPlayer && dtSTOMP == targ->deathtype ); if ( !rl_dmg ) { // damage types which ignore "lowheight" do_dmg = targ->ct != ctPlayer // always do damage to non player, secret doors etc... || dtWATER_DMG == targ->deathtype // always do water damage || dtLAVA_DMG == targ->deathtype // always do lava damage || dtSLIME_DMG == targ->deathtype // always do slime damage || dtSTOMP == targ->deathtype // always do stomp damage || dtTELE1 == targ->deathtype // always do tele damage || dtTELE2 == targ->deathtype // always do tele damage || dtTELE3 == targ->deathtype // always do tele damage || dtSUICIDE == targ->deathtype; // do suicide damage anyway } } non_hdp_damage = damage; // save damage before handicap apply for kickback calculation // #handicap# if ( attacker != targ ) // attack no self if ( attacker->ct == ctPlayer && targ->ct == ctPlayer ) // player vs player if ( ( hdp = GetHandicap(attacker) ) != 100 ) // skip checks if hdp == 100 if ( dtAXE == targ->deathtype || dtSG == targ->deathtype || dtSSG == targ->deathtype || dtNG == targ->deathtype || dtSNG == targ->deathtype || dtGL == targ->deathtype || dtRL == targ->deathtype || dtLG_BEAM == targ->deathtype || dtLG_DIS == targ->deathtype || dtLG_DIS_SELF == targ->deathtype // even that impossible ) { damage *= 0.01f * hdp; } // save damage based on the target's armor level save = newceil( targ->s.v.armortype * damage ); if ( tp4teamdmg ) save = 0; // we do not touch armor if ( save >= targ->s.v.armorvalue ) { save = targ->s.v.armorvalue; targ->s.v.armortype = 0; // lost all armor targ->s.v.items -= ( ( int ) targ->s.v.items & ( IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3 ) ); } dmg_dealt += save; if ( match_in_progress == 2 ) targ->s.v.armorvalue = targ->s.v.armorvalue - save; take = newceil( damage - save ); // mid air damage modificators if ( midair ) { int k_midair_minheight, midair_minheight; k_midair_minheight = (int)cvar("k_midair_minheight"); if ( k_midair_minheight == 1 ) midair_minheight = 128; else if ( k_midair_minheight == 2 ) midair_minheight = 256; else if ( k_midair_minheight == 3 ) midair_minheight = 512; else if ( k_midair_minheight == 4 ) midair_minheight = 1024; else midair_minheight = 64; if ( rl_dmg || stomp_dmg ) take = 9999; if ( playerheight < midair_minheight && rl_dmg ) take = 0; // no dmg done if target is not high enough if ( playerheight < 45 && !inwater && rl_dmg ) take = 0; // no rl dmg in such case if ( !rl_dmg && !do_dmg ) take = 0; // unknown damage for midair, so do not damage if ( rl_dmg && targ == attacker ) take = 0; // no self rl damage } // instagib damage modificators if ( cvar("k_instagib") ) { if ( inflictor->ct == ctPlayer ) take = 5000; if ( attacker == targ ) take = 0; } // helps kill player in prewar at "wrong" places if ( match_in_progress != 2 && native_damage > 450 ) take = 99999; // team play damage avoidance and godmode or invincibility check virtual_take = max(0, take); // virtual_take used for calculating dmg_dealt only in case of k_dmgfrags // ignore this checks for suicide damage if ( dtSUICIDE != targ->deathtype ) { if ( ( int ) targ->s.v.flags & FL_GODMODE ) { take = 0; // what if god was one of us } else if ( targ->invincible_finished >= g_globalvars.time ) { if ( targ->invincible_sound < g_globalvars.time ) { sound( targ, CHAN_AUTO, "items/protect3.wav", 1, ATTN_NORM ); targ->invincible_sound = g_globalvars.time + 2; } take = 0; } else if ( ( tp_num() == 1 || ( tp_num() == 3 && targ != attacker ) ) && !strnull( attackerteam ) && streq( targteam, attackerteam ) && attacker->ct == ctPlayer && strneq( inflictor->s.v.classname, "door" ) && !TELEDEATH( targ ) // do telefrag damage in tp ) { // teamplay == 1 don't damage self and mates (armor affected anyway) // teamplay == 3 don't damage mates, do damage to self (armor affected anyway) take = 0; } else if ( tp4teamdmg ) { take = 0; // we do not touch health } } take = max(0, take); // avoid negative take, if any if ( cvar("k_dmgfrags") ) { if ( TELEDEATH( targ ) ) { // tele doesn't count for any dmgfrags damage dmg_dealt = 0; } else if ( targ->invincible_finished >= g_globalvars.time ) { // damage dealt _not_ capped by victim's health if victim has pent dmg_dealt += virtual_take; } else { // damage dealt capped by victim's health dmg_dealt += bound( 0, virtual_take, targ->s.v.health ); } } else { // damage dealt capped by victim's health dmg_dealt += bound( 0, take, targ->s.v.health ); } // add to the damage total for clients, which will be sent as a single // message at the end of the frame // FIXME: remove after combining shotgun blasts? if ( targ->ct == ctPlayer ) { targ->s.v.dmg_take += take; targ->s.v.dmg_save += save; targ->s.v.dmg_inflictor = EDICT_TO_PROG( inflictor ); } if ( save ) { if (( streq( inflictor->s.v.classname, "worldspawn" ) || strnull( attacker->s.v.classname )) || ( targ->deathtype == dtWATER_DMG ) || ( targ->deathtype == dtEXPLO_BOX ) || ( targ->deathtype == dtFALL ) || ( targ->deathtype == dtSQUISH ) || ( targ->deathtype == dtCHANGELEVEL ) || ( targ->deathtype == dtFIREBALL ) || ( targ->deathtype == dtSLIME_DMG ) || ( targ->deathtype == dtLAVA_DMG ) || ( targ->deathtype == dtTRIGGER_HURT ) ) attackername = "world"; else attackername = attacker->s.v.netname; victimname = targ->s.v.netname; log_printf( "\t\t<event>\n" "\t\t\t<damage>\n" "\t\t\t\t<time>%f</time>\n" "\t\t\t\t<attacker>%s</attacker>\n" "\t\t\t\t<target>%s</target>\n" "\t\t\t\t<type>%s</type>\n" "\t\t\t\t<quad>%d</quad>\n" "\t\t\t\t<splash>%d</splash>\n" "\t\t\t\t<value>%d</value>\n" "\t\t\t\t<armor>1</armor>\n" "\t\t\t</damage>\n" "\t\t</event>\n", g_globalvars.time - match_start_time, cleantext(attackername), cleantext(victimname), death_type( targ->deathtype ), (int)(attacker->super_damage_finished > g_globalvars.time ? 1 : 0 ), dmg_is_splash, (int)save ); } // figure momentum add if ( inflictor != world && ( targ->s.v.movetype == MOVETYPE_WALK || ( k_bloodfest && ( (int)targ->s.v.flags & FL_MONSTER ) ) ) ) { float nailkick; for ( i = 0; i < 3; i++ ) dir[i] = targ->s.v.origin[i] - ( inflictor->s.v.absmin[i] + inflictor->s.v.absmax[i] ) * 0.5; VectorNormalize( dir ); dir[2] = ((dtLG_DIS_SELF == targ->deathtype || dtLG_DIS == targ->deathtype) && dir[2] < 0) ? -dir[2] : dir[2]; if ( midair && non_hdp_damage < 60 && attacker != targ ) { c1 = 11; c2 = 6; } // Yawnmode: nails increases kickback // - Molgrum if ( k_yawnmode && streq( inflictor->s.v.classname, "spike" ) ) nailkick = 1.2; else nailkick = 1.0; for ( i = 0; i < 3; i++ ) targ->s.v.velocity[i] += dir[i] * non_hdp_damage * c1 * nailkick * ( midair && playerheight >= 45 ? ( 1 + ( playerheight - 45 ) / 64 ) : 1 ); if ( midair && playerheight < 45 ) targ->s.v.velocity[2] += dir[2] * non_hdp_damage * c2 * nailkick; // only for z component if ( k_bloodfest && ( (int)targ->s.v.flags & FL_MONSTER ) ) { targ->s.v.flags = (int)targ->s.v.flags & ~FL_ONGROUND; } } if ( match_in_progress == 2 && (int)cvar("k_dmgfrags") ) { if ( attacker->ct == ctPlayer && targ->ct == ctPlayer && attacker != targ ) { if ( isDuel() || isFFA() || strneq(attackerteam, targteam) ) { int dmg_frags; attacker->ps.dmg_frags += dmg_dealt; // add dealt dmg_frags = attacker->ps.dmg_frags / 100; // 1 frag = 100 damage attacker->s.v.frags = (int)(attacker->s.v.frags + dmg_frags); attacker->ps.dmg_frags -= dmg_frags * 100; } } } // do the damage if ( match_in_progress == 2 || dtSUICIDE == targ->deathtype // do suicide damage anyway || TELEDEATH( targ ) || ( k_practice && targ->ct != ctPlayer ) // #practice mode# || take >= 99999 // do such huge damage even in prewar, prewar because indirectly here match_in_progress != 2 ) { targ->s.v.health -= take; // G_bprint( 2, "%s %f\n", targ->s.v.classname, targ->s.v.health ); if ( take ) { if (( streq( inflictor->s.v.classname, "worldspawn" ) || strnull( attacker->s.v.classname )) || ( targ->deathtype == dtWATER_DMG ) || ( targ->deathtype == dtEXPLO_BOX ) || ( targ->deathtype == dtFALL ) || ( targ->deathtype == dtSQUISH ) || ( targ->deathtype == dtCHANGELEVEL ) || ( targ->deathtype == dtFIREBALL ) || ( targ->deathtype == dtSLIME_DMG ) || ( targ->deathtype == dtLAVA_DMG ) || ( targ->deathtype == dtTRIGGER_HURT ) ) attackername = "world"; else attackername = attacker->s.v.netname; victimname = targ->s.v.netname; log_printf( "\t\t<event>\n" "\t\t\t<damage>\n" "\t\t\t\t<time>%f</time>\n" "\t\t\t\t<attacker>%s</attacker>\n" "\t\t\t\t<target>%s</target>\n" "\t\t\t\t<type>%s</type>\n" "\t\t\t\t<quad>%d</quad>\n" "\t\t\t\t<splash>%d</splash>\n" "\t\t\t\t<value>%d</value>\n" "\t\t\t\t<armor>0</armor>\n" "\t\t\t</damage>\n" "\t\t</event>\n", g_globalvars.time - match_start_time, cleantext(attackername), cleantext(victimname), death_type( targ->deathtype ), (int)(attacker->super_damage_finished > g_globalvars.time ? 1 : 0 ), dmg_is_splash, (int)take ); } if ( !targ->s.v.health || dtSUICIDE == targ->deathtype ) targ->s.v.health = -1; // qqshka, no zero health, heh, imo less bugs after this } // show damage in sbar if ( match_in_progress != 2 && ISLIVE( targ ) && !k_matchLess ) { if ( !midair || ( (int)targ->s.v.flags & FL_ONGROUND ) ) { if ( targ->ct == ctPlayer ) targ->s.v.currentammo = 1000 + Q_rint(damage); if ( attacker != targ && attacker->ct == ctPlayer) attacker->s.v.health = 1000 + Q_rint(damage); } } // update damage stats like: give/taked/team damage if ( attacker->ct == ctPlayer && targ->ct == ctPlayer ) { if ( attacker == targ ) { // self damage attacker->ps.dmg_self += dmg_dealt; } else { int items = targ->s.v.items; // damage to enemy weapon if ( items & (IT_ROCKET_LAUNCHER | IT_LIGHTNING) ) { attacker->ps.dmg_eweapon += dmg_dealt; } if ( tp_num() && streq(attackerteam, targteam) ) { attacker->ps.dmg_team += dmg_dealt; } else { attacker->ps.dmg_g += dmg_dealt; targ->ps.dmg_t += dmg_dealt; } // real hits if ( take || save ) { if ( dtRL == targ->deathtype ) attacker->ps.wpn[wpRL].rhits++; if ( dtGL == targ->deathtype ) attacker->ps.wpn[wpGL].rhits++; } // virtual hits if ( virtual_take || save ) { if ( dtRL == targ->deathtype ) { attacker->ps.wpn[wpRL].vhits++; // virtual given rl damage attacker->ps.dmg_g_rl += ( virtual_take + save ); } if ( dtGL == targ->deathtype ) attacker->ps.wpn[wpGL].vhits++; } } } // mid air bonuses if ( midair && match_in_progress == 2 && attacker != targ && take && rl_dmg) MidairDamageBonus(attacker, midheight); if ( midair && match_in_progress == 2 && stomp_dmg ) { attacker->ps.mid_stomps++; targ->s.v.frags -= 3; } // if targed killed, do appropriate action and return if ( ISDEAD( targ ) ) { Killed( targ, attacker, inflictor ); return; } // react to the damage - call pain function oldself = self; self = targ; if ( (int)self->s.v.flags & FL_MONSTER ) { GetMadAtAttacker( attacker ); } if ( self->th_pain ) { self->th_pain( attacker, take ); } self = oldself; }
int get_votes_req( int fofs, qbool diff ) { float percent = 51; int votes, vt_req, idx, el_type; votes = get_votes( fofs ); switch ( fofs ) { case OV_BREAK: percent = cvar(k_matchLess ? "k_vp_map" : "k_vp_break"); break; // in matchless mode there is no /break but /next_map so using "k_vp_map" case OV_PICKUP: percent = cvar("k_vp_pickup"); break; case OV_RPICKUP: percent = cvar("k_vp_rpickup"); break; case OV_MAP: percent = cvar("k_vp_map"); idx = vote_get_maps (); if ( idx >= 0 && !strnull( GetMapName(maps_voted[idx].map_id) ) ) votes = maps_voted[idx].map_votes; else votes = 0; break; case OV_ELECT: if ( (el_type = get_elect_type ()) == etAdmin ) { percent = cvar("k_vp_admin"); break; } else if ( el_type == etCaptain ) { percent = cvar("k_vp_captain"); break; } else { percent = 100; break; // unknown/none election break; } break; case OV_NOSPECS: percent = cvar("k_vp_nospecs"); break; case OV_TEAMOVERLAY: percent = cvar("k_vp_teamoverlay"); break; case OV_COOP: percent = cvar("k_vp_coop"); break; case OV_ANTILAG: percent = cvar("k_vp_antilag"); break; } percent = bound(0.51, bound(51, percent, 100)/100, 1); // calc and bound percentage between 50% to 100% if (isRACE() && fofs == OV_MAP) { vt_req = race_count_votes_req(percent); } else { vt_req = ceil(percent * (CountPlayers() - CountBots())); } if ( fofs == OV_ELECT ) vt_req = max(2, vt_req); // if election, at least 2 votes needed else if ( fofs == OV_BREAK && k_matchLess && match_in_progress == 1 ) vt_req = max(2, vt_req); // at least 2 votes in this case else if ( fofs == OV_BREAK ) vt_req = max(1, vt_req); // at least 1 vote in any case else if ( fofs == OV_RPICKUP ) vt_req = max(3, vt_req); // at least 3 votes in this case else if ( fofs == OV_NOSPECS && cvar("_k_nospecs") ) vt_req = max(1, vt_req); // at least 1 vote in this case else if ( fofs == OV_NOSPECS ) vt_req = max(2, vt_req); // at least 2 votes in this case else if ( fofs == OV_TEAMOVERLAY ) vt_req = max(2, vt_req); // at least 2 votes in this case else if ( fofs == OV_COOP ) vt_req = max(1, vt_req); // at least 1 votes in this case else if ( fofs == OV_ANTILAG ) vt_req = max(2, vt_req); // at least 2 votes in this case if (CountBots () > 0 && CountPlayers () - CountBots () == 1) vt_req = 1; if ( diff ) return max(0, vt_req - votes ); return max(0, vt_req - CountBots()); }
// KTX has in-built modifications to several maps - frogbot routing relies on entity order so we have // to customise again here. Called after all markers created, but before traveltime calculations static void CustomiseFrogbotMap (void) { gedict_t* ent = NULL; // KTX may have added a quad, so to keep routes compatible with PR1-version, we add it as a marker after others if (streq(g_globalvars.mapname, "aerowalk") && !FrogbotOptionEnabled(FB_OPTION_EDITOR_MODE)) { gedict_t* quad = ez_find (world, "item_artifact_super_damage"); if (quad) { gedict_t* nearest_marker; quad->fb.fl_marker = false; nearest_marker = LocateMarker (quad->s.v.origin); quad->fb.fl_marker = true; StartItemFB (quad); quad->fb.T |= MARKER_DYNAMICALLY_ADDED; // Quad is in same zone as nearest marker, and linked by the first path that's valid SetZone (nearest_marker->fb.Z_, quad->fb.index + 1); SetGoalForMarker (18, quad); AddPath (nearest_marker, quad); AddPath (quad, nearest_marker); SpawnMarkerIndicator (quad); } } // We stopped it from removing the telespawn earlier on... if (!cvar ("k_end_tele_spawn") && streq ("end", g_globalvars.mapname)) { vec3_t TS_ORIGIN = { -392, 608, 40 }; // tele spawn gedict_t* p = NULL; gedict_t* m = NULL; for (p = world; (p = find (p, FOFCLSN, "info_player_deathmatch")); ) { if (VectorCompare (p->s.v.origin, TS_ORIGIN)) { p->classname = "info_player_deathmatch_removed"; // Remove any spawn marker for (m = world; (m = find (m, FOFCLSN, "spawnpoint")); ) { if (m->k_lastspawn == p) { ent_remove (m); break; } } break; } } } // Expand bounding box of all items if (!isRACE()) { for (ent = world; (ent = nextent(ent)); ) { if (streq(ent->classname, "info_teleport_destination") || streq(ent->classname, "info_player_deathmatch")) { continue; } if (streq(ent->classname, "marker")) { vec3_t mins = { -65, -65, -24 }; vec3_t maxs = { 65, 65, 32 }; vec3_t viewoffset = { 80, 80, 24 }; int i; for (i = 0; i < 3; ++i) { if (ent->fb.fixed_size[i]) { mins[i] = -ent->fb.fixed_size[i] / 2 - (i < 2 ? 15 : 0); maxs[i] = ent->fb.fixed_size[i] / 2 - (i < 2 ? 15 : 0); viewoffset[i] = (maxs[i] - mins[i]) / 2; } } VectorCopy(viewoffset, ent->s.v.view_ofs); setsize(ent, PASSVEC3(mins), PASSVEC3(maxs)); } else if ((int)ent->s.v.flags & FL_ITEM) { PlaceItemFB(ent); } } } // Link all teleporters if (FrogbotOptionEnabled (FB_OPTION_EDITOR_MODE)) { for (ent = world; (ent = ez_find (ent, "trigger_teleport")); ) { // If this teleport takes us to the marker close to the grenade, set arrow_time if (!strnull (ent->target)) { gedict_t* target = find (world, FOFS (targetname), ent->target); AddPath (ent, target); } } } }