Simplify clipped circle pictures (e.g. crosshair ring).
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / gamemodes / gamemode / ctf / cl_ctf.qc
1 #include "cl_ctf.qh"
2
3 #include <client/hud/panel/modicons.qh>
4
5 // CTF HUD modicon section
6 int redflag_prevframe, blueflag_prevframe, yellowflag_prevframe, pinkflag_prevframe, neutralflag_prevframe; // status during previous frame
7 int redflag_prevstatus, blueflag_prevstatus, yellowflag_prevstatus, pinkflag_prevstatus, neutralflag_prevstatus; // last remembered status
8 float redflag_statuschange_time, blueflag_statuschange_time, yellowflag_statuschange_time, pinkflag_statuschange_time, neutralflag_statuschange_time; // time when the status changed
9
10 void HUD_Mod_CTF_Reset()
11 {
12     redflag_prevstatus = blueflag_prevstatus = yellowflag_prevstatus = pinkflag_prevstatus = neutralflag_prevstatus = 0;
13     redflag_prevframe = blueflag_prevframe = yellowflag_prevframe = pinkflag_prevframe = neutralflag_prevframe = 0;
14     redflag_statuschange_time = blueflag_statuschange_time = yellowflag_statuschange_time = pinkflag_statuschange_time = neutralflag_statuschange_time = 0;
15 }
16
17 int autocvar__teams_available;
18 void HUD_Mod_CTF(vector pos, vector mySize)
19 {
20     vector redflag_pos, blueflag_pos, yellowflag_pos, pinkflag_pos, neutralflag_pos;
21     vector flag_size;
22     float f; // every function should have that
23
24     int redflag, blueflag, yellowflag, pinkflag, neutralflag; // current status
25     float redflag_statuschange_elapsedtime = 0, blueflag_statuschange_elapsedtime = 0, yellowflag_statuschange_elapsedtime = 0, pinkflag_statuschange_elapsedtime = 0, neutralflag_statuschange_elapsedtime = 0; // time since the status changed
26     bool ctf_oneflag; // one-flag CTF mode enabled/disabled
27     bool ctf_stalemate; // currently in stalemate
28     int stat_items = STAT(CTF_FLAGSTATUS);
29     float fs, fs2, fs3, size1, size2;
30     vector e1, e2;
31
32     int nteams = autocvar__teams_available;
33
34     redflag = (stat_items/CTF_RED_FLAG_TAKEN) & 3;
35     blueflag = (stat_items/CTF_BLUE_FLAG_TAKEN) & 3;
36     yellowflag = (stat_items/CTF_YELLOW_FLAG_TAKEN) & 3;
37     pinkflag = (stat_items/CTF_PINK_FLAG_TAKEN) & 3;
38     neutralflag = (stat_items/CTF_NEUTRAL_FLAG_TAKEN) & 3;
39
40     ctf_oneflag = (stat_items & CTF_FLAG_NEUTRAL);
41
42     ctf_stalemate = (stat_items & CTF_STALEMATE);
43
44     mod_active = (redflag || blueflag || yellowflag || pinkflag || neutralflag || (stat_items & CTF_SHIELDED));
45
46     if (autocvar__hud_configure) {
47         redflag = 1;
48         blueflag = 2;
49         if (nteams & BIT(2))
50             yellowflag = 2;
51         if (nteams & BIT(3))
52             pinkflag = 3;
53         ctf_oneflag = neutralflag = 0; // disable neutral flag in hud editor?
54     }
55
56     // when status CHANGES, set old status into prevstatus and current status into status
57     #define X(team) MACRO_BEGIN \
58         if (team##flag != team##flag_prevframe) { \
59             team##flag_statuschange_time = time; \
60             team##flag_prevstatus = team##flag_prevframe; \
61             team##flag_prevframe = team##flag; \
62         } \
63         team##flag_statuschange_elapsedtime = time - team##flag_statuschange_time; \
64     MACRO_END
65     X(red);
66     X(blue);
67     X(yellow);
68     X(pink);
69     X(neutral);
70     #undef X
71
72     const float BLINK_FACTOR = 0.15;
73     const float BLINK_BASE = 0.85;
74     // note:
75     //   RMS = sqrt(BLINK_BASE^2 + 0.5 * BLINK_FACTOR^2)
76     // thus
77     //   BLINK_BASE = sqrt(RMS^2 - 0.5 * BLINK_FACTOR^2)
78     // ensure RMS == 1
79     const float BLINK_FREQ = 5; // circle frequency, = 2*pi*frequency in hertz
80
81     #define X(team, cond) \
82     string team##_icon = string_null, team##_icon_prevstatus = string_null; \
83     int team##_alpha, team##_alpha_prevstatus; \
84     team##_alpha = team##_alpha_prevstatus = 1; \
85     MACRO_BEGIN \
86         switch (team##flag) { \
87             case 1: team##_icon = "flag_" #team "_taken"; break; \
88             case 2: team##_icon = "flag_" #team "_lost"; break; \
89             case 3: team##_icon = "flag_" #team "_carrying"; team##_alpha = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ); break; \
90             default: \
91                 if ((stat_items & CTF_SHIELDED) && (cond)) { \
92                     team##_icon = "flag_" #team "_shielded"; \
93                 } else { \
94                     team##_icon = string_null; \
95                 } \
96                 break; \
97         } \
98         switch (team##flag_prevstatus) { \
99             case 1: team##_icon_prevstatus = "flag_" #team "_taken"; break; \
100             case 2: team##_icon_prevstatus = "flag_" #team "_lost"; break; \
101             case 3: team##_icon_prevstatus = "flag_" #team "_carrying"; team##_alpha_prevstatus = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ); break; \
102             default: \
103                 if (team##flag == 3) { \
104                     team##_icon_prevstatus = "flag_" #team "_carrying"; /* make it more visible */\
105                 } else if((stat_items & CTF_SHIELDED) && (cond)) { \
106                     team##_icon_prevstatus = "flag_" #team "_shielded"; \
107                 } else { \
108                     team##_icon_prevstatus = string_null; \
109                 } \
110                 break; \
111         } \
112     MACRO_END
113     X(red, myteam != NUM_TEAM_1 && (nteams & BIT(0)));
114     X(blue, myteam != NUM_TEAM_2 && (nteams & BIT(1)));
115     X(yellow, myteam != NUM_TEAM_3 && (nteams & BIT(2)));
116     X(pink, myteam != NUM_TEAM_4 && (nteams & BIT(3)));
117     X(neutral, ctf_oneflag);
118     #undef X
119
120     int tcount = 2;
121     if(nteams & BIT(2))
122         tcount = 3;
123     if(nteams & BIT(3))
124         tcount = 4;
125
126     if (ctf_oneflag) {
127         // hacky, but these aren't needed
128         red_icon = red_icon_prevstatus = blue_icon = blue_icon_prevstatus = yellow_icon = yellow_icon_prevstatus = pink_icon = pink_icon_prevstatus = string_null;
129         fs = fs2 = fs3 = 1;
130     } else switch (tcount) {
131         default:
132         case 2: fs = 0.5; fs2 = 0.5; fs3 = 0.5; break;
133         case 3: fs = 1; fs2 = 0.35; fs3 = 0.35; break;
134         case 4: fs = 0.75; fs2 = 0.25; fs3 = 0.5; break;
135     }
136
137     if (mySize_x > mySize_y) {
138         size1 = mySize_x;
139         size2 = mySize_y;
140         e1 = eX;
141         e2 = eY;
142     } else {
143         size1 = mySize_y;
144         size2 = mySize_x;
145         e1 = eY;
146         e2 = eX;
147     }
148
149     switch (myteam) {
150         default:
151         case NUM_TEAM_1: {
152             redflag_pos = pos;
153             blueflag_pos = pos + eX * fs2 * size1;
154             yellowflag_pos = pos - eX * fs2 * size1;
155             pinkflag_pos = pos + eX * fs3 * size1;
156             break;
157         }
158         case NUM_TEAM_2: {
159             redflag_pos = pos + eX * fs2 * size1;
160             blueflag_pos = pos;
161             yellowflag_pos = pos - eX * fs2 * size1;
162             pinkflag_pos = pos + eX * fs3 * size1;
163             break;
164         }
165         case NUM_TEAM_3: {
166             redflag_pos = pos + eX * fs3 * size1;
167             blueflag_pos = pos - eX * fs2 * size1;
168             yellowflag_pos = pos;
169             pinkflag_pos = pos + eX * fs2 * size1;
170             break;
171         }
172         case NUM_TEAM_4: {
173             redflag_pos = pos - eX * fs2 * size1;
174             blueflag_pos = pos + eX * fs3 * size1;
175             yellowflag_pos = pos + eX * fs2 * size1;
176             pinkflag_pos = pos;
177             break;
178         }
179     }
180     neutralflag_pos = pos;
181     flag_size = e1 * fs * size1 + e2 * size2;
182
183     #define X(team) MACRO_BEGIN \
184         f = bound(0, team##flag_statuschange_elapsedtime * 2, 1); \
185         if (team##_icon && ctf_stalemate) \
186             drawpic_aspect_skin(team##flag_pos, "flag_stalemate", flag_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL); \
187         if (team##_icon_prevstatus && f < 1) \
188             drawpic_aspect_skin_expanding(team##flag_pos, team##_icon_prevstatus, flag_size, '1 1 1', panel_fg_alpha * team##_alpha_prevstatus, DRAWFLAG_NORMAL, f); \
189         if (team##_icon) \
190             drawpic_aspect_skin(team##flag_pos, team##_icon, flag_size, '1 1 1', panel_fg_alpha * team##_alpha * f, DRAWFLAG_NORMAL); \
191     MACRO_END
192     X(red);
193     X(blue);
194     X(yellow);
195     X(pink);
196     X(neutral);
197     #undef X
198 }