1 #include "sv_minigames.qh"
3 #include <common/minigames/minigames.qh>
4 #include <server/gamelog.qh>
6 void player_clear_minigame(entity player)
8 CS(player).active_minigame = NULL;
9 player.minigame_players = NULL;
10 if ( IS_PLAYER(player) )
11 set_movetype(player, MOVETYPE_WALK);
13 set_movetype(player, MOVETYPE_FLY_WORLDONLY);
14 Player_SetForcedTeamIndex(player, TEAM_FORCE_DEFAULT);
17 void minigame_rmplayer(entity minigame_session, entity player)
20 entity p = minigame_session.minigame_players;
22 if ( p.minigame_players == player )
24 if ( p.list_next == NULL )
26 end_minigame(minigame_session);
29 minigame_session.minigame_event(minigame_session,"part",player);
30 GameLogEcho(strcat(":minigame:part:",minigame_session.netname,":",
31 ftos(etof(player)),":",player.netname));
32 minigame_session.minigame_players = p.list_next;
34 player_clear_minigame(player);
38 for ( e = p.list_next; e != NULL; e = e.list_next )
40 if ( e.minigame_players == player )
42 minigame_session.minigame_event(minigame_session,"part",player);
43 GameLogEcho(strcat(":minigame:part:",minigame_session.netname,":",
44 ftos(etof(player)),":",player.netname));
45 p.list_next = e.list_next;
47 player_clear_minigame(player);
56 #define FIELD(Flags, Type,Name) if ( sf & (Flags) ) Write##Type(MSG_ENTITY, this.Name);
57 #define MSLE(Name,Fields) \
58 else if ( this.classname == #Name ) { \
59 if ( sf & MINIG_SF_CREATE ) WriteString(MSG_ENTITY,this.owner.netname); \
62 // Send an entity to a client
63 // only use on minigame entities or entities with a minigame owner
64 bool minigame_SendEntity(entity this, entity to, int sf)
66 WriteHeader(MSG_ENTITY, ENT_CLIENT_MINIGAME);
67 WriteByte(MSG_ENTITY, sf);
69 if ( sf & MINIG_SF_CREATE )
71 WriteShort(MSG_ENTITY,msle_id(this.classname));
72 WriteString(MSG_ENTITY,this.netname);
75 entity minigame_ent = this.owner;
77 if ( this.classname == "minigame" )
81 if ( sf & MINIG_SF_CREATE )
82 WriteString(MSG_ENTITY,this.descriptor.netname);
84 if ( sf & MINIG_SF_UPDATE )
85 WriteLong(MSG_ENTITY,this.minigame_flags);
87 else if ( this.classname == "minigame_player" )
89 if ( sf & MINIG_SF_CREATE )
91 WriteString(MSG_ENTITY,this.owner.netname);
92 WriteLong(MSG_ENTITY,etof(this.minigame_players));
94 if ( sf & MINIG_SF_UPDATE )
95 WriteByte(MSG_ENTITY,this.team);
97 MINIGAME_SIMPLELINKED_ENTITIES
99 minigame_ent.minigame_event(minigame_ent,"network_send",this,sf);
107 // Force resend all minigame entities
108 void minigame_resend(entity minigame)
110 minigame.SendFlags = MINIG_SF_ALL;
112 while (( e = findentity(e,owner,minigame) ))
114 e.SendFlags = MINIG_SF_ALL;
118 bool minigame_CheckSend(entity this, entity client)
121 for ( e = this.owner.minigame_players; e != NULL; e = e.list_next )
122 if ( e.minigame_players == client )
127 int minigame_addplayer(entity minigame_session, entity player)
129 if ( CS(player).active_minigame )
131 if ( CS(player).active_minigame == minigame_session )
133 minigame_rmplayer(CS(player).active_minigame,player);
135 entity player_pointer = new(minigame_player);
136 int mgteam = minigame_session.minigame_event(minigame_session,"join",player,player_pointer);
140 player_pointer.owner = minigame_session;
141 player_pointer.minigame_players = player;
142 player_pointer.team = mgteam;
143 player_pointer.list_next = minigame_session.minigame_players;
144 minigame_session.minigame_players = player_pointer;
145 CS(player).active_minigame = minigame_session;
146 player.minigame_players = player_pointer;
147 setcefc(player_pointer, minigame_CheckSend);
148 Net_LinkEntity(player_pointer, false, 0, minigame_SendEntity);
150 if ( !IS_OBSERVER(player) && autocvar_sv_minigames_observer )
151 PutObserverInServer(player, true, true);
152 if ( autocvar_sv_minigames_observer == 2 )
153 Player_SetForcedTeamIndex(player, TEAM_FORCE_SPECTATOR);
155 minigame_resend(minigame_session);
157 else { delete(player_pointer); }
158 GameLogEcho(strcat(":minigame:join",(mgteam?"":"fail"),":",minigame_session.netname,":",
159 ftos(etof(player)),":",player.netname));
164 entity start_minigame(entity player, string minigame )
166 if ( !autocvar_sv_minigames || !IS_REAL_CLIENT(player) )
169 entity e = minigame_get_descriptor(minigame);
172 entity minig = new(minigame);
173 minig.netname = strzone(strcat(e.netname,"_",ftos(etof(minig))));
174 minig.descriptor = e;
175 minig.minigame_event = e.minigame_event;
176 minig.minigame_event(minig,"start");
177 GameLogEcho(strcat(":minigame:start:",minig.netname));
178 if ( ! minigame_addplayer(minig,player) )
180 LOG_TRACE("Minigame ",minig.netname," rejected the first player join!");
184 Net_LinkEntity(minig, false, 0, minigame_SendEntity);
186 if ( !minigame_sessions )
187 minigame_sessions = minig;
190 minigame_sessions.owner = minig;
191 minig.list_next = minigame_sessions;
192 minigame_sessions = minig;
200 entity join_minigame(entity player, string game_id )
202 if ( !autocvar_sv_minigames || !IS_REAL_CLIENT(player) )
206 for ( minig = minigame_sessions; minig != NULL; minig = minig.list_next )
208 if ( minig.netname == game_id )
209 if ( minigame_addplayer(minig,player) )
216 void part_minigame(entity player)
218 entity minig = CS(player).active_minigame;
220 if ( minig && minig.classname == "minigame" )
221 minigame_rmplayer(minig,player);
224 void end_minigame(entity minigame_session)
226 if ( minigame_session.owner )
227 minigame_session.owner.list_next = minigame_session.list_next;
229 minigame_sessions = minigame_session.list_next;
231 minigame_session.minigame_event(minigame_session,"end");
232 GameLogEcho(strcat(":minigame:end:",minigame_session.netname));
236 while( (e = findentity(e, owner, minigame_session)) )
237 if ( e.minigame_autoclean )
239 LOG_TRACE("SV Auto-cleaned: ",ftos(etof(e)), " (",e.classname,")");
244 for ( e = minigame_session.minigame_players; e != NULL; e = p )
247 player_clear_minigame(e.minigame_players);
251 strfree(minigame_session.netname);
252 delete(minigame_session);
257 while ( minigame_sessions )
259 end_minigame(minigame_sessions);
263 string invite_minigame(entity inviter, entity player)
265 if ( !inviter || !CS(inviter).active_minigame )
266 return "Invalid minigame";
267 if ( VerifyClientEntity(player, true, false) <= 0 )
268 return "Invalid player";
269 if ( inviter == player )
270 return "You can't invite yourself";
271 if (autocvar_g_playban_minigames && PlayerInList(player, autocvar_g_playban_list)) // playban
272 return "You can't invite a banned player";
273 if ( CS(player).active_minigame == CS(inviter).active_minigame )
274 return strcat(player.netname," is already playing");
276 Send_Notification(NOTIF_ONE, player, MSG_INFO, INFO_MINIGAME_INVITE,
277 CS(inviter).active_minigame.netname, inviter.netname );
279 GameLogEcho(strcat(":minigame:invite:",CS(inviter).active_minigame.netname,":",
280 ftos(etof(player)),":",player.netname));
285 entity minigame_find_player(entity client)
287 if ( ! CS(client).active_minigame )
290 for ( e = CS(client).active_minigame.minigame_players; e; e = e.list_next )
291 if ( e.minigame_players == client )
296 bool MinigameImpulse(entity this, int imp)
298 if (!CS(this).active_minigame) return false;
299 entity e = minigame_find_player(this);
300 if ( imp && CS(this).active_minigame && e )
302 return CS(this).active_minigame.minigame_event(CS(this).active_minigame,"impulse",e,imp);
309 void ClientCommand_minigame(entity caller, int request, int argc, string command)
311 if ( !autocvar_sv_minigames )
313 sprint(caller,"Minigames are not enabled!\n");
317 if (autocvar_g_playban_minigames && PlayerInList(caller, autocvar_g_playban_list)) // playban
319 Send_Notification(NOTIF_ONE_ONLY, caller, MSG_CENTER, CENTER_JOIN_PLAYBAN);
320 sprint(caller, "You aren't allowed to play minigames because you are banned from them in this server.\n");
324 if (request == CMD_REQUEST_COMMAND )
326 string minig_cmd = argv(1);
327 if ( minig_cmd == "create" && argc > 2 )
329 entity minig = start_minigame(caller, argv(2));
331 sprint(caller,"Created minigame session: ",minig.netname,"\n");
333 sprint(caller,"Cannot start minigame session!\n");
336 else if ( minig_cmd == "join" && argc > 2 )
338 entity minig = join_minigame(caller, argv(2));
340 sprint(caller,"Joined: ",minig.netname,"\n");
343 Send_Notification(NOTIF_ONE, caller, MSG_CENTER, CENTER_JOIN_PREVENT_MINIGAME);
344 sprint(caller,"Cannot join given minigame session!\n");
348 else if ( minig_cmd == "list" )
350 FOREACH(Minigames, true, sprint(caller, it.netname, " (", it.message, ") ", "\n"));
353 else if ( minig_cmd == "list-sessions" )
356 for ( e = minigame_sessions; e != NULL; e = e.list_next )
357 sprint(caller,e.netname,"\n");
360 else if ( minig_cmd == "end" || minig_cmd == "part" )
362 if ( CS(caller).active_minigame )
364 part_minigame(caller);
365 sprint(caller,"Left minigame session\n");
368 sprint(caller,"You aren't playing any minigame...\n");
371 else if ( minig_cmd == "invite" && argc > 2 )
373 if ( CS(caller).active_minigame )
375 entity client = GetIndexedEntity(argc, 2);
376 string error = invite_minigame(caller,client);
379 sprint(caller,"You have invited ",client.netname,
380 " to join your game of ", CS(caller).active_minigame.descriptor.message, "\n");
383 sprint(caller,"Could not invite: ", error, ".\n");
386 sprint(caller,"You aren't playing any minigame...\n");
389 else if ( CS(caller).active_minigame )
391 entity e = minigame_find_player(caller);
392 string subcommand = substring(command,argv_end_index(0),-1);
393 int arg_c = tokenize_console(subcommand);
394 if ( CS(caller).active_minigame.minigame_event(CS(caller).active_minigame,"cmd",e,arg_c,subcommand) )
398 else sprint(caller,strcat("Wrong command:^1 ",command,"\n"));
401 sprint(caller, "\nUsage:^3 cmd minigame create <minigame>\n");
402 sprint(caller, " Start a new minigame session\n");
403 sprint(caller, "Usage:^3 cmd minigame join <session>\n");
404 sprint(caller, " Join an exising minigame session\n");
405 sprint(caller, "Usage:^3 cmd minigame list\n");
406 sprint(caller, " List available minigames\n");
407 sprint(caller, "Usage:^3 cmd minigame list-sessions\n");
408 sprint(caller, " List available minigames sessions\n");
409 sprint(caller, "Usage:^3 cmd minigame part|end\n");
410 sprint(caller, " Leave the current minigame\n");
411 sprint(caller, "Usage:^3 cmd minigame invite <player>\n");
412 sprint(caller, " Invite the given player to join you in a minigame\n");