2 const int PONG_MGF_RESET = 0x0010; // Ball is reset to the center
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
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)
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;
20 void pong_ball_think();
22 void pong_ball_thinkthrow()
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;
36 void pong_reset_ball(entity ball)
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;
45 void pong_ball_think()
47 float think_speed = autocvar_sys_ticrate;
48 self.nextthink = time + think_speed;
50 self.origin_x += self.velocity_x * think_speed;
51 self.origin_y += self.velocity_y * think_speed;
52 if ( self.origin_y <= 0 )
55 self.velocity_y *= -1;
57 else if ( self.origin_y >= 1 )
60 self.velocity_y *= -1;
64 if ( self.origin_x <= 0 )
66 pong_reset_ball(self);
68 else if ( self.origin_x >= 1 )
70 pong_reset_ball(self);
73 self.SendFlags |= MINIG_SF_UPDATE;
76 void pong_paddle_think()
78 float think_speed = autocvar_sys_ticrate;
79 self.nextthink = time + think_speed;
81 if ( self.realowner.movement.x > 0 && self.origin_y > self.pong_length/2 )
83 self.origin_y -= autocvar_sv_minigames_pong_paddlespeed * think_speed;
84 if ( self.origin_y < 0 )
86 self.SendFlags |= MINIG_SF_UPDATE;
88 else if ( self.realowner.movement.x < 0 && self.origin_y < 1-self.pong_length/2 )
90 self.origin_y += autocvar_sv_minigames_pong_paddlespeed * think_speed;
91 if ( self.origin_y > 1 )
93 self.SendFlags |= MINIG_SF_UPDATE;
98 // required function, handle server side events
99 int minigame_event_pong(entity minigame, string event, ...)
105 entity ball = msle_spawn(minigame,"pong_ball");
106 pong_reset_ball(ball);
107 minigame.minigame_flags = PONG_MGF_RESET; // todo useful?
116 int pl_num = minigame_count_players(minigame);
118 // Don't allow joining a single player match
119 if ( (minigame.pong_ai) && pl_num > 0 )
122 // Don't allow more than 2 players
123 if(pl_num >= 2) { return false; }
126 // Get the right team
127 if(minigame.minigame_players)
128 pl_team = minigame_next_team(minigame.minigame_players.team, 2);
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;
149 entity sent = ...(0,entity);
151 if ( sent.classname == "minigame_player" && (sf & PONG_SF_PLAYERSCORE ) )
153 WriteByte(MSG_ENTITY,sent.pong_score);
155 else if ( sent.classname == "minigame" && (sf & PONG_SF_SINGLEPLAYER) )
157 WriteByte(MSG_ENTITY,sent.pong_ai);
169 // Required function, draw the game board
170 void minigame_hud_board_pong(vector pos, vector mySize)
172 minigame_hud_fitsqare(pos, mySize);
173 minigame_hud_simpleboard(pos,mySize,minigame_texture("pong/board"));
177 vector ball_size = minigame_hud_denormalize_size('1 1 0' / 16,pos,mySize);
179 FOREACH_MINIGAME_ENTITY(e)
181 if ( e.classname == "pong_ball" )
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 );
187 else if ( e.classname == "pong_paddle" )
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 );
198 // Required function, draw the game status panel
199 void minigame_hud_status_pong(vector pos, vector mySize)
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);
209 vector player_fontsize = hud_fontsize * 1.75;
210 ts_y = ( mySize_y - 2*player_fontsize_y ) / 2;
213 vector tile_size = '48 48 0';
216 FOREACH_MINIGAME_ENTITY(e)
218 if ( e.classname == "minigame_player" )
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);
227 mypos_y += player_fontsize_y;
229 drawstring(mypos,ftos(e.pong_score),tile_size,
230 '0.7 0.84 1', panel_fg_alpha, DRAWFLAG_NORMAL);
236 // Required function, handle client events
237 int minigame_event_pong(entity minigame, string event, ...)
244 switch ( ...(0,int) )
254 case "network_receive":
256 entity sent = ...(0,entity);
258 if ( sent.classname == "minigame_player" && (sf & PONG_SF_PLAYERSCORE ) )
260 sent.pong_score = ReadByte();
262 else if ( sent.classname == "minigame" && (sf & PONG_SF_SINGLEPLAYER) )
265 bool spawnai = ai && !sent.pong_ai;
270 entity aiplayer = spawn();
271 aiplayer.classname = "minigame_player";
272 aiplayer.owner = minigame;
274 aiplayer.minigame_playerslot = 0;
275 aiplayer.minigame_autoclean = 1;
276 // todo aiplayer.think
283 HUD_MinigameMenu_CustomEntry(...(0,entity),_("Single Player"),"singleplayer");
288 if ( ...(0,string) == "singleplayer" && !minigame.pong_ai )
290 if ( minigame_count_players(minigame) == 1 )
291 minigame_cmd("singleplayer");