Date: Friday January 26, 2001 @ 17:58 Author: ahn Update of /home/netrek/cvsroot/Vanilla/robots In directory swashbuckler.fortress.real-time.com:/var/tmp/cvs-serv2637 Modified Files: inl.c inlcomm.c inldefs.h Log Message: Added momentum scoring support. Changed continuous scoring parameters. See README.scores and ChangeLog for details. **************************************** Index: Vanilla/robots/inl.c diff -u Vanilla/robots/inl.c:1.35 Vanilla/robots/inl.c:1.36 --- Vanilla/robots/inl.c:1.35 Tue Nov 14 22:12:47 2000 +++ Vanilla/robots/inl.c Fri Jan 26 17:58:01 2001 @@ -1,7 +1,7 @@ -/* $Id: inl.c,v 1.35 2000/11/15 04:12:47 ahn Exp $ */ +/* $Id: inl.c,v 1.36 2001/01/26 23:58:01 ahn Exp $ */ #ifndef lint -static char vcid[] = "$Id: inl.c,v 1.35 2000/11/15 04:12:47 ahn Exp $"; +static char vcid[] = "$Id: inl.c,v 1.36 2001/01/26 23:58:01 ahn Exp $"; #endif /* lint */ /* @@ -114,6 +114,7 @@ 0, /* tmout_ticks */ 0, /* time */ 0, /* overtime */ + 0, /* extratime */ 0, /* score_mode */ 0.0 /* weighted_divisor */ }; @@ -600,24 +601,30 @@ int p, t; double weight = (double) inl_stat.game_ticks / (double) inl_stat.time; + static const double weight_max = 2.7408445; /* 0.5 + 0.5 * exp(1.5); */ + + /* sanity check! */ if (weight < 0.0) weight = 0.0; else if (weight > 1.0) weight = 1.0; /* weight = linear range between 0.0 and 1.0 during regulation. - * map this to 0.75 <-> 1.5 range + * map this to exponential curve using formula: + * weight = 0.5 + 0.5 * exp(1.5 * time) + * weight range is 1.0 to 2.7408445 * -da */ - weight = 0.75 + (0.75 * weight); + weight = 0.5 + 0.5 * exp(1.5 * weight); /* sanity check */ - if (weight < 0.75) - weight = 0.75; - else if (weight > 1.5) - weight = 1.5; + if (weight < 1.0) + weight = 1.0; + else if (weight > weight_max) + weight = weight_max; - inl_stat.weighted_divisor += (weight * 4.0); + /* weight multiply factor should be max points you can get per planet */ + inl_stat.weighted_divisor += (weight * 2.0); for (p=0; p<MAXPLANETS; p++) { @@ -626,12 +633,15 @@ if (sides[inl_teams[t].side_index].flag == planets[p].pl_owner) { /* planet is owned by this team, so it has > 0 armies. each planet - is worth 1-4 points for each army on the planet, capped at 4. */ + is worth 1-2 points for each pair of armies on the planet, + capped at 2. I.e. 1-2 armies = 1 pt, >=3 armies = 2 pts. */ int points = planets[p].pl_armies; - if (points > 4) - points = 4; + if (points > 2) + points = 2; + else + points = 1; /* absolute continuous score is just the cumulative point total */ inl_teams[t].abs_score += points; @@ -651,9 +661,9 @@ } - /* announce updated scores every 5 minutes */ + /* announce updated scores every 5 minutes if not in normal mode */ - if ((inl_stat.game_ticks % (5 * PERMIN)) == 0) + if (inl_stat.score_mode && ((inl_stat.game_ticks % (5 * PERMIN)) == 0)) announce_scores(0, MALL, NULL); } @@ -733,30 +743,44 @@ #endif /* Determine if there is a winner at the end of regulation. - returns 0 if game is tied - returns 1 if there is a winner by planet count - returns 2 if there is a winner by continuous score > 2.0 - returns 3 if there is a winner by continuous score < 2.0 & planet 11-8-1 + returns -1 if momentum score goes to EXTRA TIME + returns 0 if game is tied + returns 1 if winner by planet count + returns 2 if winner by continuous score > 2.0 + returns 3 if winner by continuous score < 2.0 & planet 11-8-1 + returns 4 if winner by momentum scoring -da */ int check_winner() { double divisor = inl_stat.weighted_divisor; double delta; + /* -1 = HOME is winning + * 0 = tied + * 1 = AWAY is winning */ + int winning_cont = 0; + int winning_norm = 0; + countplanets(); - /* NORMAL scoring mode; OR, continuous scoring and in OT. + if (inl_teams[HOME].planets > inl_teams[AWAY].planets + 2) + winning_norm = -1; + else if (inl_teams[AWAY].planets > inl_teams[HOME].planets + 2) + winning_norm = 1; + else + winning_norm = 0; + + /* NORMAL scoring mode; OR, continuous/momentum scoring and in OT. Use absolute planet count. */ + if ((inl_stat.score_mode == 0) || (inl_stat.flags & S_OVERTIME)) { - if (inl_teams[HOME].planets > inl_teams[AWAY].planets + 2) - return 1; - else if (inl_teams[AWAY].planets > inl_teams[HOME].planets + 2) + if (winning_norm) return 1; else return 0; } - /* CONTINUOUS scoring mode */ + /* CONTINUOUS or MOMENTUM scoring mode */ /* sanity check */ if (inl_stat.weighted_divisor < 1.0) @@ -765,25 +789,51 @@ if (inl_stat.game_ticks < 100) return 0; - delta = inl_teams[0].weighted_score / divisor - - inl_teams[1].weighted_score / divisor; + delta = inl_teams[HOME].weighted_score / divisor - + inl_teams[AWAY].weighted_score / divisor; - /* multiply by -1 instead of fabs() */ - if (delta < 0.0) - delta *= -1.0; - - /* if continuous score delta is >= 2.0, we have winner */ + /* 2.0 is the differential */ if (delta >= 2.0) - return 2; + winning_cont = -1; + else if (delta <= -2.0) + winning_cont = 1; + else + winning_cont = 0; + + /* CONTINUOUS scoring mode: + delta > 2.0: win + delta < 2.0 but planet > 11-8-1: win + otherwise, tie. + */ + + if (inl_stat.score_mode == 1) { + + if (winning_cont) + return 2; + else if (winning_norm) + return 3; + else + return 0; + + } - /* if continuous score delta is < 2.0, but a team has > 11-8-1, - we have a winner */ - else if ((inl_teams[HOME].planets > inl_teams[AWAY].planets + 2) || - (inl_teams[AWAY].planets > inl_teams[HOME].planets + 2)) - return 3; + /* MOMENTUM scoring mode */ + else if (inl_stat.score_mode == 2) { - /* otherwise, game is a tie */ - return 0; + /* game tied, go to OT */ + if (!winning_cont && !winning_norm) + return 0; + + /* if either team is winning by at least one method, return winner */ + if (winning_cont + winning_norm) + return 4; + + /* otherwise, EXTRA TIME */ + else + return -1; + + } + } int @@ -792,44 +842,102 @@ int game_over = 0; int win_cond; - if ((win_cond = check_winner()) != 0) + /* check_winner always returns > 0 if winner exists */ + if ((win_cond = check_winner()) > 0) { pmessage(0, MALL, inl_from, "---------- Game Over ----------"); - pmessage(0, MALL, inl_from, "Planet count: %i - %i - %i", - inl_teams[HOME].planets, inl_teams[AWAY].planets, - (20 - inl_teams[HOME].planets - inl_teams[AWAY].planets)); /* need to write this to the inl_log because the pmessages don't get flushed out to the log before the close */ fprintf(inl_log, "---------- Game Over ---------\n"); - fprintf(inl_log, "SCORE: Planet count: %i - %i - %i\n", - inl_teams[HOME].planets, inl_teams[AWAY].planets, - (20 - inl_teams[HOME].planets - inl_teams[AWAY].planets)); announce_scores(0, MALL, inl_log); switch(win_cond) { case 1: - pmessage(0, MALL, inl_from, "Victory by: planet count (normal scoring)"); - fprintf(inl_log, "SCORE: Victory by planet count (normal scoring)\n"); + pmessage(0, MALL, inl_from, "Victory by planet count"); + fprintf(inl_log, "SCORE: Victory by planet count\n"); break; case 2: - pmessage(0, MALL, inl_from, "Victory by: continuous score >= 2.0"); - fprintf(inl_log, "SCORE: Victory by: continuous score >= 2.0\n"); + pmessage(0, MALL, inl_from, "Victory by continuous score >= 2.0"); + fprintf(inl_log, "SCORE: Victory by continuous score >= 2.0\n"); break; case 3: - pmessage(0, MALL, inl_from, "Victory by: planet count (continuous score < 2.0)"); - fprintf(inl_log, "SCORE: Victory by: planet count (continuous score < 2.0)\n"); + pmessage(0, MALL, inl_from, "Victory by planet count (continuous score < 2.0)"); + fprintf(inl_log, "SCORE: Victory by planet count (continuous score < 2.0)\n"); + break; + case 4: + pmessage(0, MALL, inl_from, "Victory by momentum score"); + fprintf(inl_log, "SCORE: Victory by momentum score\n"); break; default: - pmessage(0, MALL, inl_from, "Victory by: UNKNOWN"); - fprintf(inl_log, "SCORE: Victory by: UNKNOWN\n"); + pmessage(0, MALL, inl_from, "Victory by UNKNOWN"); + fprintf(inl_log, "SCORE: Victory by UNKNOWN\n"); break; } game_over = 1; } + + /* still in regulation, but momentum scoring dictates EXTRA TIME */ + else if ((inl_stat.flags & S_TOURNEY) && (win_cond == -1)) + { + + static const int extratime = 5 * PERMIN; + static const int extra_max = 5 * PERMIN * 3; + + /* only allow 3 cycles of extra time */ + if (inl_stat.extratime < extra_max) { + + pmessage(0, MALL, inl_from, "---------- Extra Time (Momentum) ----------"); + pmessage(0, MALL, inl_from, "%i of %i total minutes added to regulation.", + extratime / PERMIN, extra_max); + + fprintf(inl_log, "---------- Extra Time (Momentum) ----------\n"); + fprintf(inl_log, "%i of %i total minutes added to regulation\n", + extratime / PERMIN, extra_max); + + /* first extra time cycle results in obliteration */ + if (inl_stat.extratime == 0) + obliterate(0,KPROVIDENCE); + + inl_stat.extratime += extratime; + + inl_game.idx = 0; + inl_game.end += extratime; + inl_game.message = "%i %s left in EXTRA time (momentum)"; + + announce_scores(0, MALL, inl_log); + + } + + /* after extra time is over, declare continuous score the winner */ + else { + pmessage(0, MALL, inl_from, "---------- Game Over (Momentum) ----------"); + + fprintf(inl_log, "---------- Game Over (Momentum) ----------\n"); + + announce_scores(0, MALL, inl_log); + + if (inl_teams[0].weighted_score > inl_teams[1].weighted_score) { + pmessage(0, MALL, inl_from, "Tie breaker: %s wins by continuous score", + sides[inl_teams[0].side_index].name); + fprintf(inl_log, "Tie breaker: %s wins by continuous score\n", + sides[inl_teams[0].side_index].name); + } + else { + pmessage(0, MALL, inl_from, "Tie breaker: %s wins by continuous score", + sides[inl_teams[1].side_index].name); + fprintf(inl_log, "Tie breaker: %s wins by continuous score\n", + sides[inl_teams[1].side_index].name); + } + + game_over = 1; + } + + } + else if (inl_stat.flags & S_TOURNEY) { inl_stat.flags &= ~(S_TOURNEY | S_COUNTDOWN); @@ -843,10 +951,6 @@ /* inl_game.counts[0] = inl_stat.overtime / (PERMIN*2); */ inl_game.message = "%i %s left in overtime"; - fprintf(inl_log, "SCORE: Planet count: %i - %i - %i\n", - inl_teams[HOME].planets, inl_teams[AWAY].planets, - (20 - inl_teams[HOME].planets - inl_teams[AWAY].planets)); - announce_scores(0, MALL, inl_log); } else if (inl_game.end <= inl_stat.game_ticks) @@ -855,9 +959,6 @@ "------ Game ran out of time without a winner ------"); fprintf(inl_log, "---------- Game Over (TIED) ---------\n"); - fprintf(inl_log, "SCORE: Planet count: %i - %i - %i\n", - inl_teams[HOME].planets, inl_teams[AWAY].planets, - (20 - inl_teams[HOME].planets - inl_teams[AWAY].planets)); announce_scores(0, MALL, inl_log); game_over = 1; @@ -1320,8 +1421,17 @@ pmessage (0, MALL, inl_from, "%s is the starting time of t-mode play.", tmp); - if (inl_stat.score_mode) - pmessage(0, MALL, inl_from, "Continuous scoring enabled."); + switch(inl_stat.score_mode) { + case 0: + pmessage(0, MALL, inl_from, "Planet scoring enabled."); + break; + case 1: + pmessage(0, MALL, inl_from, "Continuous scoring enabled."); + break; + case 2: + pmessage(0, MALL, inl_from, "Momentum scoring enabled."); + break; + } doResources(0); Index: Vanilla/robots/inlcomm.c diff -u Vanilla/robots/inlcomm.c:1.19 Vanilla/robots/inlcomm.c:1.20 --- Vanilla/robots/inlcomm.c:1.19 Sat Nov 4 17:49:40 2000 +++ Vanilla/robots/inlcomm.c Fri Jan 26 17:58:01 2001 @@ -259,6 +259,20 @@ return 0; } + if (inl_teams[HOME].score_mode != inl_teams[AWAY].score_mode) + { + pmessage(0, MALL, inl_from, + "Scoring mode has not be approved by both sides!"); + for (c = 0; c < INLTEAM; c++) + { + pmessage(0, MALL, inl_from, + "%s (%s) has set score mode to %d", + inl_teams[c].t_name, inl_teams[c].name, + inl_teams[c].score_mode); + } + return 0; + } + for (c=0; c < INLTEAM; c++) inl_teams[c].flags &= ~T_START; @@ -314,6 +328,9 @@ time = inl_stat.time; if (inl_stat.flags & S_OVERTIME) time += inl_stat.overtime; + + time += inl_stat.extratime; + #ifdef nodef pmessage(who, MINDIV, addr_mess(who, MINDIV), "Minutes remaining: %i Planet tally: %i - %i - %i", @@ -324,9 +341,13 @@ { int seconds = ( (time - inl_stat.game_ticks) / PERSEC ) % 60; int minutes = ( (time - inl_stat.game_ticks) / PERMIN ); - - pmessage(who, MINDIV, addr_mess(who, MINDIV), - "Time remaining: %d:%02.2d", minutes, seconds); + + if (inl_stat.overtime) + pmessage(who, MINDIV, addr_mess(who, MINDIV), + "Extra Time remaining: %d:%02.2d", minutes, seconds); + else + pmessage(who, MINDIV, addr_mess(who, MINDIV), + "Time remaining: %d:%02.2d", minutes, seconds); } #endif @@ -1033,9 +1054,11 @@ void announce_scores(int who, int flag, FILE *fp) { int win_cond; - char *side; - - float divisor = (float) (inl_stat.game_ticks * 4); + char *h_name, *a_name; + char *p_ahead, *c_ahead, *m_ahead; + char *s_mode; + float h_cont, a_cont; + int h_planets, a_planets, n_planets; if (inl_stat.game_ticks < 1) return; @@ -1043,81 +1066,94 @@ if (inl_stat.weighted_divisor < 1.0) return; - if (inl_stat.score_mode == 0) - pmessage(who, flag, addr_mess(who, flag), "Scoring mode: planet count"); - else - pmessage(who, flag, addr_mess(who, flag), "Scoring mode: continuous score"); + /* this is critical! */ + win_cond = check_winner(); - pmessage(who, flag, addr_mess(who, flag), - "Continuous score: %s vs %s %.2f - %.2f (weighted)", - sides[inl_teams[0].side_index].name, - sides[inl_teams[1].side_index].name, - (float) inl_teams[0].weighted_score / inl_stat.weighted_divisor, - (float) inl_teams[1].weighted_score / inl_stat.weighted_divisor); - - if (fp) - fprintf(fp, "SCORE: Continuous score: %s vs %s %.2f - %.2f (weighted)\n", - sides[inl_teams[0].side_index].name, - sides[inl_teams[1].side_index].name, - (float) inl_teams[0].weighted_score / inl_stat.weighted_divisor, - (float) inl_teams[1].weighted_score / inl_stat.weighted_divisor); - - - /***** no need for these debug statements -da - if (divisor < 1.0f) - divisor = 1.0f; + h_name = sides[inl_teams[HOME].side_index].name; + a_name = sides[inl_teams[AWAY].side_index].name; - pmessage(who, flag, addr_mess(who, flag), - "Debug: %s vs %s %.2f - %.2f (continuous)", - sides[inl_teams[0].side_index].name, - sides[inl_teams[1].side_index].name, - (float) inl_teams[0].abs_score / divisor, - (float) inl_teams[1].abs_score / divisor); + h_cont = (float) inl_teams[HOME].weighted_score / inl_stat.weighted_divisor; + a_cont = (float) inl_teams[AWAY].weighted_score / inl_stat.weighted_divisor; - divisor = (float) ((inl_stat.game_ticks / PERMIN) * 4); + h_planets = inl_teams[HOME].planets; + a_planets = inl_teams[AWAY].planets; + n_planets = 20 - h_planets - a_planets; + + if (h_planets > a_planets + 2) + p_ahead = h_name; + else if (a_planets > h_planets + 2) + p_ahead = a_name; + else + p_ahead = "tied"; - if (divisor <= 1.0f) - divisor = 1.0f; + if (h_cont > a_cont + 2.0) + c_ahead = h_name; + else if (a_cont > h_cont + 2.0) + c_ahead = a_name; + else + c_ahead = "tied"; + if ((h_planets > a_planets + 2) || (h_cont > a_cont + 2.0)) + m_ahead = h_name; + else if ((a_planets > h_planets + 2) || (a_cont > h_cont + 2.0)) + m_ahead = a_name; + else + m_ahead = "tied"; + pmessage(who, flag, addr_mess(who, flag), - "Debug: %s vs %s %.2f - %.2f (semi-continuous)", - sides[inl_teams[0].side_index].name, - sides[inl_teams[1].side_index].name, - (float) inl_teams[0].semi_score / divisor, - (float) inl_teams[1].semi_score / divisor); + "Planet count: %s - %s: %i - %i - %i [%s]", + h_name, a_name, h_planets, a_planets, n_planets, p_ahead); - ******/ + pmessage(who, flag, addr_mess(who, flag), + "Continuous score: %s - %s: %.2f - %.2f [%s]", + h_name, a_name, h_cont, a_cont, c_ahead); - win_cond = check_winner(); + if (fp) { + fprintf(fp, "SCORE: Planet count: %s - %s: %i - %i - %i [%s]\n", + h_name, a_name, h_planets, a_planets, n_planets, p_ahead); - side = (inl_teams[0].weighted_score > inl_teams[1].weighted_score)? - sides[inl_teams[0].side_index].name: - sides[inl_teams[1].side_index].name; + fprintf(fp, "SCORE: Continuous score: %s - %s: %.2f - %.2f [%s]\n", + h_name, a_name, h_cont, a_cont, c_ahead); + } - switch(win_cond) { + switch(inl_stat.score_mode) { case 0: - if (inl_stat.score_mode) { - pmessage(who, flag, addr_mess(who, flag), "Game TIED."); + s_mode = "planet count"; + break; + case 1: + s_mode = "continuous score"; + break; + case 2: + s_mode = "momentum score"; + break; + default: + s_mode = "UNKNOWN (report this bug)"; + break; + } - if (fp) fprintf(fp, "SCORE: Game TIED.\n"); - } + switch(win_cond) { + case -1: + case 0: + pmessage(who, flag, addr_mess(who, flag), "Game TIED by %s", s_mode); + if (fp) fprintf(fp, "SCORE: Game TIED by %s\n", s_mode); break; case 1: - pmessage(who, flag, addr_mess(who, flag), - "%s winning by planet count", side); - /* ignore NORMAL scoring mode */ + pmessage(who, flag, addr_mess(who, flag), "%s winning by %s", p_ahead, s_mode); + if (fp) fprintf(fp, "SCORE: %s winning by %s\n", p_ahead, s_mode); break; case 2: - pmessage(who, flag, addr_mess(who, flag), - "%s winning by score >= 2.0", side); - if (fp) - fprintf(fp, "SCORE: %s winning by score >= 2.0\n", side); + pmessage(who, flag, addr_mess(who, flag), "%s winning by %s", c_ahead, s_mode); + if (fp) fprintf(fp, "SCORE: %s winning by %s\n", c_ahead, s_mode); break; case 3: - pmessage(who, flag, addr_mess(who, flag), - "%s winning by score < 2.0 but planet > 11-8-1", side); - if (fp) - fprintf(fp, "SCORE: %s winning by score < 2.0 but planet > 11-8-1\n", side); + pmessage(who, flag, addr_mess(who, flag), "%s winning by %s [tie break]", + p_ahead, s_mode); + if (fp) fprintf(fp, "SCORE: %s winning by %s [tie break]\n", p_ahead, s_mode); + break; + case 4: + pmessage(who, flag, addr_mess(who, flag), "%s winning by %s", + m_ahead, s_mode); + if (fp) fprintf(fp, "SCORE: %s winning by %s\n", m_ahead, s_mode); break; } @@ -1134,6 +1170,7 @@ int who, team; char *mode; + int sc_mode = -1; who = mess->m_from; @@ -1145,12 +1182,29 @@ team = check_player(who, 1); - if (inl_teams[team].score_mode) - inl_teams[team].score_mode = 0; - else - inl_teams[team].score_mode = 1; + comm = strchr(comm, ' '); + + if (comm && (sscanf(comm, "%d", &sc_mode) != 1)) + sc_mode = -1; - mode = (inl_teams[team].score_mode? "CONTINUOUS": "NORMAL"); + switch(sc_mode) { + case 0: + inl_teams[team].score_mode = 0; + mode = "NORMAL"; + break; + case 1: + inl_teams[team].score_mode = 1; + mode = "CONTINUOUS"; + break; + case 2: + inl_teams[team].score_mode = 2; + mode = "MOMENTUM"; + break; + default: + pmessage(who, MINDIV, addr_mess(who, MINDIV), + "Usage: SCOREMODE [012]; 0=planets, 1=continuous; 2=momentum"); + return 0; + } pmessage(0, MALL, inl_from, "%s requests %s scoring mode.", players[who].p_mapchars, mode); Index: Vanilla/robots/inldefs.h diff -u Vanilla/robots/inldefs.h:1.4 Vanilla/robots/inldefs.h:1.5 --- Vanilla/robots/inldefs.h:1.4 Wed Jun 7 15:41:17 2000 +++ Vanilla/robots/inldefs.h Fri Jan 26 17:58:01 2001 @@ -106,6 +106,7 @@ int game_ticks; /* ticks in official game */ int tmout_ticks; int time, overtime; + int extratime; int score_mode; double weighted_divisor; } Inl_stats;