]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'mirceakitsune/campaign_gametype_icon' into 'master'
authorMartin Taibr <taibr.martin@gmail.com>
Sat, 4 Jan 2020 16:20:45 +0000 (16:20 +0000)
committerMartin Taibr <taibr.martin@gmail.com>
Sat, 4 Jan 2020 16:20:45 +0000 (16:20 +0000)
Draw the gametype icon on campaign entries

Since I've been doing multiple campaign fixes, I decided to include an update to the menu part as well. I wanted to see how it would look if the gametype icon of levels was also displayed within the field. Personally I find it good looking, as well somewhat easier to tell which level you're at with this change.

I tried several combinations; Above the checkmark looked okay, but it's harder to tell which level the icon is referring to... it seems to look best on the right side of the map preview image. I included a few screenshots, the first representing the old appearance and the last being what the MR currently adds... if you find another position better please suggest it and I'll make a new commit.

![campaign](/uploads/3cf11cc059b9353dfa1dc973c4e859b9/campaign.jpg)
![campaign_above_checkmark](/uploads/9537d4e2bc7919f4275c8848ffbba405/campaign_above_checkmark.jpg)
![campaign_preview_left](/uploads/2ecd0dfa12246c26a9accc4485658b4e/campaign_preview_left.jpg)
![campaign_preview_right](/uploads/f4b32394f3b54e13daf43a50e32b33a7/campaign_preview_right.jpg)

See merge request xonotic/xonotic-data.pk3dir!748

mutators.cfg
qcsrc/Makefile
qcsrc/client/view.qc
qcsrc/client/view.qh
qcsrc/lib/csqcmodel/cl_player.qc
qcsrc/lib/i18n.qh
qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc
qcsrc/menu/xonotic/dialog_singleplayer.qc
qcsrc/server/campaign.qc
xonotic-common.cfg

index 0fcbed2f2e45e5e9b273b92f7b3e2175a5358907..14289d8c8514146d75cf75f0c7e06cc0e0f60418 100644 (file)
@@ -6,7 +6,7 @@
 // =========
 //  dodging
 // =========
-set g_dodging 0 "set to 1 to enable dodging in games"
+set g_dodging 0 "set to 1 to enable dodging (quick acceleration in a given direction)"
 
 seta cl_dodging_timeout 0.2 "determines how long apart (in seconds) two taps on the same direction key are considered a dodge. use 0 to disable"
 
@@ -110,7 +110,7 @@ set g_invincible_projectiles 0 "set to 1 to disable any damage to projectiles in
 // ===============
 //  rocket flying
 // ===============
-set g_rocket_flying 0 "set to 1 to enable rocket flying in all balance configs"
+set g_rocket_flying 0 "make rocket jumping easier - use the remote_jump weapon cvars for selfdamage and selfpush force"
 set g_rocket_flying_disabledelays 1 "disable detonation delays on rockets and mines"
 
 
@@ -144,7 +144,7 @@ set g_nix_with_powerups 0 "when 1, powerups still show up in NIX"
 // ================
 set g_physical_items 0 "1 uses ODE physics for dropped weapons, 2 for all items, requires physics_ode to be enabled"
 set g_physical_items_damageforcescale 3 "how affected physical weapons are by damage"
-set g_physical_items_reset 1 "return map items to their original lotation after being picked up"
+set g_physical_items_reset 1 "return map items to their original location after being picked up"
 
 
 // ===============
@@ -152,9 +152,9 @@ set g_physical_items_reset 1 "return map items to their original lotation after
 // ===============
 set g_touchexplode 0 "touching other players causes an explosion"
 set g_touchexplode_radius 50
-set g_touchexplode_damage 10
+set g_touchexplode_damage 20
 set g_touchexplode_edgedamage 0
-set g_touchexplode_force 150
+set g_touchexplode_force 300
 
 
 // ================
@@ -184,7 +184,7 @@ set g_random_gravity_negative 1000 "negative gravity multiplier"
 // =======
 //  Nades
 // =======
