[Freeciv-Dev] Re: (PR#7241) Wish List: observer mode
[Top] [All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
<URL: http://rt.freeciv.org/Ticket/Display.html?id=7241 >
attached is a patch to implement a global observer mode.
I thought long and hard about it, but it seems the best way to implement
the mode is through the dead player which was done in the /dead.
I've added a couple of improvements to the patch. First, use
/obs connection
to attach to a global observer. Second, you can create global observers in
pregame. Also, I've created a unique nation (with a white flag) for
observers.
Hopefully all the /take /obs /detach, etc logic is ok, I _think_ I debugged
it thoroughly, but there could be a corner case I missed.
In my testing (before I fixed everything I found that needed to be fixed) I
was getting some core dumps when I quit out of the server. Hopefully my
fixes cured all this, but look out for them.
-mike
diff -Nur -Xcvs/diff_ignore snap/common/nation.h snap-obs/common/nation.h
--- snap/common/nation.h 2004-07-24 12:39:02.000000000 -0500
+++ snap-obs/common/nation.h 2004-08-28 11:38:57.000000000 -0500
@@ -21,6 +21,8 @@
/* Changing this value will break network compatibility. */
#define NO_NATION_SELECTED (Nation_Type_id)(-1)
+#define OBSERVER_NATION (game.nation_count - 2)
+
/*
* Purpose of this constant is to catch invalid ruleset and network
* data and to allow static allocation of the nation_info packet.
diff -Nur -Xcvs/diff_ignore snap/common/player.c snap-obs/common/player.c
--- snap/common/player.c 2004-08-28 10:38:53.000000000 -0500
+++ snap-obs/common/player.c 2004-08-28 11:48:22.000000000 -0500
@@ -101,6 +101,7 @@
conn_list_init(&plr->connections);
plr->current_conn = NULL;
plr->is_connected = FALSE;
+ plr->is_observer = FALSE;
plr->was_created = FALSE;
plr->is_alive=TRUE;
plr->is_dying = FALSE;
diff -Nur -Xcvs/diff_ignore snap/common/player.h snap-obs/common/player.h
--- snap/common/player.h 2004-08-28 10:38:53.000000000 -0500
+++ snap-obs/common/player.h 2004-08-28 16:51:56.533658904 -0500
@@ -30,6 +30,7 @@
#define ANON_PLAYER_NAME "noname"
#define ANON_USER_NAME "Unassigned"
+#define OBSERVER_NAME "Observer"
/*
* pplayer->ai.barbarian_type uses this enum. Note that the values
@@ -186,6 +187,7 @@
bool turn_done;
int nturns_idle;
bool is_alive;
+ bool is_observer; /* is the player a global observer */
bool is_dying; /* set once the player is in the process of dying */
bool got_tech; /* set once the player is fully dead */
diff -Nur -Xcvs/diff_ignore snap/data/civ1/nations.ruleset
snap-obs/data/civ1/nations.ruleset
--- snap/data/civ1/nations.ruleset 2004-02-22 11:12:03.000000000 -0600
+++ snap-obs/data/civ1/nations.ruleset 2004-08-28 14:02:54.019104395 -0500
@@ -62,6 +62,7 @@
*include "nation/mongol.ruleset"
;
-; barbarians MUST go last
+; observer and barbarians MUST go last in THIS order
;
+*include "nation/observer.ruleset"
*include "nation/barbarian.ruleset"
diff -Nur -Xcvs/diff_ignore snap/data/default/nations.ruleset
snap-obs/data/default/nations.ruleset
--- snap/data/default/nations.ruleset 2004-06-26 17:14:01.000000000 -0500
+++ snap-obs/data/default/nations.ruleset 2004-08-28 14:02:01.720584942
-0500
@@ -103,6 +103,7 @@
*include "nation/afghani.ruleset"
;
-; barbarians MUST go last
+; observer and barbarians MUST go last in THIS order
;
+*include "nation/observer.ruleset"
*include "nation/barbarian.ruleset"
diff -Nur -Xcvs/diff_ignore snap/data/flags/Makefile.am
snap-obs/data/flags/Makefile.am
--- snap/data/flags/Makefile.am 2004-06-25 20:37:21.000000000 -0500
+++ snap-obs/data/flags/Makefile.am 2004-08-28 11:09:59.000000000 -0500
@@ -58,6 +58,7 @@
nato.png \
netherlands.png \
norway.png \
+ observer.png \
olympic.png \
pakistan.png \
peru.png \
diff -Nur -Xcvs/diff_ignore snap/data/misc/flags.spec
snap-obs/data/misc/flags.spec
--- snap/data/misc/flags.spec 2004-07-17 10:33:42.000000000 -0500
+++ snap-obs/data/misc/flags.spec 2004-08-28 11:27:34.000000000 -0500
@@ -76,6 +76,7 @@
"f.nato", "flags/nato"
"f.netherlands", "flags/netherlands"
"f.norway", "flags/norway"
+ "f.observer", "flags/observer"
"f.olympic", "flags/olympic"
"f.pakistan", "flags/pakistan"
"f.peru", "flags/peru"
diff -Nur -Xcvs/diff_ignore snap/data/nation/Makefile.am
snap-obs/data/nation/Makefile.am
--- snap/data/nation/Makefile.am 2004-08-28 10:42:46.000000000 -0500
+++ snap-obs/data/nation/Makefile.am 2004-08-28 11:24:19.000000000 -0500
@@ -49,6 +49,7 @@
lithuanian.ruleset \
mongol.ruleset \
mordor.ruleset \
+ observer.ruleset \
persian.ruleset \
polish.ruleset \
portuguese.ruleset \
diff -Nur -Xcvs/diff_ignore snap/data/nation/observer.ruleset
snap-obs/data/nation/observer.ruleset
--- snap/data/nation/observer.ruleset 1969-12-31 18:00:00.000000000 -0600
+++ snap-obs/data/nation/observer.ruleset 2004-08-28 16:30:21.342413569
-0500
@@ -0,0 +1,20 @@
+[nation_observer]
+
+name=_("Observer")
+plural=_("?plural:Observers")
+leader="None"
+leader_sex="Male"
+flag="f.observer"
+flag_alt = "-"
+city_style = "Classical"
+
+init_techs=""
+init_buildings=""
+
+tech_goals = ""
+wonder = ""
+government = "Anarchy"
+
+cities = "Nowhere"
+
+; nothing more needed for observer
diff -Nur -Xcvs/diff_ignore snap/po/POTFILES.in snap-obs/po/POTFILES.in
--- snap/po/POTFILES.in 2004-07-17 10:33:49.000000000 -0500
+++ snap-obs/po/POTFILES.in 2004-08-28 11:24:03.000000000 -0500
@@ -270,6 +270,7 @@
data/nation/lithuanian.ruleset
data/nation/mongol.ruleset
data/nation/mordor.ruleset
+data/nation/observer.ruleset
data/nation/persian.ruleset
data/nation/polish.ruleset
data/nation/portuguese.ruleset
diff -Nur -Xcvs/diff_ignore snap/server/gamehand.c snap-obs/server/gamehand.c
--- snap/server/gamehand.c 2004-07-24 12:39:08.000000000 -0500
+++ snap-obs/server/gamehand.c 2004-08-28 13:49:42.045029132 -0500
@@ -183,6 +183,11 @@
struct start_position pos
= map.start_positions[start_pos[pplayer->player_no]];
+ /* don't give any units to observer */
+ if (pplayer->is_observer) {
+ continue;
+ }
+
/* Place the first unit. */
place_starting_unit(pos.x, pos.y, pplayer, game.start_units[0]);
} players_iterate_end;
@@ -193,6 +198,11 @@
struct start_position p
= map.start_positions[start_pos[pplayer->player_no]];
+ /* don't give any units to observer */
+ if (pplayer->is_observer) {
+ continue;
+ }
+
for (i = 1; i < strlen(game.start_units); i++) {
do {
x = p.x + myrand(2 * game.dispersion + 1) - game.dispersion;
diff -Nur -Xcvs/diff_ignore snap/server/ruleset.c snap-obs/server/ruleset.c
--- snap/server/ruleset.c 2004-08-28 10:38:55.000000000 -0500
+++ snap-obs/server/ruleset.c 2004-08-28 11:06:59.000000000 -0500
@@ -2052,7 +2052,7 @@
(void) section_file_lookup(file, "datafile.description"); /* unused */
sec = secfile_get_secnames_prefix(file, "nation", &game.nation_count);
- game.playable_nation_count = game.nation_count - 1;
+ game.playable_nation_count = game.nation_count - 2;
freelog(LOG_VERBOSE, "There are %d nations defined",
game.playable_nation_count);
if (game.playable_nation_count < 0) {
diff -Nur -Xcvs/diff_ignore snap/server/srv_main.c snap-obs/server/srv_main.c
--- snap/server/srv_main.c 2004-08-28 10:38:55.000000000 -0500
+++ snap-obs/server/srv_main.c 2004-08-28 15:07:05.399525586 -0500
@@ -193,7 +193,7 @@
**************************************************************************/
static bool is_game_over(void)
{
- int barbs = 0, alive = 0;
+ int barbs = 0, alive = 0, observers = 0;
bool all_allied;
struct player *victor = NULL;
@@ -205,17 +205,20 @@
return TRUE;
}
- /* count barbarians */
+ /* count barbarians and observers */
players_iterate(pplayer) {
if (is_barbarian(pplayer)) {
barbs++;
}
+ if (pplayer->is_observer) {
+ observers++;
+ }
} players_iterate_end;
/* the game does not quit if we are playing solo */
- if (game.nplayers == (barbs + 1)) {
+ if (game.nplayers == (observers + barbs + 1)) {
return FALSE;
- }
+ }
/* count the living */
players_iterate(pplayer) {
@@ -1271,7 +1274,15 @@
game.max_players);
}
- for(;game.nplayers < game.aifill;) {
+ /* we don't want aifill to count global observers... */
+ i = 0;
+ players_iterate(pplayer) {
+ if (pplayer->is_observer) {
+ i++;
+ }
+ } players_iterate_end;
+
+ for(;game.nplayers < game.aifill + i;) {
nation = select_random_nation(common_class);
assert(nation != NO_NATION_SELECTED);
mark_nation_as_used(nation);
@@ -1635,7 +1646,9 @@
*/
server_state = RUN_GAME_STATE;
players_iterate(pplayer) {
- if (pplayer->nation == NO_NATION_SELECTED && !pplayer->ai.control) {
+ if (pplayer->is_observer) {
+ pplayer->nation = OBSERVER_NATION;
+ } else if (pplayer->nation == NO_NATION_SELECTED && !pplayer->ai.control) {
send_select_nation(pplayer);
server_state = SELECT_RACES_STATE;
}
@@ -1726,6 +1739,7 @@
if(map.num_start_positions == 0) {
create_start_positions();
}
+
}
/* start positions are created, now we can do this safely */
@@ -1771,6 +1785,13 @@
if(game.is_new_game) {
init_new_game();
+
+ /* give global observers the entire map */
+ players_iterate(pplayer) {
+ if (pplayer->is_observer) {
+ map_know_and_see_all(pplayer);
+ }
+ } players_iterate_end;
}
send_game_state(&game.game_connections, CLIENT_GAME_RUNNING_STATE);
diff -Nur -Xcvs/diff_ignore snap/server/stdinhand.c snap-obs/server/stdinhand.c
--- snap/server/stdinhand.c 2004-08-28 10:38:55.000000000 -0500
+++ snap-obs/server/stdinhand.c 2004-08-28 17:33:29.714893901 -0500
@@ -51,6 +51,7 @@
#include "gamehand.h"
#include "gamelog.h"
#include "mapgen.h"
+#include "maphand.h"
#include "meta.h"
#include "plrhand.h"
#include "report.h"
@@ -1083,7 +1084,8 @@
typedef enum {
PNameOk,
PNameEmpty,
- PNameTooLong
+ PNameTooLong,
+ PNameIllegal
} PlayerNameStatus;
/**************************************************************************
@@ -1097,6 +1099,8 @@
return PNameEmpty;
} else if (len > MAX_LEN_NAME-1) {
return PNameTooLong;
+ } else if (strcmp(name, OBSERVER_NAME) == 0 ) {
+ return PNameIllegal;
}
return PNameOk;
@@ -2149,6 +2153,13 @@
return FALSE;
}
+ if (PNameStatus == PNameIllegal)
+ {
+ cmd_reply(CMD_CREATE, caller, C_SYNTAX, _("That name is not allowed."));
+ return FALSE;
+ }
+
+
if ((pplayer=find_player_by_name(arg))) {
cmd_reply(CMD_CREATE, caller, C_BOUNCE,
_("A player already exists by that name."));
@@ -3842,16 +3853,6 @@
goto end;
}
-#define NO_GLOBAL_OBS /* remove this construction when global obs is reality */
-
-#ifdef NO_GLOBAL_OBS
- if ((caller && ntokens == 0) || (!caller && ntokens == 1)) {
- cmd_reply(CMD_OBSERVE, caller, C_SYNTAX,
- _("Usage: observe [connection-name [player-name]]"));
- goto end;
- }
-#endif
-
/* match connection if we're console, match a player if we're not */
if (ntokens == 1) {
if (!caller && !(pconn = find_conn_by_user_prefix(arg[0], &result))) {
@@ -3881,9 +3882,47 @@
pconn = caller;
}
-#ifndef NO_GLOBAL_OBS
- /* global observing needs some code here! */
-#endif
+ /* if we have no pplayer, it means that we want to be a global observer */
+ if (!pplayer) {
+ /* check if a global observer has already been created */
+ players_iterate(aplayer) {
+ if (aplayer->is_observer) {
+ pplayer = aplayer;
+ break;
+ }
+ } players_iterate_end;
+
+ /* we need to create a new player */
+ if (!pplayer) {
+ if (game.nplayers >= MAX_NUM_PLAYERS) {
+ notify_player(NULL, _("Game: A global observer cannot be created: too "
+ "many regular players."));
+ goto end;
+ }
+
+ pplayer = &game.players[game.nplayers];
+ server_player_init(pplayer, TRUE);
+ sz_strlcpy(pplayer->name, OBSERVER_NAME);
+ sz_strlcpy(pplayer->username, ANON_USER_NAME);
+
+ pplayer->is_connected = FALSE;
+ pplayer->is_observer = TRUE;
+ pplayer->capital = TRUE;
+ pplayer->turn_done = TRUE;
+ pplayer->embassy = 0; /* no embassys */
+ pplayer->is_alive = FALSE;
+ pplayer->was_created = FALSE;
+
+ if (server_state == RUN_GAME_STATE) {
+ pplayer->nation = OBSERVER_NATION;
+ init_tech(pplayer, 0);
+ map_know_and_see_all(pplayer);
+ }
+
+ game.nplayers++;
+ notify_player(NULL, _("Game: A global observer has been created"));
+ }
+ }
/******** PART II: do the observing ********/
@@ -4032,6 +4071,13 @@
goto end;
}
+ /* you may not take over a global observer */
+ if (pplayer->is_observer) {
+ cmd_reply(CMD_TAKE, caller, C_FAIL, _("%s cannot be taken."),
+ pplayer->name);
+ goto end;
+ }
+
/* taking your own player makes no sense. */
if (pconn->player == pplayer && !pconn->observer) {
cmd_reply(CMD_TAKE, caller, C_FAIL, _("%s already controls %s"),
@@ -4131,7 +4177,7 @@
struct player *pplayer = NULL;
bool is_newgame = (server_state == PRE_GAME_STATE ||
server_state == SELECT_RACES_STATE) && game.is_new_game;
- bool res = FALSE;
+ bool one_obs_among_many = FALSE, res = FALSE;
sz_strlcpy(buf, str);
ntokens = get_tokens(buf, arg, 1, TOKEN_DELIMITERS);
@@ -4171,6 +4217,18 @@
goto end;
}
+ /* a special case for global observers: we don't want to remove the
+ * observer player in pregame if someone else is also observing it */
+ i = 0;
+ conn_list_iterate(pplayer->connections, aconn) {
+ if (aconn->observer) {
+ i++;
+ }
+ } conn_list_iterate_end;
+ if (i > 1 && pconn->observer) {
+ one_obs_among_many = TRUE;
+ }
+
res = TRUE;
if (check) {
goto end;
@@ -4187,8 +4245,10 @@
_("%s detaching from %s"), pconn->username, pplayer->name);
/* only remove the player if the game is new and in pregame,
- * the player wasn't /created, and no one is controlling it */
- if (!pplayer->is_connected && !pplayer->was_created && is_newgame) {
+ * the player wasn't /created, and no one is controlling it
+ * and we were observing but no one else was... */
+ if (!pplayer->is_connected && !pplayer->was_created && is_newgame
+ && !one_obs_among_many) {
/* detach any observers */
conn_list_iterate(pplayer->connections, aconn) {
if (aconn->observer) {
@@ -4200,6 +4260,7 @@
/* actually do the removal */
game_remove_player(pplayer);
game_renumber_players(pplayer->player_no);
+ player_init(&game.players[game.nplayers]);
}
if (!pplayer->is_connected) {
- [Freeciv-Dev] Re: (PR#7241) Wish List: observer mode,
Mike Kaufman <=
|
|