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