Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/hud-workshop.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ jobs:
nade2_hud.vxml_c nade2_pick.vxml_c \
nade2_run.vxml_c nade2_edit.vxml_c nade2_bar.vxml_c \
nade2_wheel.vxml_c nadehud2.vcss_c nadewheel2.vcss_c \
nade3_edit.vxml_c nade3_bar.vxml_c nadebar3.vcss_c
nade3_edit.vxml_c nade3_bar.vxml_c nade4_bar.vxml_c nadebar3.vcss_c
do
case "$TREE" in
*"$expected"*) ;;
Expand Down
4 changes: 2 additions & 2 deletions apps/utility-sw/hud/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ it through `CCSCustomHudLayout`.

| Layout | Captures input | What it is |
| --- | --- | --- |
| `nade3_bar` | no | Everything on screen while you play: a compass with a grenade icon per spot, coloured by type, what the keys do right now, and what the last key did. On the right, what utility is out and for how long, and the plan or stack being worked through. In the middle, for a few seconds, what a flash did. |
| `nade4_bar` | no | Everything on screen while you play: a compass with a grenade icon per spot, coloured by type, what the keys do right now, and what the last key did. On the right, what utility is out and for how long, and the plan or stack being worked through. In the middle, for a few seconds, what a flash did. |
| `nade2_hud` | no | The throw card, bottom right: where it lands, a drawn mouse and keycaps for how to throw it, the run-up, live aim error, and how far along the run of landed throws that counts as mastered. |
| `nade2_wheel` | yes | TAB. Eight wedges around a hub, an outer ring of two more over each, and wedges that open a wheel of their own. Beside it, what the keys do. Generated with `nadewheel2.css` by `wheel.py`: edit that and run it, never the two files. |
| `nade2_pick` | yes | Choosing a lineup: the map with a marker per landing spot beside the list, under one set of filter chips. |
Expand All @@ -21,7 +21,7 @@ what changed on the compass once `nadehud2.css` was published. `nade_hud`, `nade
servers still on a plugin that asks for them; nothing in this repo drives them
any more. Neither does it drive `nade2_edit`, superseded by `nade3_edit` because its
buttons used classes `nadehud2.css` never styled, nor `nade2_bar`, superseded by
`nade3_bar` because every compass pip was the same grey. `HudSlots.cs` has the rule for when a name has to change.
`nade3_bar` because every compass pip was the same grey, and `nade4_bar` for the legend row that spawns a lineup's bots. `HudSlots.cs` has the rule for when a name has to change.

Passive layouts must never capture input — a panel that takes the cursor while
somebody is aiming takes the shot with it.
Expand Down
130 changes: 130 additions & 0 deletions apps/utility-sw/hud/panorama/layout/custom_game/nade4_bar.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
<root>
<styles>
<include src="s2r://panorama/styles/custom_game/nadehud2.vcss_c" />
<include src="s2r://panorama/styles/custom_game/nadebar3.vcss_c" />
</styles>
<Panel class="nh-screen" hittest="false">
<Panel id="NadeBar" class="nh-bar" hittest="false">
<Panel class="nh-top" hittest="false">
<Panel id="compass" class="nh-compass" hittest="false">
<Panel class="nh-compass-ribbon" hittest="false">
<Panel class="nh-compass-tick" hittest="false" />
<Panel id="p1" class="nh-pip" hittest="false" />
<Panel id="p2" class="nh-pip" hittest="false" />
<Panel id="p3" class="nh-pip" hittest="false" />
<Panel id="p4" class="nh-pip" hittest="false" />
<Panel id="p5" class="nh-pip" hittest="false" />
<Panel id="p6" class="nh-pip" hittest="false" />
<Panel id="p7" class="nh-pip" hittest="false" />
<Panel id="p8" class="nh-pip" hittest="false" />
</Panel>
<Panel class="nh-compass-line" hittest="false" />
<Panel class="nh-compass-foot" hittest="false">
<Label id="cleft" class="nh-compass-more" text="{s:cleft}" />
<Label id="cfocus" class="nh-compass-focus" text="{s:cfocus}" />
<Label id="cright" class="nh-compass-more nh-compass-right" text="{s:cright}" />
</Panel>
</Panel>
</Panel>

<Panel id="legend" class="nh-legend" hittest="false">
<Panel id="kr1" class="nh-key-row" hittest="false"><Panel class="nh-key-col" hittest="false"><Label id="kc1" class="nh-keycap" text="{g:csgo_key:kb1}" /></Panel><Label id="k1" class="nh-key-label" text="{s:k1}" /></Panel>
<Panel id="kr2" class="nh-key-row" hittest="false"><Panel class="nh-key-col" hittest="false"><Label id="kc2" class="nh-keycap" text="{g:csgo_key:kb2}" /></Panel><Label id="k2" class="nh-key-label" text="{s:k2}" /></Panel>
<Panel id="kr3" class="nh-key-row" hittest="false"><Panel class="nh-key-col" hittest="false"><Label id="kc3" class="nh-keycap" text="{g:csgo_key:kb3}" /></Panel><Label id="k3" class="nh-key-label" text="{s:k3}" /></Panel>
<Panel id="kr4" class="nh-key-row" hittest="false"><Panel class="nh-key-col" hittest="false"><Label id="kc4" class="nh-keycap" text="{g:csgo_key:kb4}" /><Label class="nh-key-twice" text="×2" /></Panel><Label id="k4" class="nh-key-label" text="{s:k4}" /></Panel>
<Panel id="kr5" class="nh-key-row" hittest="false"><Panel class="nh-key-col" hittest="false"><Label id="kc5" class="nh-keycap" text="{g:csgo_key:kb5}" /></Panel><Label id="k5" class="nh-key-label" text="{s:k5}" /></Panel>
<Panel id="kr6" class="nh-key-row" hittest="false"><Panel class="nh-key-col" hittest="false"><Label id="kc6" class="nh-keycap" text="{g:csgo_key:kb6}" /><Label class="nh-key-twice" text="×2" /></Panel><Label id="k6" class="nh-key-label" text="{s:k6}" /></Panel>
<Panel id="kr7" class="nh-key-row" hittest="false"><Panel class="nh-key-col" hittest="false"><Label id="kc7" class="nh-keycap" text="{g:csgo_key:kb7}" /><Label class="nh-key-twice" text="×2" /></Panel><Label id="k7" class="nh-key-label" text="{s:k7}" /></Panel>
<Panel id="kr8" class="nh-key-row" hittest="false"><Panel class="nh-key-col" hittest="false"><Label id="kc8" class="nh-keycap" text="{g:csgo_key:kb8}" /></Panel><Label id="k8" class="nh-key-label" text="{s:k8}" /></Panel>
</Panel>

<Panel class="nh-right" hittest="false">
<Panel id="out" class="nh-out" hittest="false">
<Panel class="nh-out-head" hittest="false">
<Label class="nh-out-title" text="RECENT UTILITY" />
<Label id="ocount" class="nh-out-count" text="{s:ocount}" />
</Panel>
<Panel id="or1" class="nh-out-row" hittest="false">
<Panel class="nh-out-line" hittest="false"><Panel class="nh-out-icon" hittest="false" /><Panel class="nh-out-text" hittest="false"><Label id="on1" class="nh-out-name" text="{s:on1}" /><Panel class="nh-out-sub" hittest="false"><Label id="of1" class="nh-out-flight" text="{s:of1}" /><Label id="os1" class="nh-out-score" text="{s:os1}" /></Panel></Panel><Label id="ot1" class="nh-out-time" text="{s:ot1}" /></Panel>
<Panel class="nh-out-track" hittest="false"><Panel id="ob1" class="nh-out-fill" hittest="false" /></Panel>
</Panel>
<Panel id="or2" class="nh-out-row" hittest="false">
<Panel class="nh-out-line" hittest="false"><Panel class="nh-out-icon" hittest="false" /><Panel class="nh-out-text" hittest="false"><Label id="on2" class="nh-out-name" text="{s:on2}" /><Panel class="nh-out-sub" hittest="false"><Label id="of2" class="nh-out-flight" text="{s:of2}" /><Label id="os2" class="nh-out-score" text="{s:os2}" /></Panel></Panel><Label id="ot2" class="nh-out-time" text="{s:ot2}" /></Panel>
<Panel class="nh-out-track" hittest="false"><Panel id="ob2" class="nh-out-fill" hittest="false" /></Panel>
</Panel>
<Panel id="or3" class="nh-out-row" hittest="false">
<Panel class="nh-out-line" hittest="false"><Panel class="nh-out-icon" hittest="false" /><Panel class="nh-out-text" hittest="false"><Label id="on3" class="nh-out-name" text="{s:on3}" /><Panel class="nh-out-sub" hittest="false"><Label id="of3" class="nh-out-flight" text="{s:of3}" /><Label id="os3" class="nh-out-score" text="{s:os3}" /></Panel></Panel><Label id="ot3" class="nh-out-time" text="{s:ot3}" /></Panel>
<Panel class="nh-out-track" hittest="false"><Panel id="ob3" class="nh-out-fill" hittest="false" /></Panel>
</Panel>
<Panel id="or4" class="nh-out-row" hittest="false">
<Panel class="nh-out-line" hittest="false"><Panel class="nh-out-icon" hittest="false" /><Panel class="nh-out-text" hittest="false"><Label id="on4" class="nh-out-name" text="{s:on4}" /><Panel class="nh-out-sub" hittest="false"><Label id="of4" class="nh-out-flight" text="{s:of4}" /><Label id="os4" class="nh-out-score" text="{s:os4}" /></Panel></Panel><Label id="ot4" class="nh-out-time" text="{s:ot4}" /></Panel>
<Panel class="nh-out-track" hittest="false"><Panel id="ob4" class="nh-out-fill" hittest="false" /></Panel>
</Panel>
<Panel id="or5" class="nh-out-row" hittest="false">
<Panel class="nh-out-line" hittest="false"><Panel class="nh-out-icon" hittest="false" /><Panel class="nh-out-text" hittest="false"><Label id="on5" class="nh-out-name" text="{s:on5}" /><Panel class="nh-out-sub" hittest="false"><Label id="of5" class="nh-out-flight" text="{s:of5}" /><Label id="os5" class="nh-out-score" text="{s:os5}" /></Panel></Panel><Label id="ot5" class="nh-out-time" text="{s:ot5}" /></Panel>
<Panel class="nh-out-track" hittest="false"><Panel id="ob5" class="nh-out-fill" hittest="false" /></Panel>
</Panel>
<Panel id="or6" class="nh-out-row" hittest="false">
<Panel class="nh-out-line" hittest="false"><Panel class="nh-out-icon" hittest="false" /><Panel class="nh-out-text" hittest="false"><Label id="on6" class="nh-out-name" text="{s:on6}" /><Panel class="nh-out-sub" hittest="false"><Label id="of6" class="nh-out-flight" text="{s:of6}" /><Label id="os6" class="nh-out-score" text="{s:os6}" /></Panel></Panel><Label id="ot6" class="nh-out-time" text="{s:ot6}" /></Panel>
<Panel class="nh-out-track" hittest="false"><Panel id="ob6" class="nh-out-fill" hittest="false" /></Panel>
</Panel>
<Label id="omore" class="nh-out-more" text="{s:omore}" />
</Panel>

<Panel id="plan" class="nh-plan" hittest="false">
<Panel class="nh-plan-head" hittest="false">
<Label id="pltitle" class="nh-plan-title" text="{s:pltitle}" />
<Label id="plsub" class="nh-plan-sub" text="{s:plsub}" />
</Panel>
<Panel id="plr1" class="nh-plan-row" hittest="false"><Label id="pl1" class="nh-plan-name" text="{s:pl1}" /><Label id="plv1" class="nh-plan-val" text="{s:plv1}" /></Panel>
<Panel id="plr2" class="nh-plan-row" hittest="false"><Label id="pl2" class="nh-plan-name" text="{s:pl2}" /><Label id="plv2" class="nh-plan-val" text="{s:plv2}" /></Panel>
<Panel id="plr3" class="nh-plan-row" hittest="false"><Label id="pl3" class="nh-plan-name" text="{s:pl3}" /><Label id="plv3" class="nh-plan-val" text="{s:plv3}" /></Panel>
<Panel id="plr4" class="nh-plan-row" hittest="false"><Label id="pl4" class="nh-plan-name" text="{s:pl4}" /><Label id="plv4" class="nh-plan-val" text="{s:plv4}" /></Panel>
<Panel id="plr5" class="nh-plan-row" hittest="false"><Label id="pl5" class="nh-plan-name" text="{s:pl5}" /><Label id="plv5" class="nh-plan-val" text="{s:plv5}" /></Panel>
<Panel id="plr6" class="nh-plan-row" hittest="false"><Label id="pl6" class="nh-plan-name" text="{s:pl6}" /><Label id="plv6" class="nh-plan-val" text="{s:plv6}" /></Panel>
<Label id="plfoot" class="nh-plan-foot" text="{s:plfoot}" />
</Panel>
</Panel>

<Panel id="flash" class="nh-flash" hittest="false">
<Panel class="nh-flash-head" hittest="false">
<Label id="fltitle" class="nh-flash-title" text="{s:fltitle}" />
<Label id="flsub" class="nh-flash-sub" text="{s:flsub}" />
</Panel>
<Panel id="fr1" class="nh-flash-row" hittest="false">
<Label id="fw1" class="nh-flash-who" text="{s:fw1}" />
<Panel class="nh-flash-track" hittest="false"><Panel id="fa1" class="nh-flash-fade" hittest="false" /><Panel id="fu1" class="nh-flash-full" hittest="false" /></Panel>
<Label id="fs1" class="nh-flash-secs" text="{s:fs1}" />
<Label id="fg1" class="nh-flash-tag" text="{s:fg1}" />
</Panel>
<Panel id="fr2" class="nh-flash-row" hittest="false">
<Label id="fw2" class="nh-flash-who" text="{s:fw2}" />
<Panel class="nh-flash-track" hittest="false"><Panel id="fa2" class="nh-flash-fade" hittest="false" /><Panel id="fu2" class="nh-flash-full" hittest="false" /></Panel>
<Label id="fs2" class="nh-flash-secs" text="{s:fs2}" />
<Label id="fg2" class="nh-flash-tag" text="{s:fg2}" />
</Panel>
<Panel id="fr3" class="nh-flash-row" hittest="false">
<Label id="fw3" class="nh-flash-who" text="{s:fw3}" />
<Panel class="nh-flash-track" hittest="false"><Panel id="fa3" class="nh-flash-fade" hittest="false" /><Panel id="fu3" class="nh-flash-full" hittest="false" /></Panel>
<Label id="fs3" class="nh-flash-secs" text="{s:fs3}" />
<Label id="fg3" class="nh-flash-tag" text="{s:fg3}" />
</Panel>
<Panel id="fr4" class="nh-flash-row" hittest="false">
<Label id="fw4" class="nh-flash-who" text="{s:fw4}" />
<Panel class="nh-flash-track" hittest="false"><Panel id="fa4" class="nh-flash-fade" hittest="false" /><Panel id="fu4" class="nh-flash-full" hittest="false" /></Panel>
<Label id="fs4" class="nh-flash-secs" text="{s:fs4}" />
<Label id="fg4" class="nh-flash-tag" text="{s:fg4}" />
</Panel>
<Panel id="fr5" class="nh-flash-row" hittest="false">
<Label id="fw5" class="nh-flash-who" text="{s:fw5}" />
<Panel class="nh-flash-track" hittest="false"><Panel id="fa5" class="nh-flash-fade" hittest="false" /><Panel id="fu5" class="nh-flash-full" hittest="false" /></Panel>
<Label id="fs5" class="nh-flash-secs" text="{s:fs5}" />
<Label id="fg5" class="nh-flash-tag" text="{s:fg5}" />
</Panel>
<Label id="flfoot" class="nh-flash-foot" text="{s:flfoot}" />
</Panel>

<Label id="toast" class="nh-toast" text="{s:toast}" />
</Panel>
</Panel>
</root>
6 changes: 6 additions & 0 deletions apps/utility-sw/src/Commands/Practice.cs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ private void SaveThrow(ulong steamId, string name)
thrown.side = player.Controller.Team == Team.CT ? "CT" : "TERRORIST";
thrown.visibility = nameof(eLineupVisibility.Private);
thrown.plugin_version = ModuleVersion;
thrown.bots = LineupBots.Snapshot(_bots, MaxBots);

_library.Add(steamId, thrown);

Expand All @@ -157,6 +158,11 @@ private void SaveThrow(ulong steamId, string name)

Tell(steamId, $" {ChatColors.Green}saved {ChatColors.Default}{name}");

if (thrown.bots.Count > 0)
{
Toast(player, $"Saved · {BotCount(thrown.bots.Count)} kept with it");
}

// A smoke saved straight after it went off is still spreading, and the
// panel keeps the first cloud a lineup gets. The save waits the few
// seconds for it rather than going without -- see SmokeSettled.
Expand Down
20 changes: 19 additions & 1 deletion apps/utility-sw/src/Hud/PracticeActions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,17 @@ private WheelPage WheelFor(IPlayer player, string page)
"Place A Bot",
_bots.Count == 0 ? "where I stand" : $"{_bots.Count} of {MaxBots}",
Disabled: BotSlotsLeft() == 0
),
)
{
Quick = new WheelItem?[]
{
new WheelItem(
"keepbots",
"Keep On Lineup",
Disabled: _bots.Count == 0 || KeepTarget(player) == null
),
},
},
new WheelItem(
"nobots",
"Remove Bots",
Expand Down Expand Up @@ -906,6 +916,14 @@ private void Do(IPlayer player, string action)
ClearBots();
Toast(player, "Bots removed");

break;
case "lineupbots":
SpawnLineupBots(player);

break;
case "keepbots":
KeepBotsOnLineup(player);

break;
case "spawns":
ToggleSpawns(player);
Expand Down
1 change: 1 addition & 0 deletions apps/utility-sw/src/Hud/PracticeBar.cs
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,7 @@ bool cleared
UseKey(steamId, at, cleared),
new NadeBarTemplate.Key(reload, zoomed || following),
new NadeBarTemplate.Key("Add a bot here"),
BotKey(player, pawn, at),
new NadeBarTemplate.Key(noclip ? "Noclip · on" : "Noclip", noclip),
AimRingKey(steamId),
new NadeBarTemplate.Key("Clear smoke and fire · twice for bots"),
Expand Down
17 changes: 15 additions & 2 deletions apps/utility-sw/src/Hud/PracticeKeys.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ namespace UtilityPractice;
// behind it. That one needs no rule either -- there is nothing to throw again
// until the first has landed.
//
// Drop is taken outright: a server where nothing runs out has no use for it, so
// it stands up the bots saved on a lineup instead, on whatever key it is bound
// to.
//
// Crouch and walk keep their jobs and gain one each on a double tap, which is
// a thing nobody does to either by accident: a bot where you stand, and
// noclip.
Expand All @@ -40,6 +44,8 @@ public partial class UtilityPracticePlugin
// What the default bind for delete sends.
private const string SellBackCommand = "sellbackall";

private const string DropCommand = "drop";

// Two presses of one key inside a third of a second are one gesture.
private const int DoubleTapTicks = 21;

Expand Down Expand Up @@ -87,7 +93,7 @@ private HookResult OnClientCommand(int playerId, string commandLine)

string command = commandLine.Trim().Split(' ')[0];

if (command != SellBackCommand)
if (command != SellBackCommand && command != DropCommand)
{
return HookResult.Continue;
}
Expand All @@ -103,7 +109,14 @@ private HookResult OnClientCommand(int playerId, string commandLine)

try
{
ClearPressed(player);
if (command == SellBackCommand)
{
ClearPressed(player);
}
else if (!CursorOpen(player))
{
Do(player, "lineupbots");
}
}
catch (Exception error)
{
Expand Down
Loading
Loading