-set g_nades 0 "enable off-hand grenades"
+set g_nades 0 "enable off-hand grenades - use the 'dropweapon' (second press throws) or 'hook' (release throws) binds"
 set g_nades_spread 0.04 "random spread offset of throw direction"
 set g_nades_throw_offset "0 -25 0" "nade throwing offset"
 set g_nades_spawn 1 "give nades right away when player spawns rather than delaying entire refire"
@@ -387,7 +387,7 @@ set g_buffs_flight_time 60 "flight buff carry time"
 // ================
 //  grappling hook
 // ================
-set g_grappling_hook 0 "let players spawn with the grappling hook which allows them to pull themselves up"
+set g_grappling_hook 0 "let players spawn with the grappling hook which allows them to pull themselves"
 set g_grappling_hook_useammo 0 "use ammunition with the off-hand grappling hook"
 
 
index d09b2c5ccffa730255a6545d0f411a11adc05fc5..7c8e3b8ad16f7207d5296f16a4cde3a61863c540 100644 (file)
@@ -93,8 +93,8 @@ pk3: csprogs-$(VER).pk3
        $(eval DAT=$(PROG)-$(VER).dat)
        $(eval LNO=$(PROG)-$(VER).lno)
        @ echo "http://xonotic.org" > $(TXT)
-       @ ln -f $(PROGS_OUT)/$(PROG).dat $(DAT)
-       @ ln -f $(PROGS_OUT)/$(PROG).lno $(LNO)
+       @ cp -f $(PROGS_OUT)/$(PROG).dat $(DAT)
+       @ cp -f $(PROGS_OUT)/$(PROG).lno $(LNO)
        @ $(RM) *.pk3
        $(ZIP) $(PK3) $(TXT) $(DAT) $(LNO)
        @ $(RM) $(TXT) $(DAT) $(LNO)
index 08c717a0b6ff505103e95556ceca4fcda33f3b3b..66f80ad2c45b878fdafc3a9ea070fde4ef29c2ec 100644 (file)
@@ -394,7 +394,6 @@ STATIC_INIT(fpscounter_init)
        showfps_prevfps_time = currentTime; // we must initialize it to avoid an instant low frame sending
 }
 
-float drawtime;
 float avgspeed;
 vector GetCurrentFov(float fov)
 {
index f3c1f4139fff3543ca272c7a750a3cd3328422b5..448361d05f2075d992d3f47a11e83fba5964c439 100644 (file)
@@ -20,3 +20,5 @@ const int CURSOR_NORMAL = 0;
 const int CURSOR_MOVE = 1;
 const int CURSOR_RESIZE = 2;
 const int CURSOR_RESIZE2 = 3;
+
+float drawtime;
index 04b96bc9974974cf98656754bf9aeb1b0583502a..f49c5f6dbd93ab621aea33c531ea47d5c7653380 100644 (file)
@@ -207,6 +207,303 @@ bool CSQCPlayer_IsLocalPlayer(entity this)
        return (this == csqcplayer);
 }
 
