X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=qcsrc%2Fserver%2Fmiscfunctions.qc;h=689c7f93c8dc5ef675815e1c8b4b120ca4ff343a;hb=23b8d3a0e72974b6e5068a00bf9edd8788617d52;hp=1359c056692298f68ce457d95d13537e1398a9b8;hpb=40cc357c2c4732d3d035240cfab34b9097f51f34;p=xonotic%2Fxonotic-data.pk3dir.git diff --git a/qcsrc/server/miscfunctions.qc b/qcsrc/server/miscfunctions.qc index 1359c0566..689c7f93c 100644 --- a/qcsrc/server/miscfunctions.qc +++ b/qcsrc/server/miscfunctions.qc @@ -67,6 +67,16 @@ float DistributeEvenly_Get(float weight) DistributeEvenly_amount -= f; return f; } +float DistributeEvenly_GetRandomized(float weight) +{ + float f; + if (weight <= 0) + return 0; + f = floor(random() + DistributeEvenly_amount * weight / DistributeEvenly_totalweight); + DistributeEvenly_totalweight -= weight; + DistributeEvenly_amount -= f; + return f; +} #define move_out_of_solid(e) WarpZoneLib_MoveOutOfSolid(e) @@ -80,14 +90,19 @@ string STR_OBSERVER = "observer"; #define FOR_EACH_REALCLIENT(v) FOR_EACH_CLIENT(v) if(clienttype(v) == CLIENTTYPE_REAL) #define FOR_EACH_PLAYER(v) for(v = world; (v = find(v, classname, STR_PLAYER)) != world; ) #define FOR_EACH_REALPLAYER(v) FOR_EACH_PLAYER(v) if(clienttype(v) == CLIENTTYPE_REAL) +#define FOR_EACH_MONSTER(v) for(v = world; (v = findflags(v, flags, FL_MONSTER)) != world; ) #else #define FOR_EACH_CLIENTSLOT(v) for(v = world; (v = nextent(v)) && (num_for_edict(v) <= maxclients); ) #define FOR_EACH_CLIENT(v) FOR_EACH_CLIENTSLOT(v) if(v.flags & FL_CLIENT) #define FOR_EACH_REALCLIENT(v) FOR_EACH_CLIENT(v) if(clienttype(v) == CLIENTTYPE_REAL) #define FOR_EACH_PLAYER(v) FOR_EACH_CLIENT(v) if(v.classname == STR_PLAYER) +#define FOR_EACH_SPEC(v) FOR_EACH_CLIENT(v) if(v.classname != STR_PLAYER) #define FOR_EACH_REALPLAYER(v) FOR_EACH_REALCLIENT(v) if(v.classname == STR_PLAYER) +#define FOR_EACH_MONSTER(v) for(v = world; (v = findflags(v, flags, FL_MONSTER)) != world; ) #endif +#define CENTER_OR_VIEWOFS(ent) (ent.origin + ((ent.classname == STR_PLAYER) ? ent.view_ofs : ((ent.mins + ent.maxs) * 0.5))) + // copies a string to a tempstring (so one can strunzone it) string strcat1(string s) = #115; // FRIK_FILE @@ -415,7 +430,7 @@ string formatmessage(string msg) else replacement = "batteries"; // ;) } else if (escape == "x") { replacement = cursor_ent.netname; - if (!replacement || !cursor_ent) + if (replacement == "" || !cursor_ent) replacement = "nothing"; } else if (escape == "s") replacement = ftos(vlen(self.velocity - self.velocity_z * '0 0 1')); @@ -526,7 +541,7 @@ string W_FixWeaponOrder_ForceComplete_AndBuildImpulseList(string wo) } void GetCvars(float f) { - string s; + string s = string_null; if (f > 0) s = strcat1(argv(f)); @@ -740,6 +755,7 @@ float g_pickup_healthmega_anyway; float g_pickup_ammo_anyway; float g_pickup_weapons_anyway; float g_weaponarena; +WEPSET_DECLARE_A(g_weaponarena_weapons); float g_weaponarena_random; float g_weaponarena_random_with_laser; string g_weaponarena_list; @@ -749,7 +765,9 @@ float g_weapondamagefactor; float g_weaponforcefactor; float g_weaponspreadfactor; -float start_weapons; +WEPSET_DECLARE_A(start_weapons); +WEPSET_DECLARE_A(start_weapons_default); +WEPSET_DECLARE_A(start_weapons_defaultmask); float start_items; float start_ammo_shells; float start_ammo_nails; @@ -758,7 +776,9 @@ float start_ammo_cells; float start_ammo_fuel; float start_health; float start_armorvalue; -float warmup_start_weapons; +WEPSET_DECLARE_A(warmup_start_weapons); +WEPSET_DECLARE_A(warmup_start_weapons_default); +WEPSET_DECLARE_A(warmup_start_weapons_defaultmask); float warmup_start_ammo_shells; float warmup_start_ammo_nails; float warmup_start_ammo_rockets; @@ -767,34 +787,48 @@ float warmup_start_ammo_fuel; float warmup_start_health; float warmup_start_armorvalue; float g_weapon_stay; -float g_ghost_items; entity get_weaponinfo(float w); float want_weapon(string cvarprefix, entity weaponinfo, float allguns) { var float i = weaponinfo.weapon; + var float d = 0; if (!i) return 0; - var float t = cvar(strcat(cvarprefix, weaponinfo.netname)); - - if (t < 0) // "default" weapon selection + if (g_lms || g_ca || allguns) { - if (g_lms || g_ca || allguns) - t = (weaponinfo.spawnflags & WEP_FLAG_NORMAL); - else if(t < -1) - t = 0; - else if (g_cts) - t = (i == WEP_SHOTGUN); - else if (g_nexball) - t = 0; // weapon is set a few lines later + if(weaponinfo.spawnflags & WEP_FLAG_NORMAL) + d = TRUE; else - t = (i == WEP_LASER || i == WEP_SHOTGUN); - if(g_grappling_hook) // if possible, redirect off-hand hook to on-hand hook - t |= (i == WEP_HOOK); + d = FALSE; } + else if (g_cts) + d = (i == WEP_SHOTGUN); + else if (g_nexball) + d = 0; // weapon is set a few lines later + else + d = (i == WEP_LASER || i == WEP_SHOTGUN); + + if(g_grappling_hook) // if possible, redirect off-hand hook to on-hand hook + d |= (i == WEP_HOOK); + if(weaponinfo.spawnflags & WEP_FLAG_MUTATORBLOCKED) // never default mutator blocked guns + d = 0; + + var float t = cvar(strcat(cvarprefix, weaponinfo.netname)); + + //print(strcat("want_weapon: ", weaponinfo.netname, " - d: ", ftos(d), ", t: ", ftos(t), ". \n")); + + // bit order in t: + // 1: want or not + // 2: is default? + // 4: is set by default? + if(t < 0) + t = 4 | (3 * d); + else + t |= (2 * d); return t; } @@ -806,7 +840,9 @@ void readplayerstartcvars() string s; // initialize starting values for players - start_weapons = 0; + WEPSET_CLEAR_A(start_weapons); + WEPSET_CLEAR_A(start_weapons_default); + WEPSET_CLEAR_A(start_weapons_defaultmask); start_items = 0; start_ammo_shells = 0; start_ammo_nails = 0; @@ -816,6 +852,8 @@ void readplayerstartcvars() start_armorvalue = cvar("g_balance_armor_start"); g_weaponarena = 0; + WEPSET_CLEAR_A(g_weaponarena_weapons); + s = cvar_string("g_weaponarena"); if (s == "0" || s == "") { @@ -833,34 +871,35 @@ void readplayerstartcvars() } else if (s == "all") { + g_weaponarena = 1; g_weaponarena_list = "All Weapons"; for (j = WEP_FIRST; j <= WEP_LAST; ++j) { e = get_weaponinfo(j); - g_weaponarena |= e.weapons; - weapon_action(e.weapon, WR_PRECACHE); + if not(e.spawnflags & WEP_FLAG_MUTATORBLOCKED) + WEPSET_OR_AW(g_weaponarena_weapons, j); } } else if (s == "most") { + g_weaponarena = 1; g_weaponarena_list = "Most Weapons"; for (j = WEP_FIRST; j <= WEP_LAST; ++j) { e = get_weaponinfo(j); - if (e.spawnflags & WEP_FLAG_NORMAL) - { - g_weaponarena |= e.weapons; - weapon_action(e.weapon, WR_PRECACHE); - } + if not(e.spawnflags & WEP_FLAG_MUTATORBLOCKED) + if (e.spawnflags & WEP_FLAG_NORMAL) + WEPSET_OR_AW(g_weaponarena_weapons, j); } } else if (s == "none") { + g_weaponarena = 1; g_weaponarena_list = "No Weapons"; - g_weaponarena = WEPBIT_ALL + 1; // this supports no single weapon bit! } else { + g_weaponarena = 1; t = tokenize_console(s); g_weaponarena_list = ""; for (i = 0; i < t; ++i) @@ -871,8 +910,7 @@ void readplayerstartcvars() e = get_weaponinfo(j); if (e.netname == s) { - g_weaponarena |= e.weapons; - weapon_action(e.weapon, WR_PRECACHE); + WEPSET_OR_AW(g_weaponarena_weapons, j); g_weaponarena_list = strcat(g_weaponarena_list, e.message, " & "); break; } @@ -896,7 +934,7 @@ void readplayerstartcvars() g_minstagib = 0; // incompatible g_pinata = 0; // incompatible g_weapon_stay = 0; // incompatible - start_weapons = g_weaponarena; + WEPSET_COPY_AA(start_weapons, g_weaponarena_weapons); if(!(g_lms || g_ca)) start_items |= IT_UNLIMITED_AMMO; } @@ -907,8 +945,7 @@ void readplayerstartcvars() g_bloodloss = 0; // incompatible start_health = 100; start_armorvalue = 0; - start_weapons = WEPBIT_MINSTANEX; - weapon_action(WEP_MINSTANEX, WR_PRECACHE); + WEPSET_COPY_AW(start_weapons, WEP_MINSTANEX); g_minstagib_invis_alpha = cvar("g_minstagib_invis_alpha"); start_items |= IT_UNLIMITED_SUPERWEAPONS; @@ -920,8 +957,13 @@ void readplayerstartcvars() for (i = WEP_FIRST; i <= WEP_LAST; ++i) { e = get_weaponinfo(i); - if(want_weapon("g_start_weapon_", e, FALSE)) - start_weapons |= e.weapons; + float w = want_weapon("g_start_weapon_", e, FALSE); + if(w & 1) + WEPSET_OR_AW(start_weapons, i); + if(w & 2) + WEPSET_OR_AW(start_weapons_default, i); + if(w & 4) + WEPSET_OR_AW(start_weapons_defaultmask, i); } } @@ -979,7 +1021,9 @@ void readplayerstartcvars() warmup_start_ammo_fuel = start_ammo_fuel; warmup_start_health = start_health; warmup_start_armorvalue = start_armorvalue; - warmup_start_weapons = start_weapons; + WEPSET_COPY_AA(warmup_start_weapons, start_weapons); + WEPSET_COPY_AA(warmup_start_weapons_default, start_weapons_default); + WEPSET_COPY_AA(warmup_start_weapons_defaultmask, start_weapons_defaultmask); if (!g_weaponarena && !g_minstagib && !g_ca) { @@ -990,17 +1034,29 @@ void readplayerstartcvars() warmup_start_ammo_fuel = cvar("g_warmup_start_ammo_fuel"); warmup_start_health = cvar("g_warmup_start_health"); warmup_start_armorvalue = cvar("g_warmup_start_armor"); - warmup_start_weapons = 0; + WEPSET_CLEAR_A(warmup_start_weapons); + WEPSET_CLEAR_A(warmup_start_weapons_default); + WEPSET_CLEAR_A(warmup_start_weapons_defaultmask); for (i = WEP_FIRST; i <= WEP_LAST; ++i) { e = get_weaponinfo(i); - if(want_weapon("g_start_weapon_", e, cvar("g_warmup_allguns"))) - warmup_start_weapons |= e.weapons; + float w = want_weapon("g_start_weapon_", e, cvar("g_warmup_allguns")); + if(w & 1) + WEPSET_OR_AW(warmup_start_weapons, i); + if(w & 2) + WEPSET_OR_AW(warmup_start_weapons_default, i); + if(w & 4) + WEPSET_OR_AW(warmup_start_weapons_defaultmask, i); } } } - if (g_jetpack || (g_grappling_hook && (start_weapons & WEPBIT_HOOK))) + if (g_jetpack) + start_items |= IT_JETPACK; + + MUTATOR_CALLHOOK(SetStartItems); + + if ((start_items & IT_JETPACK) || (g_grappling_hook && WEPSET_CONTAINS_AW(start_weapons, WEP_HOOK))) { g_grappling_hook = 0; // these two can't coexist, as they use the same button start_items |= IT_FUEL_REGEN; @@ -1008,16 +1064,11 @@ void readplayerstartcvars() warmup_start_ammo_fuel = max(warmup_start_ammo_fuel, cvar("g_balance_fuel_rotstable")); } - if (g_jetpack) - start_items |= IT_JETPACK; - - MUTATOR_CALLHOOK(SetStartItems); - for (i = WEP_FIRST; i <= WEP_LAST; ++i) { e = get_weaponinfo(i); - if(e.weapons & (start_weapons | warmup_start_weapons)) - weapon_action(e.weapon, WR_PRECACHE); + if(WEPSET_CONTAINS_AW(start_weapons, i) || WEPSET_CONTAINS_AW(warmup_start_weapons, i)) + weapon_action(i, WR_PRECACHE); } start_ammo_shells = max(0, start_ammo_shells); @@ -1065,23 +1116,39 @@ float sv_pitch_fixyaw; string GetGametype(); // g_world.qc void readlevelcvars(void) { - // first load all the mutators - if(cvar("g_invincible_projectiles")) - MUTATOR_ADD(mutator_invincibleprojectiles); - if(cvar("g_nix")) - MUTATOR_ADD(mutator_nix); + g_minstagib = cvar("g_minstagib"); + + monster_skill = cvar("g_monsters_skill"); + + // load ALL the mutators if(cvar("g_dodging")) MUTATOR_ADD(mutator_dodging); - if(cvar("g_rocket_flying")) - MUTATOR_ADD(mutator_rocketflying); - if(cvar("g_vampire")) - MUTATOR_ADD(mutator_vampire); if(cvar("g_spawn_near_teammate")) MUTATOR_ADD(mutator_spawn_near_teammate); + if(cvar("g_physical_items")) + MUTATOR_ADD(mutator_physical_items); + if(!g_minstagib) + { + if(cvar("g_invincible_projectiles")) + MUTATOR_ADD(mutator_invincibleprojectiles); + if(cvar("g_new_toys")) + MUTATOR_ADD(mutator_new_toys); + if(cvar("g_nix")) + MUTATOR_ADD(mutator_nix); + if(cvar("g_rocket_flying")) + MUTATOR_ADD(mutator_rocketflying); + if(cvar("g_vampire")) + MUTATOR_ADD(mutator_vampire); + if(cvar("g_superspectate")) + MUTATOR_ADD(mutator_superspec); + } // is this a mutator? is this a mode? if(cvar("g_sandbox")) MUTATOR_ADD(sandbox); + + if(cvar("g_za")) + MUTATOR_ADD(mutator_zombie_apocalypse); if(cvar("sv_allow_fullbright")) serverflags |= SERVERFLAG_ALLOW_FULLBRIGHT; @@ -1123,12 +1190,10 @@ void readlevelcvars(void) g_grappling_hook = cvar("g_grappling_hook"); g_jetpack = cvar("g_jetpack"); g_midair = cvar("g_midair"); - g_minstagib = cvar("g_minstagib"); g_norecoil = cvar("g_norecoil"); g_bloodloss = cvar("g_bloodloss"); sv_maxidle = cvar("sv_maxidle"); sv_maxidle_spectatorsareidle = cvar("sv_maxidle_spectatorsareidle"); - g_ctf_reverse = cvar("g_ctf_reverse"); sv_autotaunt = cvar("sv_autotaunt"); sv_taunt = cvar("sv_taunt"); @@ -1206,11 +1271,6 @@ void readlevelcvars(void) if(!g_weapon_stay) g_weapon_stay = cvar("g_weapon_stay"); - g_ghost_items = cvar("g_ghost_items"); - - if(g_ghost_items >= 1) - g_ghost_items = 0.25; // default alpha value - if not(inWarmupStage && !g_ca) game_starttime = cvar("g_start_delay"); @@ -1548,9 +1608,6 @@ void precache() precache_sound ("player/lava.wav"); precache_sound ("player/slime.wav"); - if (g_jetpack) - precache_sound ("misc/jetpack_fly.wav"); - precache_model ("models/sprites/0.spr32"); precache_model ("models/sprites/1.spr32"); precache_model ("models/sprites/2.spr32"); @@ -1656,7 +1713,7 @@ void make_safe_for_remove(entity e) { if (e.initialize_entity) { - entity ent, prev; + entity ent, prev = world; for (ent = initialize_entity_first; ent; ) { if ((ent == e) || ((ent.classname == "initialize_entity") && (ent.enemy == e))) @@ -1728,6 +1785,7 @@ void InitializeEntity(entity e, void(void) func, float order) e.initialize_entity_order = order; cur = initialize_entity_first; + prev = world; for (;;) { if (!cur || cur.initialize_entity_order > order) @@ -1772,7 +1830,7 @@ void InitializeEntitiesRun() self = e_old; } //dprint("Delayed initialization: ", self.classname, "\n"); - if(func != func_null) + if(func) func(); else { @@ -1786,7 +1844,6 @@ void InitializeEntitiesRun() .float uncustomizeentityforclient_set; .void(void) uncustomizeentityforclient; -void(void) SUB_Nullpointer = #0; void UncustomizeEntitiesRun() { entity oldself; @@ -1799,7 +1856,7 @@ void SetCustomizer(entity e, float(void) customizer, void(void) uncustomizer) { e.customizeentityforclient = customizer; e.uncustomizeentityforclient = uncustomizer; - e.uncustomizeentityforclient_set = (uncustomizer != SUB_Nullpointer); + e.uncustomizeentityforclient_set = !!uncustomizer; } .float nottargeted; @@ -2078,7 +2135,7 @@ void race_writeTime(string map, float t, string myuid) float newpos; newpos = race_readPos(map, t); - float i, prevpos; + float i, prevpos = 0; for(i = 1; i <= RANKINGS_CNT; ++i) { if(race_readUID(map, i) == myuid) @@ -2140,6 +2197,8 @@ float MoveToRandomMapLocation(entity e, float goodcontents, float badcontents, f org = world.mins; delta = world.maxs - world.mins; + start = end = org; + for (i = 0; i < attempts; ++i) { start_x = org_x + random() * delta_x; @@ -2356,8 +2415,8 @@ vector shotorg_adjust_values(vector vecs, float y_is_right, float visual, float { if (visual) { - vecs_y = 0; - vecs_z -= 2; + if (autocvar_g_shootfromclient) { vecs = shotorg_adjustfromclient(vecs, y_is_right, (autocvar_g_shootfromclient >= 2), algn); } + else { vecs_y = 0; vecs_z -= 2; } } else { @@ -2396,12 +2455,8 @@ vector shotorg_adjust(vector vecs, float y_is_right, float visual) void attach_sameorigin(entity e, entity to, string tag) { vector org, t_forward, t_left, t_up, e_forward, e_up; - vector org0, ang0; float tagscale; - ang0 = e.angles; - org0 = e.origin; - org = e.origin - gettaginfo(to, gettagindex(to, tag)); tagscale = pow(vlen(v_forward), -2); // undo a scale on the tag t_forward = v_forward * tagscale; @@ -2479,43 +2534,6 @@ vector gettaginfo_relative(entity e, float tag) return gettaginfo(gettaginfo_relative_ent, tag); } -void SoundEntity_StartSound(entity pl, float chan, string samp, float vol, float attn) -{ - float p; - p = pow(2, chan); - if (pl.soundentity.cnt & p) - return; - soundtoat(MSG_ALL, pl.soundentity, gettaginfo(pl.soundentity, 0), chan, samp, vol, attn); - pl.soundentity.cnt |= p; -} - -void SoundEntity_StopSound(entity pl, float chan) -{ - float p; - p = pow(2, chan); - if (pl.soundentity.cnt & p) - { - stopsoundto(MSG_ALL, pl.soundentity, chan); - pl.soundentity.cnt &~= p; - } -} - -void SoundEntity_Attach(entity pl) -{ - pl.soundentity = spawn(); - pl.soundentity.classname = "soundentity"; - pl.soundentity.owner = pl; - setattachment(pl.soundentity, pl, ""); - setmodel(pl.soundentity, "null"); -} - -void SoundEntity_Detach(entity pl) -{ - float i; - for (i = 0; i <= 7; ++i) - SoundEntity_StopSound(pl, i); -} - .float scale2; float modeleffect_SendEntity(entity to, float sf) @@ -2749,6 +2767,8 @@ float isPushable(entity e) { if(e.iscreature) return TRUE; + if(e.pushable) + return TRUE; switch(e.classname) { case "body":