From 339f6065ac2e63085046a9011f960909deb744b4 Mon Sep 17 00:00:00 2001 From: Mattia Basaglia Date: Wed, 11 Feb 2015 19:38:50 +0100 Subject: [PATCH] Very basic pong setup --- qcsrc/common/minigames/cl_minigames.qc | 9 +- qcsrc/common/minigames/minigame/all.qh | 5 + qcsrc/common/minigames/minigame/pong.qc | 299 ++++++++++++++++++++++++ 3 files changed, 310 insertions(+), 3 deletions(-) create mode 100644 qcsrc/common/minigames/minigame/pong.qc diff --git a/qcsrc/common/minigames/cl_minigames.qc b/qcsrc/common/minigames/cl_minigames.qc index e9a8a4b41..85ddf57ff 100644 --- a/qcsrc/common/minigames/cl_minigames.qc +++ b/qcsrc/common/minigames/cl_minigames.qc @@ -251,9 +251,12 @@ void ent_read_minigame() if ( minigame_ent ) minigame_ent.minigame_event(minigame_ent,"network_receive",self,sf); - dprint("CL Reading entity: ",ftos(num_for_edict(self)), - " classname:",self.classname," enttype:",ftos(self.enttype) ); - dprint(" sf:",ftos(sf)," netname:",self.netname,"\n\n"); + if ( sf & MINIG_SF_CREATE ) + { + dprint("CL Reading entity: ",ftos(num_for_edict(self)), + " classname:",self.classname," enttype:",ftos(self.enttype) ); + dprint(" sf:",ftos(sf)," netname:",self.netname,"\n\n"); + } } #undef ReadFloat #undef ReadString diff --git a/qcsrc/common/minigames/minigame/all.qh b/qcsrc/common/minigames/minigame/all.qh index 72e8edda4..4f2f1ea08 100644 --- a/qcsrc/common/minigames/minigame/all.qh +++ b/qcsrc/common/minigames/minigame/all.qh @@ -43,6 +43,7 @@ used as send flags for minigame entities: * MINIG_SF_CREATE Used when creating a new object, you can use this to define fields that don't change + Don't add MINIG_SF_CREATE to SendFlags on your own * MINIG_SF_UPDATE A miscellaneous update, can be safely used if the entity has just a few fields * MINIG_SF_CUSTOM @@ -62,6 +63,7 @@ that .owner is set to the minigame session entity and .minigame_autoclean is tru #include "nmm.qc" #include "ttt.qc" +#include "pong.qc" /** * Registration: @@ -72,6 +74,7 @@ that .owner is set to the minigame session entity and .minigame_autoclean is tru #define REGISTERED_MINIGAMES \ MINIGAME(nmm, "Nine Men's Morris") \ MINIGAME(ttt, "Tic Tac Toe") \ + MINIGAME(pong, "Pong") \ /*empty line*/ /** @@ -102,4 +105,6 @@ that .owner is set to the minigame session entity and .minigame_autoclean is tru */ #define MINIGAME_SIMPLELINKED_ENTITIES \ MSLE(minigame_board_piece,FIELD(MINIG_SF_CREATE,Byte,team) FIELD(MINIG_SF_UPDATE, Short, minigame_flags) FIELD(MINIG_SF_UPDATE, Vector2D,origin)) \ + MSLE(pong_paddle,FIELD(MINIG_SF_CREATE,Byte,team) FIELD(MINIG_SF_CREATE,Float,pong_length) FIELD(MINIG_SF_UPDATE,Vector2D,origin)) \ + MSLE(pong_ball, FIELD(MINIG_SF_UPDATE, Vector2D, velocity) FIELD(MINIG_SF_UPDATE, Vector2D, origin)) \ /*empty line*/ diff --git a/qcsrc/common/minigames/minigame/pong.qc b/qcsrc/common/minigames/minigame/pong.qc new file mode 100644 index 000000000..706620d2c --- /dev/null +++ b/qcsrc/common/minigames/minigame/pong.qc @@ -0,0 +1,299 @@ +// minigame flags +const int PONG_MGF_RESET = 0x0010; // Ball is reset to the center + +// send flags +const int PONG_SF_PLAYERSCORE = MINIG_SF_CUSTOM; // sent when reporting scores +const int PONG_SF_SINGLEPLAYER = MINIG_SF_CUSTOM<<1;// send minigame.pong_ai + +// fields +.int pong_ai; // (minigame) when non-zero, singleplayer vs AI +.int pong_score; // (minigame_player) number of goals +.float pong_length;// (pong_paddle) size (0,1) + +#ifdef SVQC + +float autocvar_sv_minigames_pong_paddlesize = 0.3; +float autocvar_sv_minigames_pong_paddlespeed= 1; +float autocvar_sv_minigames_pong_ballwait = 1; +float autocvar_sv_minigames_pong_ballspeed = 1; + +void pong_ball_think(); + +void pong_ball_thinkthrow() +{ + float angle; + do + angle = random()*M_PI*2; + while ( (angle > 0.44*M_PI && angle < 0.55*M_PI) || + (angle > 1.44*M_PI && angle < 1.55*M_PI) ); + self.velocity_x = cos(angle)*autocvar_sv_minigames_pong_ballspeed; + self.velocity_y = sin(angle)*autocvar_sv_minigames_pong_ballspeed; + self.SendFlags |= MINIG_SF_UPDATE; + self.think = pong_ball_think; + self.nextthink = time; +} + +void pong_reset_ball(entity ball) +{ + ball.velocity = '0 0 0'; + ball.origin = '0.5 0.5 0'; + ball.SendFlags |= MINIG_SF_UPDATE; + ball.think = pong_ball_thinkthrow; + ball.nextthink = time + autocvar_sv_minigames_pong_ballwait; +} + +void pong_ball_think() +{ + float think_speed = autocvar_sys_ticrate; + self.nextthink = time + think_speed; + + self.origin_x += self.velocity_x * think_speed; + self.origin_y += self.velocity_y * think_speed; + if ( self.origin_y <= 0 ) + { + self.origin_y = 0; + self.velocity_y *= -1; + } + else if ( self.origin_y >= 1 ) + { + self.origin_y = 1; + self.velocity_y *= -1; + } + + // todo score + if ( self.origin_x <= 0 ) + { + pong_reset_ball(self); + } + else if ( self.origin_x >= 1 ) + { + pong_reset_ball(self); + } + + self.SendFlags |= MINIG_SF_UPDATE; +} + +void pong_paddle_think() +{ + float think_speed = autocvar_sys_ticrate; + self.nextthink = time + think_speed; + + if ( self.realowner.movement.x > 0 && self.origin_y > self.pong_length/2 ) + { + self.origin_y -= autocvar_sv_minigames_pong_paddlespeed * think_speed; + if ( self.origin_y < 0 ) + self.origin_y = 0; + self.SendFlags |= MINIG_SF_UPDATE; + } + else if ( self.realowner.movement.x < 0 && self.origin_y < 1-self.pong_length/2 ) + { + self.origin_y += autocvar_sv_minigames_pong_paddlespeed * think_speed; + if ( self.origin_y > 1 ) + self.origin_y = 1; + self.SendFlags |= MINIG_SF_UPDATE; + } + +} + +// required function, handle server side events +int minigame_event_pong(entity minigame, string event, ...) +{ + switch (event) + { + case "start": + { + entity ball = msle_spawn(minigame,"pong_ball"); + pong_reset_ball(ball); + minigame.minigame_flags = PONG_MGF_RESET; // todo useful? + + return true; + } + case "end": + // nothing to do + return false; + case "join": + { + int pl_num = minigame_count_players(minigame); + + // Don't allow joining a single player match + if ( (minigame.pong_ai) && pl_num > 0 ) + return false; + + // Don't allow more than 2 players + if(pl_num >= 2) { return false; } + + int pl_team = 1; + // Get the right team + if(minigame.minigame_players) + pl_team = minigame_next_team(minigame.minigame_players.team, 2); + + + entity player = ...(0,entity); + entity paddle = msle_spawn(minigame,"pong_paddle");// Note puddle isn't a typo + paddle.pong_length = autocvar_sv_minigames_pong_paddlesize; + paddle.origin_y = 0.5; + paddle.origin_x = pl_team == 1 ? 0.95 : 0.05; + paddle.think = pong_paddle_think; + paddle.nextthink = time; + paddle.team = pl_team; + paddle.realowner = player; + + // Team 1 by default + return pl_team; + } + case "cmd": + // nothing to do + return false; + case "network_send": + { + entity sent = ...(0,entity); + int sf = ...(1,int); + if ( sent.classname == "minigame_player" && (sf & PONG_SF_PLAYERSCORE ) ) + { + WriteByte(MSG_ENTITY,sent.pong_score); + } + else if ( sent.classname == "minigame" && (sf & PONG_SF_SINGLEPLAYER) ) + { + WriteByte(MSG_ENTITY,sent.pong_ai); + } + return false; + } + } + return false; +} + + +#elif defined(CSQC) + + +// Required function, draw the game board +void minigame_hud_board_pong(vector pos, vector mySize) +{ + minigame_hud_fitsqare(pos, mySize); + minigame_hud_simpleboard(pos,mySize,minigame_texture("pong/board")); + + entity e; + vector obj_pos; + vector ball_size = minigame_hud_denormalize_size('1 1 0' / 16,pos,mySize); + vector paddle_size; + FOREACH_MINIGAME_ENTITY(e) + { + if ( e.classname == "pong_ball" ) + { + obj_pos = minigame_hud_denormalize(e.origin,pos,mySize); + minigame_drawpic_centered( obj_pos, minigame_texture("pong/ball"), + ball_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL ); + } + else if ( e.classname == "pong_paddle" ) + { + obj_pos = minigame_hud_denormalize(e.origin,pos,mySize); + paddle_size = minigame_hud_denormalize_size(eX / 16 + eY*e.pong_length,pos,mySize); + minigame_drawpic_centered( obj_pos, minigame_texture("pong/paddle"), + paddle_size, '1 0 0', panel_fg_alpha, DRAWFLAG_NORMAL ); + } + } +} + + +// Required function, draw the game status panel +void minigame_hud_status_pong(vector pos, vector mySize) +{ + HUD_Panel_DrawBg(1); + vector ts; + ts = minigame_drawstring_wrapped(mySize_x,pos,active_minigame.descriptor.message, + hud_fontsize * 2, '0.25 0.47 0.72', panel_fg_alpha, DRAWFLAG_NORMAL,0.5); + + pos_y += ts_y; + mySize_y -= ts_y; + + vector player_fontsize = hud_fontsize * 1.75; + ts_y = ( mySize_y - 2*player_fontsize_y ) / 2; + ts_x = mySize_x; + vector mypos; + vector tile_size = '48 48 0'; + + entity e; + FOREACH_MINIGAME_ENTITY(e) + { + if ( e.classname == "minigame_player" ) + { + mypos = pos; + if ( e.team == 2 ) + mypos_y += player_fontsize_y + ts_y; + minigame_drawcolorcodedstring_trunc(mySize_x,mypos, + (e.minigame_playerslot ? GetPlayerName(e.minigame_playerslot-1) : _("AI")), + player_fontsize, panel_fg_alpha, DRAWFLAG_NORMAL); + + mypos_y += player_fontsize_y; + + drawstring(mypos,ftos(e.pong_score),tile_size, + '0.7 0.84 1', panel_fg_alpha, DRAWFLAG_NORMAL); + } + } +} + + +// Required function, handle client events +int minigame_event_pong(entity minigame, string event, ...) +{ + switch(event) + { + case "activate": + return false; + case "key_pressed": + switch ( ...(0,int) ) + { + case K_UPARROW: + case K_KP_UPARROW: + return true; + case K_DOWNARROW: + case K_KP_DOWNARROW: + return true; + } + return false; + case "network_receive": + { + entity sent = ...(0,entity); + int sf = ...(1,int); + if ( sent.classname == "minigame_player" && (sf & PONG_SF_PLAYERSCORE ) ) + { + sent.pong_score = ReadByte(); + } + else if ( sent.classname == "minigame" && (sf & PONG_SF_SINGLEPLAYER) ) + { + int ai = ReadByte(); + bool spawnai = ai && !sent.pong_ai; + sent.pong_ai = ai; + + if ( spawnai ) + { + entity aiplayer = spawn(); + aiplayer.classname = "minigame_player"; + aiplayer.owner = minigame; + aiplayer.team = ai; + aiplayer.minigame_playerslot = 0; + aiplayer.minigame_autoclean = 1; + // todo aiplayer.think + } + } + return false; + } + case "menu_show": + { + HUD_MinigameMenu_CustomEntry(...(0,entity),_("Single Player"),"singleplayer"); + return false; + } + case "menu_click": + { + if ( ...(0,string) == "singleplayer" && !minigame.pong_ai ) + { + if ( minigame_count_players(minigame) == 1 ) + minigame_cmd("singleplayer"); + } + return false; + } + } + + return false; +} +#endif \ No newline at end of file -- 2.39.2