+float stairsmoothz;
+float autocvar_cl_stairsmoothspeed;
+float autocvar_cl_smoothviewheight;
+float smooth_prevtime;
+float viewheightavg;
+vector CSQCPlayer_ApplySmoothing(entity this, vector v)
+{
+       float smoothtime = bound(0, time - smooth_prevtime, 0.1);
+       smooth_prevtime = max(smooth_prevtime, drawtime); // drawtime is the previous frame's time at this point
+
+       if(this.csqcmodel_teleported || !(this.pmove_flags & PMF_ONGROUND) || autocvar_cl_stairsmoothspeed <= 0)
+               stairsmoothz = v.z;
+       else
+       {
+               if(stairsmoothz < v.z)
+                       v.z = stairsmoothz = bound(v.z - PHYS_STEPHEIGHT(this), stairsmoothz + smoothtime * autocvar_cl_stairsmoothspeed, v.z);
+               else if(stairsmoothz > v.z)
+                       v.z = stairsmoothz = bound(v.z, stairsmoothz - smoothtime * autocvar_cl_stairsmoothspeed, v.z + PHYS_STEPHEIGHT(this));
+       }
+
+       float viewheight = bound(0, (time - smooth_prevtime) / max(0.0001, autocvar_cl_smoothviewheight), 1);
+       viewheightavg = viewheightavg * (1 - viewheight) + this.view_ofs.z * viewheight;
+       v.z += viewheightavg;
+
+       smooth_prevtime = time;
+
+       return v;
+}
+
+bool autocvar_v_deathtilt;
+float autocvar_v_deathtiltangle;
+void CSQCPlayer_ApplyDeathTilt(entity this)
+{
+       if(!this.csqcmodel_isdead || !autocvar_v_deathtilt)
+               return;
+       view_angles.z = autocvar_v_deathtiltangle;
+}
+
+float autocvar_v_idlescale;
+float autocvar_v_ipitch_cycle;
+float autocvar_v_iyaw_cycle;
+float autocvar_v_iroll_cycle;
+float autocvar_v_ipitch_level;
+float autocvar_v_iyaw_level;
+float autocvar_v_iroll_level;
+void CSQCPlayer_ApplyIdleScaling(entity this)
+{
+       if(!autocvar_v_idlescale)
+               return;
+       view_angles.x += autocvar_v_idlescale * sin(time * autocvar_v_ipitch_cycle) * autocvar_v_ipitch_level;
+       view_angles.y += autocvar_v_idlescale * sin(time * autocvar_v_iyaw_cycle) * autocvar_v_iyaw_level;
+       view_angles.z += autocvar_v_idlescale * sin(time * autocvar_v_iroll_cycle) * autocvar_v_iroll_level;
+       //setproperty(VF_CL_VIEWANGLES, view_angles); // update view angles as well so we can aim
+}
+
+float autocvar_cl_bob;
+float autocvar_cl_bobcycle;
+float autocvar_cl_bob_limit;
+float autocvar_cl_bob_limit_heightcheck;
+float autocvar_cl_bob_velocity_limit;
+float autocvar_cl_bobup;
+float autocvar_cl_bobfall;
+float autocvar_cl_bobfallcycle;
+float autocvar_cl_bobfallminspeed;
+float autocvar_cl_bob2;
+float autocvar_cl_bob2cycle;
+float autocvar_cl_bob2smooth;
+float bobfall_swing;
+float bobfall_speed;
+float bob2_smooth;
+vector CSQCPlayer_ApplyBobbing(entity this, vector v)
+{
+       if(this.csqcmodel_isdead)
+               return v;
+
+       // bounded XY speed, used by several effects below
+       float bob, cycle;
+
+       // vertical view bobbing code
+       if(autocvar_cl_bob && autocvar_cl_bobcycle)
+       {
+               float bob_limit = autocvar_cl_bob_limit;
+
+               if(autocvar_cl_bob_limit_heightcheck)
+               {
+                       // use traces to determine what range the view can bob in, and scale down the bob as needed
+                       vector bob_height_check_dest = v;
+                       bob_height_check_dest.z += autocvar_cl_bob_limit * 1.1;
+                       traceline(v, bob_height_check_dest, MOVE_NOMONSTERS, NULL);
+                       float trace1fraction = trace_fraction;
+
+                       bob_height_check_dest = v;
+                       bob_height_check_dest.z += autocvar_cl_bob_limit * -0.5;
+                       traceline(v, bob_height_check_dest, MOVE_NOMONSTERS, NULL);
+                       float trace2fraction = trace_fraction;
+
+                       bob_limit *= min(trace1fraction, trace2fraction);
+               }
+
+               // LordHavoc: figured out bobup: the time at which the sin is at 180
+               // degrees (which allows lengthening or squishing the peak or valley)
+               cycle = time / autocvar_cl_bobcycle;
+               cycle -= rint(cycle);
+               if(cycle < autocvar_cl_bobup)
+                       cycle = sin(M_PI * cycle / autocvar_cl_bobup);
+               else
+                       cycle = sin(M_PI + M_PI * (cycle - autocvar_cl_bobup) / (1.0 - autocvar_cl_bobup));
+               // bob is proportional to velocity in the xy plane
+               // (don't count Z, or jumping messes it up)
+               float xyspeed = bound(0, sqrt(this.velocity.x * this.velocity.x + this.velocity.y * this.velocity.y), autocvar_cl_bob_velocity_limit);
+               bob = xyspeed * autocvar_cl_bob;
+               bob = bound(0, bob, bob_limit);
+               bob = bob * 0.3 + bob * 0.7 * cycle;
+               v.z += bob;
+       }
+
+       // horizontal view bobbing code
+       if(autocvar_cl_bob2 && autocvar_cl_bob2cycle)
+       {
+               cycle = time / autocvar_cl_bob2cycle;
+               cycle -= rint(cycle);
+               if(cycle < 0.5)
+                       cycle = cos(M_PI * cycle / 0.5); // cos looks better here with the other view bobbing using sin
+               else
+                       cycle = cos(M_PI + M_PI * (cycle - 0.5) / 0.5);
+               bob = autocvar_cl_bob2 * cycle;
+
+               // this value slowly decreases from 1 to 0 when we stop touching the ground.
+               // The cycle is later multiplied with it so the view smooths back to normal
+               if(IS_ONGROUND(this) && !(input_buttons & BIT(1))) // also block the effect while the jump button is pressed, to avoid twitches when bunny-hopping
+                       bob2_smooth = 1;
+               else
+               {
+                       if(bob2_smooth > 0)
+                               bob2_smooth -= bound(0, autocvar_cl_bob2smooth, 1);
+                       else
+                               bob2_smooth = 0;
+               }
+
+               // calculate the front and side of the player between the X and Y axes
+               makevectors(view_angles);
+               // now get the speed based on those angles. The bounds should match the same value as xyspeed's
+               float side = bound(-autocvar_cl_bob_velocity_limit, (this.velocity * v_right) * bob2_smooth, autocvar_cl_bob_velocity_limit);
+               float front = bound(-autocvar_cl_bob_velocity_limit, (this.velocity * v_forward) * bob2_smooth, autocvar_cl_bob_velocity_limit);
+               v_forward = v_forward * bob;
+               v_right = v_right * bob;
+               // we use side with forward and front with right, so the bobbing goes
+               // to the side when we walk forward and to the front when we strafe
+               vector bob2vel;
+               bob2vel.x = side * v_forward.x + front * v_right.x + 0 * v_up.x;
+               bob2vel.y = side * v_forward.y + front * v_right.y + 0 * v_up.y;
+               bob2vel.z = side * v_forward.z + front * v_right.z + 0 * v_up.z;
+               v.x += bob2vel.x;
+               v.y += bob2vel.y;
+       }
+
+       // fall bobbing code
+       // causes the view to swing down and back up when touching the ground
+       if(autocvar_cl_bobfall && autocvar_cl_bobfallcycle)
+       {
+               if(!IS_ONGROUND(this))
+               {
+                       bobfall_speed = bound(-400, this.velocity.z, 0) * bound(0, autocvar_cl_bobfall, 0.1);
+                       if(this.velocity.z < -autocvar_cl_bobfallminspeed)
+                               bobfall_swing = 1;
+                       else
+                               bobfall_swing = 0; // really?
+               }
+               else
+               {
+                       bobfall_swing = max(0, bobfall_swing - autocvar_cl_bobfallcycle * frametime);
+                       float bobfall = sin(M_PI * bobfall_swing) * bobfall_speed;
+                       v.z += bobfall;
+               }
+       }
+
+       return v;
+}
+
+float autocvar_cl_rollangle;
+float autocvar_cl_rollspeed;
+float CSQCPlayer_CalcRoll(entity this)
+{
+       makevectors(view_angles);
+       float side = (this.velocity * v_right);
+       float sign = (side < 0) ? -1 : 1;
+       side = fabs(side);
+
+       if(side < autocvar_cl_rollspeed)
+               side = side * autocvar_cl_rollangle / autocvar_cl_rollspeed;
+       else
+               side = autocvar_cl_rollangle;
+
+       return side * sign;
+}
+
+float autocvar_chase_back;
+float autocvar_chase_up;
+bool autocvar_chase_overhead;
+float autocvar_chase_pitchangle;
+vector CSQCPlayer_ApplyChase(entity this, vector v)
+{
+       vector forward;
+       vector chase_dest;
+
+       if(autocvar_chase_overhead)
+       {
+               view_angles.x = 0;
+               makevectors(view_angles);
+               forward = v_forward;
+               vector up = v_up;
+               // trace a little further so it hits a surface more consistently (to avoid 'snapping' on the edge of the range)
+               chase_dest.x = v.x - forward.x * autocvar_chase_back + up.x * autocvar_chase_up;
+               chase_dest.y = v.y - forward.y * autocvar_chase_back + up.y * autocvar_chase_up;
+               chase_dest.z = v.z - forward.z * autocvar_chase_back + up.z * autocvar_chase_up;
+
+               // trace from first person view location to our chosen third person view location
+               traceline(v, chase_dest, MOVE_NOMONSTERS, NULL);
+
+               vector bestvieworg = trace_endpos;
+               vector offset = '0 0 0';
+               for(offset.x = -16; offset.x <= 16; offset.x += 8)
+               {
+                       for(offset.y = -16; offset.y <= 16; offset.y += 8)
+                       {
+                               makevectors(view_angles);
+                               up = v_up;
+                               chase_dest.x = v.x - forward.x * autocvar_chase_back + up.x * autocvar_chase_up + offset.x;
+                               chase_dest.y = v.y - forward.y * autocvar_chase_back + up.y * autocvar_chase_up + offset.y;
+                               chase_dest.z = v.z - forward.z * autocvar_chase_back + up.z * autocvar_chase_up + offset.z;
+                               traceline(v, chase_dest, MOVE_NOMONSTERS, NULL);
+                               if(bestvieworg.z > trace_endpos.z)
+                                       bestvieworg.z = trace_endpos.z;
+                       }
+               }
+               bestvieworg.z -= 8;
+               v = bestvieworg;
+
+               view_angles.x = autocvar_chase_pitchangle;
+               //setproperty(VF_CL_VIEWANGLES, view_angles); // update view angles as well so we can aim
+       }
+       else
+       {
+               makevectors(view_angles);
+               forward = v_forward;
+               // trace a little further so it hits a surface more consistently (to avoid 'snapping' on the edge of the range)
+               float cdist = -autocvar_chase_back - 8;
+               chase_dest.x = v.x + forward.x * cdist;
+               chase_dest.y = v.y + forward.y * cdist;
+               chase_dest.z = v.z + forward.z * cdist + autocvar_chase_up;
+               traceline(v, chase_dest, MOVE_NOMONSTERS, NULL);
+               v.x = 1 * trace_endpos.x + 8 * forward.x + 4 * trace_plane_normal.x;
+               v.y = 1 * trace_endpos.y + 8 * forward.y + 4 * trace_plane_normal.y;
+               v.z = 1 * trace_endpos.z + 8 * forward.z + 4 * trace_plane_normal.z;
+       }
+
+#if 0
+       tracebox(v, '-4 -4 -4', '4 4 4', v - v_forward * autocvar_chase_back, MOVE_NORMAL, this);
+       v = trace_endpos;
+       tracebox(v, '-4 -4 -4', '4 4 4', v + v_up * autocvar_chase_up, MOVE_NORMAL, this);
+       v = trace_endpos;
+#endif
+       return v;
+}
+
+void CSQCPlayer_CalcRefdef(entity this)
+{
+       vector vieworg = this.origin;
+       if(intermission)
+       {
+               // just update view offset, don't need to do anything else
+               vieworg.z += this.view_ofs.z;
+       }
+       else
+       {
+               vieworg = CSQCPlayer_ApplySmoothing(this, vieworg);
+               if(autocvar_chase_active)
+                       vieworg = CSQCPlayer_ApplyChase(this, vieworg);
+               else
+               {
+                       // angles
+                       CSQCPlayer_ApplyDeathTilt(this);
+                       view_angles = view_angles + view_punchangle;
+                       view_angles.z += CSQCPlayer_CalcRoll(this);
+                       // TODO? we don't have damage time accessible here
+                       // origin
+                       vieworg = vieworg + view_punchvector;
+                       vieworg = CSQCPlayer_ApplyBobbing(this, vieworg);
+               }
+               CSQCPlayer_ApplyIdleScaling(this);
+       }
+       setproperty(VF_ORIGIN, vieworg);
+       setproperty(VF_ANGLES, view_angles);
+}
+
+bool autocvar_cl_useenginerefdef = true;
+
 /** Called once per CSQC_UpdateView() */
 void CSQCPlayer_SetCamera()
 {
@@ -285,13 +582,21 @@ void CSQCPlayer_SetCamera()
                        InterpolateOrigin_Do(view);
                        view.view_ofs = '0 0 1' * vh;
                }
