38614c7d4629481c9c8fafeb6b029b533e263491
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / minigames / cl_minigames.qc
1 #include "cl_minigames.qh"
2
3 // Draw a square in the center of the avaliable area
4 void minigame_hud_simpleboard(vector pos, vector mySize, string board_texture)
5 {
6         if(panel.current_panel_bg != "0" && panel.current_panel_bg != "")
7                 draw_BorderPicture(pos - '1 1 0' * panel_bg_border,
8                                         panel.current_panel_bg,
9                                         mySize + '1 1 0' * 2 * panel_bg_border,
10                                         panel_bg_color, panel_bg_alpha,
11                                          '1 1 0' * (panel_bg_border/BORDER_MULTIPLIER));
12         drawpic(pos, board_texture, mySize, '1 1 1', panel_bg_alpha, DRAWFLAG_NORMAL);
13 }
14
15 // De-normalize (2D vector) v from relative coordinate inside pos mySize
16 vector minigame_hud_denormalize(vector v, vector pos, vector mySize)
17 {
18         v_x = pos_x + v_x * mySize_x;
19         v_y = pos_y + v_y * mySize_y;
20         return v;
21 }
22 // De-normalize (2D vector) v from relative size inside pos mySize
23 vector minigame_hud_denormalize_size(vector v, vector pos, vector mySize)
24 {
25         v_x = v_x * mySize_x;
26         v_y = v_y * mySize_y;
27         return v;
28 }
29
30 // Normalize (2D vector) v to relative coordinate inside pos mySize
31 vector minigame_hud_normalize(vector v, vector pos, vector mySize)
32 {
33         v_x = ( v_x - pos_x ) / mySize_x;
34         v_y = ( v_y - pos_y ) / mySize_y;
35         return v;
36 }
37
38 // Check if the mouse is inside the given area
39 bool minigame_hud_mouse_in(vector pos, vector sz)
40 {
41         return mousepos_x >= pos_x && mousepos_x < pos_x + sz_x &&
42                mousepos_y >= pos_y && mousepos_y < pos_y + sz_y ;
43 }
44
45 string minigame_texture_skin(string skinname, string name)
46 {
47         return sprintf("gfx/hud/%s/minigames/%s", skinname, name);
48 }
49 string minigame_texture(string name)
50 {
51         string path = minigame_texture_skin(autocvar_menu_skin,name);
52         if ( precache_pic(path) == "" )
53                 path = minigame_texture_skin("default", name);
54         return path;
55 }
56
57 #define FIELD(Flags, Type, Name) MSLE_CLEAN_##Type(self.Name)
58 #define MSLE_CLEAN_String(x) strunzone(x);
59 #define MSLE_CLEAN_Byte(x)
60 #define MSLE_CLEAN_Char(x)
61 #define MSLE_CLEAN_Short(x)
62 #define MSLE_CLEAN_Long(x)
63 #define MSLE_CLEAN_Coord(x)
64 #define MSLE_CLEAN_Angle(x)
65 #define MSLE_CLEAN_Float(x)
66 #define MSLE_CLEAN_Vector(x)
67 #define MSLE_CLEAN_Vector2D(x)
68
69 #define MSLE(Name,Fields) \
70         void msle_entremove_##Name() { SELFPARAM(); strunzone(self.netname); Fields }
71 MINIGAME_SIMPLELINKED_ENTITIES
72 #undef MSLE
73 #undef FIELD
74
75 void minigame_autoclean_entity(entity e)
76 {
77         LOG_DEBUG("CL Auto-cleaned: ",ftos(num_for_edict(e)), " (",e.classname,")\n");
78         remove(e);
79 }
80
81 void HUD_MinigameMenu_CurrentButton();
82 bool auto_close_minigamemenu;
83 void deactivate_minigame()
84 {
85         if ( !active_minigame )
86                 return;
87
88         active_minigame.minigame_event(active_minigame,"deactivate");
89         entity e = world;
90         while( (e = findentity(e, owner, active_minigame)) )
91                 if ( e.minigame_autoclean )
92                 {
93                         minigame_autoclean_entity(e);
94                 }
95
96         minigame_self = world;
97         active_minigame = world;
98
99         if ( auto_close_minigamemenu )
100         {
101                 HUD_MinigameMenu_Close();
102                 auto_close_minigamemenu = 0;
103         }
104         else
105                 HUD_MinigameMenu_CurrentButton();
106 }
107
108 void minigame_entremove()
109 {SELFPARAM();
110         if ( self == active_minigame )
111                 deactivate_minigame();
112 }
113
114 void activate_minigame(entity minigame)
115 {
116         if ( !minigame )
117         {
118                 deactivate_minigame();
119                 return;
120         }
121
122         if ( !minigame.descriptor || minigame.classname != "minigame" )
123         {
124                 LOG_TRACE("Trying to activate unregistered minigame ",minigame.netname," in client\n");
125                 return;
126         }
127
128         if ( minigame == active_minigame )
129                 return;
130
131         if ( active_minigame )
132         {
133                 deactivate_minigame();
134         }
135
136         if ( minigame_self.owner != minigame )
137                 minigame_self = world;
138         active_minigame = minigame;
139         active_minigame.minigame_event(active_minigame,"activate");
140
141         if ( HUD_MinigameMenu_IsOpened() )
142                 HUD_MinigameMenu_CurrentButton();
143         else
144         {
145                 auto_close_minigamemenu = 1;
146                 HUD_MinigameMenu_Open();
147         }
148 }
149
150 void minigame_player_entremove()
151 {SELFPARAM();
152         if ( self.owner == active_minigame && self.minigame_playerslot == player_localentnum )
153                 deactivate_minigame();
154 }
155
156 vector ReadVector2D() { vector v; v_x = ReadCoord(); v_y = ReadCoord(); v_z = 0; return v; }
157 vector ReadVector() { vector v; v_x = ReadCoord(); v_y = ReadCoord(); v_z = ReadCoord(); return v; }
158 string() ReadString_Raw = #366;
159 string ReadString_Zoned() { return strzone(ReadString_Raw()); }
160 #define ReadString ReadString_Zoned
161 #define FIELD(Flags, Type,Name) if ( sf & (Flags) ) self.Name = Read##Type();
162 #define MSLE(Name,Fields) \
163         else if ( self.classname == #Name ) { \
164                 if ( sf & MINIG_SF_CREATE ) { \
165                         minigame_read_owner(); \
166                         self.entremove = msle_entremove_##Name; \
167                 } \
168                 minigame_ent = self.owner; \
169                 Fields \
170         }
171 void minigame_read_owner()
172 {SELFPARAM();
173         string owner_name = ReadString_Raw();
174         self.owner = world;
175         do
176                 self.owner = find(self.owner,netname,owner_name);
177         while ( self.owner && self.owner.classname != "minigame" );
178         if ( !self.owner )
179                 LOG_TRACE("Got a minigame entity without a minigame!\n");
180 }
181 void ent_read_minigame()
182 {SELFPARAM();
183         float sf = ReadByte();
184         if ( sf & MINIG_SF_CREATE )
185         {
186                 self.classname = msle_classname(ReadShort());
187                 self.netname = ReadString_Zoned();
188         }
189
190         entity minigame_ent = world;
191
192         if ( self.classname == "minigame" )
193         {
194                 minigame_ent = self;
195
196                 if ( sf & MINIG_SF_CREATE )
197                 {
198                         self.entremove = minigame_entremove;
199                         self.descriptor = minigame_get_descriptor(ReadString_Raw());
200                         if ( !self.descriptor )
201                                 LOG_TRACE("Got a minigame without a client-side descriptor!\n");
202                         else
203                                 self.minigame_event = self.descriptor.minigame_event;
204                 }
205                 if ( sf & MINIG_SF_UPDATE )
206                         self.minigame_flags = ReadLong();
207         }
208         else if ( self.classname == "minigame_player" )
209         {
210                 float activate = 0;
211                 if ( sf & MINIG_SF_CREATE )
212                 {
213                         self.entremove = minigame_player_entremove;
214                         minigame_read_owner();
215                         float ent = ReadLong();
216                         self.minigame_playerslot = ent;
217                         LOG_DEBUG("Player: ",GetPlayerName(ent-1),"\n");
218
219                         activate = (ent == player_localnum+1 && self.owner && self.owner != active_minigame);
220
221                 }
222                 minigame_ent = self.owner;
223
224                 if ( sf & MINIG_SF_UPDATE )
225                         self.team = ReadByte();
226
227                 if ( activate )
228                 {
229                         minigame_self = self;
230                         activate_minigame(self.owner);
231                 }
232         }
233         MINIGAME_SIMPLELINKED_ENTITIES
234
235         if ( minigame_ent )
236                 minigame_ent.minigame_event(minigame_ent,"network_receive",self,sf);
237
238         if ( sf & MINIG_SF_CREATE )
239         {
240                 LOG_DEBUG("CL Reading entity: ",ftos(num_for_edict(self)),
241                         " classname:",self.classname," enttype:",ftos(self.enttype) );
242                 LOG_DEBUG(" sf:",ftos(sf)," netname:",self.netname,"\n\n");
243         }
244 }
245 #undef ReadString
246 #undef FIELD
247 #undef MSLE
248
249 string minigame_getWrappedLine(float w, vector theFontSize, textLengthUpToWidth_widthFunction_t tw)
250 {
251         int last_word;
252         string s;
253         int take_until;
254         int skip = 0;
255
256         s = getWrappedLine_remaining;
257
258         if(w <= 0)
259         {
260                 getWrappedLine_remaining = string_null;
261                 return s; // the line has no size ANYWAY, nothing would be displayed.
262         }
263
264         take_until = textLengthUpToWidth(s, w, theFontSize, tw);
265
266         if ( take_until > strlen(s) )
267                 take_until = strlen(s);
268
269         for ( int i = 0; i < take_until; i++ )
270                 if ( substring(s,i,1) == "\n" )
271                 {
272                         take_until = i;
273                         skip = 1;
274                         break;
275                 }
276
277         if ( take_until > 0 || skip > 0 )
278         {
279                 if ( skip == 0 && take_until < strlen(s) )
280                 {
281                         last_word = take_until;
282                         while(last_word > 0 && substring(s, last_word, 1) != " ")
283                                 --last_word;
284
285                         if ( last_word != 0 )
286                         {
287                                 take_until = last_word;
288                                 skip = 1;
289                         }
290                 }
291
292                 getWrappedLine_remaining = substring(s, take_until+skip, strlen(s) - (take_until+skip));
293                 if(getWrappedLine_remaining == "")
294                         getWrappedLine_remaining = string_null;
295                 else if (tw("^7", theFontSize) == 0)
296                         getWrappedLine_remaining = strcat(find_last_color_code(substring(s, 0, take_until)), getWrappedLine_remaining);
297                 return substring(s, 0, take_until);
298         }
299         else
300         {
301                 getWrappedLine_remaining = string_null;
302                 return s;
303         }
304 }
305
306 vector minigame_drawstring_wrapped( float maxwidth, vector pos, string text,
307         vector fontsize, vector color, float theAlpha, int drawflags, float align )
308 {
309         getWrappedLine_remaining = text;
310         vector mypos = pos;
311         while ( getWrappedLine_remaining )
312         {
313                 string line = minigame_getWrappedLine(maxwidth,fontsize,stringwidth_nocolors);
314                 if ( line == "" )
315                         break;
316                 mypos_x = pos_x + (maxwidth - stringwidth_nocolors(line, fontsize)) * align;
317                 drawstring(mypos, line, fontsize, color, theAlpha, drawflags);
318                 mypos_y += fontsize_y;
319         }
320         mypos_x = maxwidth;
321         mypos_y -= pos_y;
322         return mypos;
323 }
324
325 vector minigame_drawcolorcodedstring_wrapped( float maxwidth, vector pos,
326         string text, vector fontsize, float theAlpha, int drawflags, float align )
327 {
328         getWrappedLine_remaining = text;
329         vector mypos = pos;
330         while ( getWrappedLine_remaining )
331         {
332                 string line = minigame_getWrappedLine(maxwidth,fontsize,stringwidth_colors);
333                 if ( line == "" )
334                         break;
335                 mypos_x = pos_x + (maxwidth - stringwidth_colors(line, fontsize)) * align;
336                 drawcolorcodedstring(mypos, line, fontsize, theAlpha, drawflags);
337                 mypos_y += fontsize_y;
338         }
339         mypos_x = maxwidth;
340         mypos_y -= pos_y;
341         return mypos;
342 }
343
344 void minigame_drawstring_trunc(float maxwidth, vector pos, string text,
345         vector fontsize, vector color, float theAlpha, int drawflags )
346 {
347         string line = textShortenToWidth(text,maxwidth,fontsize,stringwidth_nocolors);
348         drawstring(pos, line, fontsize, color, theAlpha, drawflags);
349 }
350
351 void minigame_drawcolorcodedstring_trunc(float maxwidth, vector pos, string text,
352         vector fontsize, float theAlpha, int drawflags )
353 {
354         string line = textShortenToWidth(text,maxwidth,fontsize,stringwidth_colors);
355         drawcolorcodedstring(pos, line, fontsize, theAlpha, drawflags);
356 }
357
358 void minigame_drawpic_centered( vector pos, string texture, vector sz,
359         vector color, float thealpha, int drawflags )
360 {
361         drawpic( pos-sz/2, texture, sz, color, thealpha, drawflags );
362 }
363
364 // Workaround because otherwise variadic arguments won't work properly
365 // It could be a bug in the compiler or in darkplaces
366 void minigame_cmd_workaround(float dummy, string...cmdargc)
367 {
368         string cmd;
369         cmd = "cmd minigame ";
370         float i;
371         for ( i = 0; i < cmdargc; i++ )
372                 cmd = strcat(cmd,...(i,string));
373         localcmd(strcat(cmd,"\n"));
374 }
375
376 // Prompt the player to play in the current minigame
377 // (ie: it's their turn and they should get back to the minigame)
378 void minigame_prompt()
379 {
380         if ( active_minigame && ! HUD_MinigameMenu_IsOpened() )
381         {
382                 HUD_Notify_Push(sprintf("minigames/%s/icon_notif",active_minigame.descriptor.netname),
383                         _("It's your turn"), "");
384         }
385 }