]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/minigames/sv_minigames.qc
Rename the minigame definition functions
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / minigames / sv_minigames.qc
1 #include "minigames.qh"
2
3 void player_clear_minigame(entity player)
4 {
5         player.active_minigame = world;
6         player.minigame_players = world;
7         if ( IS_PLAYER(player) )
8                 player.movetype = MOVETYPE_WALK;
9         else
10                 player.movetype = MOVETYPE_FLY_WORLDONLY;
11         player.team_forced = 0;
12 }
13
14 void minigame_rmplayer(entity minigame_session, entity player)
15 {
16         entity e;
17         entity p = minigame_session.minigame_players;
18         
19         if ( p.minigame_players == player )
20         {
21                 if ( p.list_next == world )
22                 {
23                         end_minigame(minigame_session);
24                         return;
25                 }
26                 minigame_session.minigame_event(minigame_session,"part",player);
27                 GameLogEcho(strcat(":minigame:part:",minigame_session.netname,":",
28                         ftos(num_for_edict(player)),":",player.netname));
29                 minigame_session.minigame_players = p.list_next;
30                 remove ( p );
31                 player_clear_minigame(player);
32         }
33         else
34         {
35                 for ( e = p.list_next; e != world; e = e.list_next )
36                 {
37                         if ( e.minigame_players == player )
38                         {
39                                 minigame_session.minigame_event(minigame_session,"part",player);
40                                 GameLogEcho(strcat(":minigame:part:",minigame_session.netname,":",
41                                         ftos(num_for_edict(player)),":",player.netname));
42                                 p.list_next = e.list_next;
43                                 remove(e);
44                                 player_clear_minigame(player);
45                                 return;
46                         }
47                         p = e;
48                 }
49         }
50 }
51
52
53 #define FIELD(Flags, Type,Name) if ( sf & (Flags) ) Write##Type(MSG_ENTITY, self.Name);
54 #define WriteVector(to,Name) WriteCoord(to,Name##_x); WriteCoord(to,Name##_y); WriteCoord(to,Name##_z)
55 #define WriteVector2D(to,Name) WriteCoord(to,Name##_x); WriteCoord(to,Name##_y)
56 #define WriteFloat WriteCoord
57 #define MSLE(Name,Fields) \
58         else if ( self.classname == #Name ) { \
59                 if ( sf & MINIG_SF_CREATE ) WriteString(MSG_ENTITY,self.owner.netname); \
60                 Fields }
61
62 // Send an entity to a client
63 // only use on minigame entities or entities with a minigame owner
64 bool minigame_SendEntity(entity to, int sf)
65 {
66         WriteByte(MSG_ENTITY, ENT_CLIENT_MINIGAME);
67         WriteByte(MSG_ENTITY, sf);
68         
69         if ( sf & MINIG_SF_CREATE )
70         {
71                 WriteShort(MSG_ENTITY,msle_id(self.classname));
72                 WriteString(MSG_ENTITY,self.netname);
73         }
74         
75         entity minigame_ent = self.owner;
76         
77         if ( self.classname == "minigame" )
78         {
79                 minigame_ent = self;
80                 
81                 if ( sf & MINIG_SF_CREATE )
82                         WriteString(MSG_ENTITY,self.descriptor.netname);
83                 
84                 if ( sf & MINIG_SF_UPDATE )
85                         WriteLong(MSG_ENTITY,self.minigame_flags);
86         }
87         else if ( self.classname == "minigame_player" )
88         {
89                 if ( sf & MINIG_SF_CREATE )
90                 {
91                         WriteString(MSG_ENTITY,self.owner.netname);
92                         WriteLong(MSG_ENTITY,num_for_edict(self.minigame_players));
93                 }
94                 if ( sf & MINIG_SF_UPDATE )
95                         WriteByte(MSG_ENTITY,self.team);
96         }
97         MINIGAME_SIMPLELINKED_ENTITIES
98         
99         minigame_ent.minigame_event(minigame_ent,"network_send",self,sf);
100         
101         return true;
102         
103 }
104 #undef FIELD
105 #undef MSLE
106 #undef WriteFloat
107
108 // Force resend all minigame entities
109 void minigame_resend(entity minigame)
110 {
111         minigame.SendFlags = MINIG_SF_ALL;
112         entity e = world;
113         while (( e = findentity(e,owner,minigame) ))
114         {
115                 e.SendFlags = MINIG_SF_ALL;
116         }
117 }
118
119 bool minigame_CheckSend()
120 {
121         entity e;
122         for ( e = self.owner.minigame_players; e != world; e = e.list_next )
123                 if ( e.minigame_players == other )
124                         return true;
125         return false;
126 }
127
128 int minigame_addplayer(entity minigame_session, entity player)
129 {
130         if ( player.active_minigame )
131         {
132                 if ( player.active_minigame == minigame_session )
133                         return 0;
134                 minigame_rmplayer(player.active_minigame,player);
135         }
136         
137         int mgteam = minigame_session.minigame_event(minigame_session,"join",player);
138         
139         if ( mgteam )
140         {
141                 entity player_pointer = spawn();
142                 player_pointer.classname = "minigame_player";
143                 player_pointer.owner = minigame_session;
144                 player_pointer.minigame_players = player;
145                 player_pointer.team = mgteam;
146                 player_pointer.list_next = minigame_session.minigame_players;
147                 minigame_session.minigame_players = player_pointer;
148                 player.active_minigame = minigame_session;
149                 player.minigame_players = player_pointer;
150                 player_pointer.customizeentityforclient = minigame_CheckSend;
151                 Net_LinkEntity(player_pointer, false, 0, minigame_SendEntity);
152
153                 if ( !IS_OBSERVER(player) && autocvar_sv_minigames_observer )
154                 {
155                         entity e = self;
156                         self = player;
157                         PutObserverInServer();
158                         self = e;
159                 }
160                 if ( autocvar_sv_minigames_observer == 2 )
161                         player.team_forced = -1;
162                 
163                 minigame_resend(minigame_session);
164         }
165         GameLogEcho(strcat(":minigame:join",(mgteam?"":"fail"),":",minigame_session.netname,":",
166                 ftos(num_for_edict(player)),":",player.netname));
167         
168         return mgteam;
169 }
170
171 entity start_minigame(entity player, string minigame )
172 {
173         if ( !autocvar_sv_minigames || !IS_REAL_CLIENT(player) )
174                 return world;
175         
176         entity e = minigame_get_descriptor(minigame);
177         if ( e ) 
178         {
179                 entity minig = spawn();
180                 minig.classname = "minigame";
181                 minig.netname = strzone(strcat(e.netname,"_",ftos(num_for_edict(minig))));
182                 minig.descriptor = e;
183                 minig.minigame_event = e.minigame_event;
184                 minig.minigame_event(minig,"start");
185                 GameLogEcho(strcat(":minigame:start:",minig.netname));
186                 if ( ! minigame_addplayer(minig,player) )
187                 {
188                         dprint("Minigame ",minig.netname," rejected the first player join!\n");
189                         end_minigame(minig);
190                         return world;
191                 }
192                 Net_LinkEntity(minig, false, 0, minigame_SendEntity);
193                 
194                 if ( !minigame_sessions )
195                         minigame_sessions = minig;
196                 else
197                 {
198                         minigame_sessions.owner = minig;
199                         minig.list_next = minigame_sessions;
200                         minigame_sessions = minig;
201                 }
202                 return minig;
203         }
204                 
205         return world;
206 }
207
208 entity join_minigame(entity player, string game_id )
209 {
210         if ( !autocvar_sv_minigames || !IS_REAL_CLIENT(player) )
211                 return world;
212         
213         entity minig;
214         for ( minig = minigame_sessions; minig != world; minig = minig.list_next )
215         {
216                 if ( minig.netname == game_id )
217                 if ( minigame_addplayer(minig,player) )
218                         return minig;
219         }
220         
221         return world;
222 }
223
224 void part_minigame(entity player )
225 {
226         entity minig = player.active_minigame;
227         
228         if ( minig && minig.classname == "minigame" )
229                 minigame_rmplayer(minig,player);
230 }
231
232 void end_minigame(entity minigame_session)
233 {
234         if ( minigame_session.owner )
235                 minigame_session.owner.list_next = minigame_session.list_next;
236         else
237                 minigame_sessions = minigame_session.list_next;
238         
239         minigame_session.minigame_event(minigame_session,"end");
240         GameLogEcho(strcat(":minigame:end:",minigame_session.netname));
241         
242         
243         entity e = world;
244         while( (e = findentity(e, owner, minigame_session)) )
245                 if ( e.minigame_autoclean )
246                 {
247                         dprint("SV Auto-cleaned: ",ftos(num_for_edict(e)), " (",e.classname,")\n");
248                         remove(e);
249                 }
250         
251         entity p;
252         for ( e = minigame_session.minigame_players; e != world; e = p )
253         {
254                 p = e.list_next;
255                 player_clear_minigame(e.minigame_players);
256                 remove(e);
257         }
258         
259         strunzone(minigame_session.netname);
260         remove(minigame_session);
261 }
262
263 void end_minigames()
264 {
265         while ( minigame_sessions )
266         {
267                 end_minigame(minigame_sessions);
268         }
269 }
270
271 void initialize_minigames()
272 {
273         entity last_minig = world;
274         entity minig;
275         #define MINIGAME(name,nicename) \
276                 minig = spawn(); \
277                 minig.classname = "minigame_descriptor"; \
278                 minig.netname = #name; \
279                 minig.message = nicename; \
280                 minig.minigame_event = name##_server_event; \
281                 if ( !last_minig ) minigame_descriptors = minig; \
282                 else last_minig.list_next = minig; \
283                 last_minig = minig;
284                 
285         REGISTERED_MINIGAMES
286         
287         #undef MINIGAME
288 }
289
290 string invite_minigame(entity inviter, entity player)
291 {
292         if ( !inviter || !inviter.active_minigame )
293                 return "Invalid minigame";
294         if ( !VerifyClientEntity(player, true, false) )
295                 return "Invalid player";
296         if ( inviter == player )
297                 return "You can't invite yourself";
298         if ( player.active_minigame == inviter.active_minigame )
299                 return strcat(player.netname," is already playing");
300         
301         Send_Notification(NOTIF_ONE, player, MSG_INFO, INFO_MINIGAME_INVITE, 
302                 inviter.active_minigame.netname, inviter.netname );
303         
304         GameLogEcho(strcat(":minigame:invite:",inviter.active_minigame.netname,":",
305                 ftos(num_for_edict(player)),":",player.netname));
306         
307         return "";
308 }
309
310 entity minigame_find_player(entity client)
311 {
312         if ( ! client.active_minigame )
313                 return world;
314         entity e;
315         for ( e = client.active_minigame.minigame_players; e; e = e.list_next )
316                 if ( e.minigame_players == client )
317                         return e;
318         return world;
319 }
320
321 bool MinigameImpulse(int imp)
322 {
323         entity e = minigame_find_player(self);
324         if ( imp && self.active_minigame && e )
325         {
326                 return self.active_minigame.minigame_event(self.active_minigame,"impulse",e,imp);
327         }
328         return false;
329 }
330
331
332
333 void ClientCommand_minigame(int request, int argc, string command)
334 {
335         if ( !autocvar_sv_minigames )
336         {
337                 sprint(self,"Minigames are not enabled!\n");
338                 return;
339         }
340         
341         if (request == CMD_REQUEST_COMMAND )
342         {
343                 string minig_cmd = argv(1);
344                 if ( minig_cmd == "create" && argc > 2 )
345                 {
346                         entity minig = start_minigame(self, argv(2));
347                         if ( minig )
348                                 sprint(self,"Created minigame session: ",minig.netname,"\n");
349                         else
350                                 sprint(self,"Cannot start minigame session!\n");
351                         return;
352                 }
353                 else if ( minig_cmd == "join" && argc > 2 )
354                 {
355                         entity minig = join_minigame(self, argv(2));
356                         if ( minig )
357                                 sprint(self,"Joined: ",minig.netname,"\n");
358                         else
359                         {
360                                 Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_JOIN_PREVENT_MINIGAME);
361                                 sprint(self,"Cannot join given minigame session!\n");
362                         }
363                         return;
364                 }
365                 else if ( minig_cmd == "list" )
366                 {
367                         entity e;
368                         for ( e = minigame_descriptors; e != world; e = e.list_next )
369                                 sprint(self,e.netname," (",e.message,") ","\n");
370                         return;
371                 }
372                 else if ( minig_cmd == "list-sessions" )
373                 {
374                         entity e;
375                         for ( e = minigame_sessions; e != world; e = e.list_next )
376                                 sprint(self,e.netname,"\n");
377                         return;
378                 }
379                 else if ( minig_cmd == "end" || minig_cmd == "part" )
380                 {
381                         if ( self.active_minigame )
382                         {
383                                 part_minigame(self);
384                                 sprint(self,"Left minigame session\n");
385                         }
386                         else
387                                 sprint(self,"You aren't playing any minigame...\n");
388                         return;
389                 }
390                 else if ( minig_cmd == "invite" && argc > 2 )
391                 {
392                         if ( self.active_minigame )
393                         {
394                                 entity client = GetIndexedEntity(argc, 2);
395                                 string error = invite_minigame(self,client);
396                                 if ( error == "" )
397                                 {
398                                         sprint(self,"You have invited ",client.netname,
399                                                 " to join your game of ", self.active_minigame.descriptor.message, "\n");
400                                 }
401                                 else
402                                         sprint(self,"Could not invite: ", error, ".\n");
403                         }
404                         else
405                                 sprint(self,"You aren't playing any minigame...\n");
406                         return;
407                 }
408                 else if ( self.active_minigame )
409                 {
410                         entity e = minigame_find_player(self);
411                         string subcommand = substring(command,argv_end_index(0),-1);
412                         int arg_c = tokenize_console(subcommand);
413                         if ( self.active_minigame.minigame_event(self.active_minigame,"cmd",e,arg_c,subcommand) )
414                                 return;
415                                 
416                 }
417                 else sprint(self,strcat("Wrong command:^1 ",command,"\n"));
418         }
419         
420         sprint(self, "\nUsage:^3 cmd minigame create <minigame>\n");
421         sprint(self, "  Start a new minigame session\n");
422         sprint(self, "Usage:^3 cmd minigame join <session>\n");
423         sprint(self, "  Join an exising minigame session\n");
424         sprint(self, "Usage:^3 cmd minigame list\n");
425         sprint(self, "  List available minigames\n");
426         sprint(self, "Usage:^3 cmd minigame list-sessions\n");
427         sprint(self, "  List available minigames sessions\n");
428         sprint(self, "Usage:^3 cmd minigame part|end\n");
429         sprint(self, "  Leave the current minigame\n");
430         sprint(self, "Usage:^3 cmd minigame invite <player>\n");
431         sprint(self, "  Invite the given player to join you in a minigame\n");
432 }