-               int refdefflags = 0;
-               if (view.csqcmodel_teleported) refdefflags |= REFDEFFLAG_TELEPORTED;
-               if (input_buttons & BIT(1)) refdefflags |= REFDEFFLAG_JUMPING;
-               // note: these two only work in WIP2, but are harmless in WIP1
-               if (PHYS_HEALTH(NULL) <= 0 && PHYS_HEALTH(NULL) != -666 && PHYS_HEALTH(NULL) != -2342) refdefflags |= REFDEFFLAG_DEAD;
-               if (intermission) refdefflags |= REFDEFFLAG_INTERMISSION;
-               V_CalcRefdef(view, refdefflags); // TODO? uses .health stat in the engine when this isn't called here, may be broken!
+               if(autocvar_cl_useenginerefdef)
+               {
+                       int refdefflags = 0;
+                       if (view.csqcmodel_teleported) refdefflags |= REFDEFFLAG_TELEPORTED;
+                       if (input_buttons & BIT(1)) refdefflags |= REFDEFFLAG_JUMPING;
+                       // note: these two only work in WIP2, but are harmless in WIP1
+                       if (PHYS_HEALTH(NULL) <= 0 && PHYS_HEALTH(NULL) != -666 && PHYS_HEALTH(NULL) != -2342) refdefflags |= REFDEFFLAG_DEAD;
+                       if (intermission) refdefflags |= REFDEFFLAG_INTERMISSION;
+                       V_CalcRefdef(view, refdefflags); // TODO? uses .health stat in the engine when this isn't called here, may be broken!
+               }
+               else
+               {
+                       CSQCPlayer_CalcRefdef(view);
+               }
+                       
        }
        else
        {
index cbdf55375922de5420b3c81c51b244acf7f3c024..0f609cae8a98b524b86c8cd2245cc814bc190b8f 100644 (file)
@@ -8,7 +8,7 @@
 string prvm_language;
 
 /**
- * @deprecated prefer _("translated")
+ * @deprecated prefer _("translated") - GMQCC's -ftranslatable-strings feature
  */
 ERASEABLE
 string language_filename(string s)
index 33fe3575a8bde07be1326970f232e4087667cf6d..eac6f754d8082755219a8ce81c3f91ba0fad97c6 100644 (file)
@@ -161,17 +161,19 @@ void XonoticMutatorsDialog_fill(entity me)
        me.TR(me);
                me.TDempty(me, 0.2);
                me.TD(me, 1, 1.8, e = makeXonoticCheckBox_T(0, "g_dodging", _("Dodging"),
-                       _("Enable dodging")));
+                       _("Enable dodging (quick acceleration in a given direction). Double-tap a directional key to dodge")));
        me.TR(me);
                me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.8, e = makeXonoticCheckBox(0, "g_touchexplode", _("Touch explode")));
