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