]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/minigames/minigame/pong.qc
Very basic pong setup
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / minigames / minigame / pong.qc
1 // minigame flags
2 const int PONG_MGF_RESET = 0x0010; // Ball is reset to the center
3
4 // send flags
5 const int PONG_SF_PLAYERSCORE  = MINIG_SF_CUSTOM;   // sent when reporting scores
6 const int PONG_SF_SINGLEPLAYER = MINIG_SF_CUSTOM<<1;// send minigame.pong_ai
7
8 // fields
9 .int   pong_ai;    // (minigame) when non-zero, singleplayer vs AI
10 .int   pong_score; // (minigame_player) number of goals
11 .float pong_length;// (pong_paddle) size (0,1)
12
13 #ifdef SVQC
14
15 float autocvar_sv_minigames_pong_paddlesize = 0.3;
16 float autocvar_sv_minigames_pong_paddlespeed= 1;
17 float autocvar_sv_minigames_pong_ballwait  = 1;
18 float autocvar_sv_minigames_pong_ballspeed  = 1;
19
20 void pong_ball_think();
21
22 void pong_ball_thinkthrow()
23 {
24         float angle;
25         do
26                 angle = random()*M_PI*2;
27         while ( (angle > 0.44*M_PI && angle < 0.55*M_PI) || 
28                 (angle > 1.44*M_PI && angle < 1.55*M_PI) );
29         self.velocity_x = cos(angle)*autocvar_sv_minigames_pong_ballspeed;
30         self.velocity_y = sin(angle)*autocvar_sv_minigames_pong_ballspeed;
31         self.SendFlags |= MINIG_SF_UPDATE;
32         self.think = pong_ball_think;
33         self.nextthink = time;
34 }
35
36 void pong_reset_ball(entity ball)
37 {
38         ball.velocity = '0 0 0';
39         ball.origin = '0.5 0.5 0';
40         ball.SendFlags |= MINIG_SF_UPDATE;
41         ball.think = pong_ball_thinkthrow;
42         ball.nextthink = time + autocvar_sv_minigames_pong_ballwait;
43 }
44
45 void pong_ball_think()
46 {
47         float think_speed = autocvar_sys_ticrate;
48         self.nextthink = time + think_speed;
49         
50         self.origin_x += self.velocity_x * think_speed;
51         self.origin_y += self.velocity_y * think_speed;
52         if ( self.origin_y <= 0 )
53         {
54                 self.origin_y = 0;
55                 self.velocity_y *= -1;
56         }
57         else if ( self.origin_y >= 1 )
58         {
59                 self.origin_y = 1;
60                 self.velocity_y *= -1;
61         }
62         
63         // todo score
64         if ( self.origin_x <= 0 )
65         {
66                 pong_reset_ball(self);
67         }
68         else if ( self.origin_x >= 1 )
69         {
70                 pong_reset_ball(self);
71         }
72         
73         self.SendFlags |= MINIG_SF_UPDATE;
74 }
75
76 void pong_paddle_think()
77 {
78         float think_speed = autocvar_sys_ticrate;
79         self.nextthink = time + think_speed;
80         
81         if ( self.realowner.movement.x > 0 && self.origin_y > self.pong_length/2 )
82         {
83                 self.origin_y -= autocvar_sv_minigames_pong_paddlespeed * think_speed;
84                 if ( self.origin_y < 0 )
85                         self.origin_y = 0;
86                 self.SendFlags |= MINIG_SF_UPDATE;
87         }
88         else if ( self.realowner.movement.x < 0 && self.origin_y < 1-self.pong_length/2 )
89         {
90                 self.origin_y += autocvar_sv_minigames_pong_paddlespeed * think_speed;
91                 if ( self.origin_y > 1 )
92                         self.origin_y = 1;
93                 self.SendFlags |= MINIG_SF_UPDATE;
94         }
95                 
96 }
97
98 // required function, handle server side events
99 int minigame_event_pong(entity minigame, string event, ...)
100 {
101         switch (event)
102         {
103                 case "start":
104                 {
105                         entity ball = msle_spawn(minigame,"pong_ball");
106                         pong_reset_ball(ball);
107                         minigame.minigame_flags = PONG_MGF_RESET; // todo useful?
108                         
109                         return true;
110                 }
111                 case "end":
112                         // nothing to do
113                         return false;
114                 case "join":
115                 {
116                         int pl_num = minigame_count_players(minigame);
117                         
118                         // Don't allow joining a single player match
119                         if ( (minigame.pong_ai) && pl_num > 0 )
120                                 return false;
121
122                         // Don't allow more than 2 players
123                         if(pl_num >= 2) { return false; }
124
125                         int pl_team = 1;
126                         // Get the right team
127                         if(minigame.minigame_players)
128                                 pl_team = minigame_next_team(minigame.minigame_players.team, 2);
129                         
130                         
131                         entity player = ...(0,entity);
132                         entity paddle = msle_spawn(minigame,"pong_paddle");// Note puddle isn't a typo
133                         paddle.pong_length = autocvar_sv_minigames_pong_paddlesize;
134                         paddle.origin_y = 0.5;
135                         paddle.origin_x = pl_team == 1 ? 0.95 : 0.05;
136                         paddle.think = pong_paddle_think;
137                         paddle.nextthink = time;
138                         paddle.team = pl_team;
139                         paddle.realowner = player;
140
141                         // Team 1 by default
142                         return pl_team;
143                 }
144                 case "cmd":
145                         // nothing to do
146                         return false;
147                 case "network_send":
148                 {
149                         entity sent = ...(0,entity);
150                         int sf = ...(1,int);
151                         if ( sent.classname == "minigame_player" && (sf & PONG_SF_PLAYERSCORE ) )
152                         {
153                                 WriteByte(MSG_ENTITY,sent.pong_score);
154                         }
155                         else if ( sent.classname == "minigame" && (sf & PONG_SF_SINGLEPLAYER) )
156                         {
157                                 WriteByte(MSG_ENTITY,sent.pong_ai);
158                         }
159                         return false;
160                 }
161         }
162         return false;
163 }
164
165
166 #elif defined(CSQC)
167
168
169 // Required function, draw the game board
170 void minigame_hud_board_pong(vector pos, vector mySize)
171 {
172         minigame_hud_fitsqare(pos, mySize);
173         minigame_hud_simpleboard(pos,mySize,minigame_texture("pong/board"));
174         
175         entity e;
176         vector obj_pos;
177         vector ball_size = minigame_hud_denormalize_size('1 1 0' / 16,pos,mySize);
178         vector paddle_size;
179         FOREACH_MINIGAME_ENTITY(e)
180         {
181                 if ( e.classname == "pong_ball" )
182                 {
183                         obj_pos = minigame_hud_denormalize(e.origin,pos,mySize);
184                         minigame_drawpic_centered( obj_pos, minigame_texture("pong/ball"),
185                                         ball_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL );
186                 }
187                 else if ( e.classname == "pong_paddle" )
188                 {
189                         obj_pos = minigame_hud_denormalize(e.origin,pos,mySize);
190                         paddle_size = minigame_hud_denormalize_size(eX / 16 + eY*e.pong_length,pos,mySize);
191                         minigame_drawpic_centered( obj_pos, minigame_texture("pong/paddle"),
192                                         paddle_size, '1 0 0', panel_fg_alpha, DRAWFLAG_NORMAL );
193                 }
194         }
195 }
196
197
198 // Required function, draw the game status panel
199 void minigame_hud_status_pong(vector pos, vector mySize)
200 {
201         HUD_Panel_DrawBg(1);
202         vector ts;
203         ts = minigame_drawstring_wrapped(mySize_x,pos,active_minigame.descriptor.message,
204                 hud_fontsize * 2, '0.25 0.47 0.72', panel_fg_alpha, DRAWFLAG_NORMAL,0.5);
205         
206         pos_y += ts_y;
207         mySize_y -= ts_y;
208         
209         vector player_fontsize = hud_fontsize * 1.75;
210         ts_y = ( mySize_y - 2*player_fontsize_y ) / 2;
211         ts_x = mySize_x;
212         vector mypos;
213         vector tile_size = '48 48 0';
214
215         entity e;
216         FOREACH_MINIGAME_ENTITY(e)
217         {
218                 if ( e.classname == "minigame_player" )
219                 {
220                         mypos = pos;
221                         if ( e.team == 2 )
222                                 mypos_y  += player_fontsize_y + ts_y;
223                         minigame_drawcolorcodedstring_trunc(mySize_x,mypos,
224                                 (e.minigame_playerslot ? GetPlayerName(e.minigame_playerslot-1) : _("AI")),
225                                 player_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
226                         
227                         mypos_y += player_fontsize_y;
228                         
229                         drawstring(mypos,ftos(e.pong_score),tile_size,
230                                            '0.7 0.84 1', panel_fg_alpha, DRAWFLAG_NORMAL);
231                 }
232         }
233 }
234
235
236 // Required function, handle client events
237 int minigame_event_pong(entity minigame, string event, ...)
238 {
239         switch(event)
240         {
241                 case "activate":
242                         return false;
243                 case "key_pressed":
244                         switch ( ...(0,int) )
245                         {
246                                 case K_UPARROW:
247                                 case K_KP_UPARROW:
248                                         return true;
249                                 case K_DOWNARROW:
250                                 case K_KP_DOWNARROW:
251                                         return true;
252                         }
253                         return false;
254                 case "network_receive":
255                 {
256                         entity sent = ...(0,entity);
257                         int sf = ...(1,int);
258                         if ( sent.classname == "minigame_player" && (sf & PONG_SF_PLAYERSCORE ) )
259                         {
260                                 sent.pong_score = ReadByte();
261                         }
262                         else if ( sent.classname == "minigame" && (sf & PONG_SF_SINGLEPLAYER) )
263                         {
264                                 int ai = ReadByte();
265                                 bool spawnai = ai && !sent.pong_ai;
266                                 sent.pong_ai = ai;
267                                 
268                                 if ( spawnai )
269                                 {
270                                         entity aiplayer = spawn();
271                                         aiplayer.classname = "minigame_player";
272                                         aiplayer.owner = minigame;
273                                         aiplayer.team = ai;
274                                         aiplayer.minigame_playerslot = 0;
275                                         aiplayer.minigame_autoclean = 1;
276                                         // todo aiplayer.think
277                                 }
278                         }
279                         return false;
280                 }
281                 case "menu_show":
282                 {
283                         HUD_MinigameMenu_CustomEntry(...(0,entity),_("Single Player"),"singleplayer");
284                         return false;
285                 }
286                 case "menu_click":
287                 {
288                         if ( ...(0,string) == "singleplayer" && !minigame.pong_ai )
289                         {
290                                 if ( minigame_count_players(minigame) == 1 )
291                                         minigame_cmd("singleplayer");
292                         }
293                         return false;
294                 }
295         }
296
297         return false;
298 }
299 #endif