+               me.TD(me, 1, 1.8, e = makeXonoticCheckBox_T(0, "g_touchexplode", _("Touch explode"),
+                        _("An explosion occurs when two players collide")));
        me.TR(me);
                me.TDempty(me, 0.2);
                me.TD(me, 1, 1.8, e = makeXonoticCheckBox_T(0, "g_cloaked", _("Cloaked"),
                        _("All players are almost invisible")));
        me.TR(me);
                me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.8, e = makeXonoticCheckBox(0, "g_buffs", _("Buffs")));
+               me.TD(me, 1, 1.8, e = makeXonoticCheckBox_T(0, "g_buffs", _("Buffs"),
+                        _("Enable buff pickups (random bonuses like Medic, Invisible, etc.) on the maps that support it")));
                        e.cvarOffValue = "-1"; // TODO: make this a radio button?
        me.TR(me);
                me.TDempty(me, 0.2);
@@ -185,7 +187,7 @@ void XonoticMutatorsDialog_fill(entity me)
        me.TR(me);
                me.TDempty(me, 0.2);
                s = makeXonoticSlider_T(10, 50, 1, "g_bloodloss",
-                       _("Amount of health below which your player gets stunned because of blood loss"));
+                       _("Amount of health below which players start bleeding out (health rots and they can't jump)"));
                me.TD(me, 1, 1.8, e = makeXonoticSliderCheckBox(0, 1, s, _("Blood loss")));
                        setDependent(e, "g_instagib", 0, 0);
        me.TR(me);
