1#include "cl_minigames.qh" 2 3// Draw a square in the center of the avaliable area 4void 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 16vector 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 23vector 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 31vector 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 39bool 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 45string minigame_texture_skin(string skinname, string name) 46{ 47 return sprintf("gfx/hud/%s/minigames/%s", skinname, name); 48} 49string 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(this.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(entity this) { strunzone(this.netname); Fields } 71MINIGAME_SIMPLELINKED_ENTITIES 72#undef MSLE 73#undef FIELD 74 75void minigame_autoclean_entity(entity e) 76{ 77 LOG_DEBUG("CL Auto-cleaned: ",ftos(etof(e)), " (",e.classname,")"); 78 delete(e); 79} 80 81void HUD_MinigameMenu_CurrentButton(); 82bool auto_close_minigamemenu; 83void deactivate_minigame() 84{ 85 if ( !active_minigame ) 86 return; 87 88 active_minigame.minigame_event(active_minigame,"deactivate"); 89 entity e = NULL; 90 while( (e = findentity(e, owner, active_minigame)) ) 91 if ( e.minigame_autoclean ) 92 { 93 minigame_autoclean_entity(e); 94 } 95 96 minigame_self = NULL; 97 active_minigame = NULL; 98 99 if ( auto_close_minigamemenu ) 100 { 101 HUD_MinigameMenu_Close(NULL, NULL, NULL); 102 auto_close_minigamemenu = 0; 103 } 104 else 105 HUD_MinigameMenu_CurrentButton(); 106} 107 108void minigame_entremove(entity this) 109{ 110 if ( this == active_minigame ) 111 deactivate_minigame(); 112} 113 114void 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"); 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 = NULL; 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 150void minigame_player_entremove(entity this) 151{ 152 if ( this.owner == active_minigame && this.minigame_playerslot == player_localentnum ) 153 deactivate_minigame(); 154} 155 156string() ReadString_Raw = #366; 157string ReadString_Zoned() { return strzone(ReadString_Raw()); } 158#define ReadString ReadString_Zoned 159#define FIELD(Flags, Type,Name) if ( sf & (Flags) ) this.Name = Read##Type(); 160#define MSLE(Name,Fields) \ 161 else if ( this.classname == #Name ) { \ 162 if ( sf & MINIG_SF_CREATE ) { \ 163 minigame_read_owner(this); \ 164 this.entremove = msle_entremove_##Name; \ 165 } \ 166 minigame_ent = this.owner; \ 167 Fields \ 168 } 169void minigame_read_owner(entity this) 170{ 171 string owner_name = ReadString_Raw(); 172 this.owner = NULL; 173 do 174 this.owner = find(this.owner,netname,owner_name); 175 while ( this.owner && this.owner.classname != "minigame" ); 176 if ( !this.owner ) 177 LOG_TRACE("Got a minigame entity without a minigame!"); 178} 179NET_HANDLE(ENT_CLIENT_MINIGAME, bool isnew) 180{ 181 float sf = ReadByte(); 182 if ( sf & MINIG_SF_CREATE ) 183 { 184 this.classname = msle_classname(ReadShort()); 185 this.netname = ReadString_Zoned(); 186 } 187 188 entity minigame_ent = NULL; 189 190 if ( this.classname == "minigame" ) 191 { 192 minigame_ent = this; 193 194 if ( sf & MINIG_SF_CREATE ) 195 { 196 this.entremove = minigame_entremove; 197 this.descriptor = minigame_get_descriptor(ReadString_Raw()); 198 if ( !this.descriptor ) 199 LOG_TRACE("Got a minigame without a client-side descriptor!"); 200 else 201 this.minigame_event = this.descriptor.minigame_event; 202 } 203 if ( sf & MINIG_SF_UPDATE ) 204 this.minigame_flags = ReadLong(); 205 } 206 else if ( this.classname == "minigame_player" ) 207 { 208 float activate = 0; 209 if ( sf & MINIG_SF_CREATE ) 210 { 211 this.entremove = minigame_player_entremove; 212 minigame_read_owner(this); 213 float ent = ReadLong(); 214 this.minigame_playerslot = ent; 215 LOG_DEBUG("Player: ",entcs_GetName(ent-1)); 216 217 activate = (ent == player_localnum+1 && this.owner && this.owner != active_minigame); 218 219 } 220 minigame_ent = this.owner; 221 222 if ( sf & MINIG_SF_UPDATE ) 223 this.team = ReadByte(); 224 225 if ( activate ) 226 { 227 minigame_self = this; 228 activate_minigame(this.owner); 229 minigame_self = this; // set it again (needed before, but may also be reset) 230 } 231 } 232 MINIGAME_SIMPLELINKED_ENTITIES 233 234 if ( minigame_ent ) 235 minigame_ent.minigame_event(minigame_ent,"network_receive",this,sf); 236 237 if ( sf & MINIG_SF_CREATE ) 238 { 239 LOG_DEBUG("CL Reading entity: ",ftos(etof(this)), 240 " classname:",this.classname," enttype:",ftos(this.enttype) ); 241 LOG_DEBUG(" sf:",ftos(sf)," netname:",this.netname); 242 } 243 return true; 244} 245#undef ReadString 246#undef FIELD 247#undef MSLE 248 249string 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 306vector 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 325vector 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 344void 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 351void 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 358void 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 366void 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) 378void 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} 386 387// handle commands etc. 388REGISTER_MUTATOR(minigames, true); 389 390MUTATOR_HOOKFUNCTION(minigames, HUD_Command) 391{ 392 if(MUTATOR_RETURNVALUE) { return false; } // command was already handled 393 394 if(argv(1) == "minigame") 395 { 396 if (HUD_MinigameMenu_IsOpened()) 397 HUD_MinigameMenu_Close(NULL, NULL, NULL); 398 else 399 HUD_MinigameMenu_Open(); 400 return true; 401 } 402 403 return false; 404} 405