@@ -194,7 +196,7 @@ void XonoticMutatorsDialog_fill(entity me)
        me.TR(me);
                me.TDempty(me, 0.2);
                s = makeXonoticSlider_T(80, 400, 8, "sv_gravity",
-                       _("Make things fall to the ground slower, lower value means lower gravity"));
+                       _("Make things fall to the ground slower (percentage of normal gravity)"));
                        s.valueDigits = 0;
                        s.valueDisplayMultiplier = 0.125; // show gravity in percent
                me.TD(me, 1, 1.8, e = makeXonoticSliderCheckBox(800, 1, s, _("Low gravity")));
@@ -207,22 +209,25 @@ void XonoticMutatorsDialog_fill(entity me)
        me.TR(me);
                me.TDempty(me, 0.2);
                me.TD(me, 1, 1.8, e = makeXonoticCheckBox_T(0, "g_grappling_hook", _("Grappling hook"),
-                       _("Players spawn with the grappling hook")));
+                       _("Players spawn with the grappling hook. Press the 'hook' key to use it")));
        me.TR(me);
                me.TDempty(me, 0.2);
                me.TD(me, 1, 1.8, e = makeXonoticCheckBox_T(0, "g_jetpack", _("Jetpack"),
-                       _("Players spawn with the jetpack")));
+                       _("Players spawn with the jetpack. Double-tap 'jump' or press the 'jetpack' key to use it")));
        me.TR(me);
                me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.8, e = makeXonoticCheckBox(0, "g_invincible_projectiles", _("Invincible Projectiles")));
+               me.TD(me, 1, 1.8, e = makeXonoticCheckBox_T(0, "g_invincible_projectiles", _("Invincible Projectiles"),
+                        _("Projectiles can't be destroyed. However, Electro combos still work")));
                        setDependent(e, "g_instagib", 0, 0);
        me.TR(me);
                me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.8, e = makeXonoticCheckBox(0, "g_new_toys", _("New Toys")));
+               me.TD(me, 1, 1.8, e = makeXonoticCheckBox_T(0, "g_new_toys", _("New Toys"),
+                        _("Some weapon spawns will be randomly replaced with new weapons: Heavy Laser Assault Cannon, Mine Layer, Rifle, T.A.G. Seeker")));
                        setDependentWeird(e, checkCompatibility_newtoys);
        me.TR(me);
                me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.8, e = makeXonoticCheckBox(0, "g_rocket_flying", _("Rocket Flying")));
+               me.TD(me, 1, 1.8, e = makeXonoticCheckBox_T(0, "g_rocket_flying", _("Rocket Flying"),
+                        _("Devastator rockets can be detonated instantly (otherwise, there's a short delay). This allows players to fire and detonate a Devastator rocket while in the air for a strong mid-air boost even while moving fast")));
                        setDependent(e, "g_instagib", 0, 0);
        me.TR(me);
                me.TDempty(me, 0.2);
index dc39346aa61f962f323964e81b05eccec083dc4f..b2ae8c0ba9269752bbeddf82c4beb723d5cf8e70 100644 (file)
@@ -128,8 +128,8 @@ void XonoticSingleplayerDialog_fill(entity me)
        me.gotoRC(me, me.rows - 2, 0);
                me.TD(me, 1, 2, e = makeXonoticTextLabel(0.5, _("Campaign Difficulty:")));
                me.TD(me, 1, 1, e = makeXonoticRadioButton(1, "g_campaign_skill", "-2", ZCTX(_("CSKL^Easy"))));
-               me.TD(me, 1, 1, e = makeXonoticRadioButton(1, "g_campaign_skill", "-1", ZCTX(_("CSKL^Medium"))));
-               me.TD(me, 1, 1, e = makeXonoticRadioButton(1, "g_campaign_skill", "0", ZCTX(_("CSKL^Hard"))));
+               me.TD(me, 1, 1, e = makeXonoticRadioButton(1, "g_campaign_skill", "0", ZCTX(_("CSKL^Medium"))));
+               me.TD(me, 1, 1, e = makeXonoticRadioButton(1, "g_campaign_skill", "2", ZCTX(_("CSKL^Hard"))));
                me.TR(me);
                me.TD(me, 1, me.columns, e = makeXonoticButton(_("Start Singleplayer!"), '0 0 0'));
                        e.onClick = CampaignList_LoadMap;
index 76e2cdeb8480069230118925719d77d9e105ae5b..6fdb6d33986a3afecfe0259e2c272b8d95a16304 100644 (file)
@@ -98,11 +98,7 @@ void CampaignPreInit()
                return;
        }
 
-       baseskill = autocvar_g_campaign_skill;
-       baseskill = baseskill + campaign_botskill[0];
-       if(baseskill < 0)
-               baseskill = 0;
-
+       baseskill = max(0, autocvar_g_campaign_skill + campaign_botskill[0]);
        campaign_forcewin = false;
 
        cvar_set("sv_public", "0");
index f44d9c96f969fa5853216a289a2d8c7e0bdeffb9..4fd0ee0c1488965a1eae4bd06164ab018a710b4e 100644 (file)
@@ -48,7 +48,7 @@ fs_empty_files_in_pack_mark_deletions 1 // makes patches able to delete files
 set g_campaign 0
 set g_campaign_forceteam 0 "Forces the player to a given team in campaign mode, 1 = red, 2 = blue, 3 = yellow, 4 = pink"
 seta g_campaign_name "xonoticbeta"
-seta g_campaign_skill -1 // -2 easy -1 medium 0 hard
+seta g_campaign_skill 0 // -2 easy, 0 medium, 2 hard
 
 alias singleplayer_start "g_campaign_index 0; set scmenu_campaign_goto 0"
 alias singleplayer_continue "set scmenu_campaign_goto -1"