glob2-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[glob2-devel] patch with improvements: brushes (6), fix AI cheating (2),


From: Joe Wells
Subject: [glob2-devel] patch with improvements: brushes (6), fix AI cheating (2), explorers (4), other GUI (7)
Date: Mon, 30 Apr 2007 02:09:15 +0100
User-agent: Gnus/5.11 (Gnus v5.11) Emacs/22.0.50 (gnu/linux)

Dear Globulation 2 gurus,

Attached is a patch to the source code of glob2 version 0.8.23 that
has a number of improvements, described below.  Also attached are some
image files that go with one of the changes.

Please don't worry about the indentation and line breaks.  That can be
easily changed.  Please just look at the coding ideas for now.

I'm sorry that I'm putting these changes all in one message.  If I
delayed until I had time to describe them all separately, I would
probably never have time to send them, so I think it is better that I
show them to you now.

The coding of some of the changes is not perfect.  Generally, when
this has happened, it is because I was following the style of code
already in glob2.  (An example is the way the code everywhere knows
that the size of the myUnits array is 1024.  ☹)

If you don't like how I have done things, I _might_ have time to redo
some of them differently.  Just ask.

I hope you find this contribution useful.

Joe

----------------------------------------------------------------------
The changes are as follows:

1. Changes in the effect of area brushes:

   A. This patch changes the shapes of the 3rd and 4th brushes to:

        X               X
         X     and     X
          X           X

      I never used the previous shapes of the 3rd and 4th brushes, but
      I now use the new shapes all the time for farming.

      (The .png images used for the button to select these shapes have
      not been updated and still show the old shapes.  It would be
      nice if these were calculated at game startup instead of being
      static .png files.)

   B. This patch changes things so that when drawing areas with a
      brush of size 1 by 1 (there is only one such brush), if an
      attempt is made to use the brush which would have no effect, we
      first toggle the state of whether we are adding or removing the
      area, so the use of the brush will have an effect.  This allows
      quickly repairing errors without having to explicitly change the
      mode by hand.  We don't do this when dragging, so only explicit
      mouse clicks can change the mode.

   C. This patch fixes bugs in drawing areas while dragging.  It is
      now far more likely that if you quickly draw a path with the
      mouse that all of the map cells the mouse goes through will be
      correctly handled.  Two separate changes needed to be made.
      First, it was necessary to stop discarding as many mouse motion
      events (but only when dragging).  Second, it was necessary to
      change to using the mouse position and button state at the time
      of each event rather than using SDL_GetMouseState (which can
      return the mouse position and button state after many events
      that have not yet been processed).

      (If SDL doesn't supply enough mouse motion events, then it is
      still possible to skip over some cells, even after this patch.
      This potential problem seems not to happen in practice.)

2. Changes to the visual appearance of area brushes:

   A. This patch makes the area brushes show the exact cells that will
      be turned on or off, instead of just a square or circle.  (This
      change is needed by the new brush shapes.)

   B. This patch draws the area brush in a color (red, blue, or
      yellow) corresponding to the kind of area (forbidden, guard, or
      clearing) that is being added or removed.  The actual colors
      that are used were obtained by inspecting the .png files for the
      area animations.

   C. The area brushes were dimmer to indicate area removal.  However,
      the brushes for removal were still bright enough that it was
      hard to notice the difference.  (I never realized there was a
      difference until I saw the code.)  This patch makes them even
      more dim, so that the difference is more likely to be noticed.

3. Changes to AI behavior:

   A. There was code in AIEcho.cpp that allows AIs to cheat by telling
      them where each player's starting buildings are located.  This
      allows AIs to launch attacks with war flags against enemies they
      have never even seen.  This patch disables this “feature”.

   B. This patch adds code to ensure that Nicowar does not commit to
      defeating a particular enemy until it has seen at least one
      building of that enemy.  (This is a necessary adjustment to the
      removal of the feature that the AIs know the location of all
      other players' starting buildings.)

4. Changes to explorer behavior:

   A. This patch greatly increases the likelihood that explorers will
      explore unknown areas on large maps.  Explorers now effectively
      explore 128 by 128 and 256 by 256 maps.  (This has not been
      tested on 512 by 512 maps, due to the memory use bug since glob2
      version 0.8.22 (bug #19601).)

   B. This patch makes explorers prefer to try to heal immediately
      after feeding and to feed immediately after healing.  This is
      necessary for explorers to have enough range to explore large
      maps.

   C. This patch works around the problem where exploredArea is not
      included in saved games by assuming on game reloading that all
      discovered cells are explored.  (This avoids all explorers going
      completely haywire when saving and reloading a game.)

   D. This patch improves decisions about whether a direction is
      diagonal or not which affect explorer behavior.

4. Other changes to visual displays:

   A. The units working for a building are always shown with white
      circles while the building is selected, instead of just when the
      mouse button is held down.

   B. This patch reduces the amount of dimness from the fog of war,
      because the old amount of dimness made it painful to view the
      screen.  The .png files used for the borders of the fog of war
      have been correspondingly adjusted.

   C. This patch reduces the amount of screen dimming due to pausing
      the game.

5. Other changes to user interface controls:

   A. This patch adds new keyboard commands for selecting all of the
      building construction tools, the flag tools, and the area tools,
      and for setting the area adding/removing mode, and for setting
      the area brush.  These commands can be bound to any of the keys
      from “a” to “z”.  Also, there are 3 prefix commands which group
      together all of the building tools, the flag tools, and the area
      tools.  For example, if you bind the prefix command for
      buildings to “b”, then “b” followed by “i” selects the “inn”
      tool.  You can also bind “i” directly to the command for
      selecting the “inn” tool if you want.  The default binding of
      the prefix command for area tools is “a”, for building tools is
      “b”, and for flag tools is “f”.  (The default for the team
      marking command (which shows the team numbers for each globule)
      has been moved from “a” to “h”.)

      (The language translations of the new commands have not yet been
      added (not even English).)

   B. This patch enables holding the Control key while pressing the
      arrow keys to move the viewport by half-screens instead of by
      single cells.  At the same time, some bugs are solved where
      window manager controls involving arrow keys and other modifiers
      could sometimes accidentally be interpreted by glob2.

   C. This patch enables using the Tab key to cycle through all of
      your globules of a given kind (worker, explorer, or warrior).
      (This was vital for debugging explorer behavior.)

   D. This patch allows the user to require the Control key to be held
      down before the scrollwheel changes the number of requested
      workers.  This solves a problem (bug #19600) where the number of
      workers keeps getting accidentally messed up.  (With this patch,
      the user requests this by setting the GLOB2_NO_RAW_MOUSEWHEEL
      environment variable; this should be done with a user option
      instead.)

6. Various new methods are added to support the changes
   (BrushTool::setFigure, BrushTool::setType,
   GameGUI::isBuildingEnabled, GameGUI::isFlagEnabled).

diff -ru ../../glob-virgin/glob2-0.8.23/src/AIEcho.cpp ./AIEcho.cpp
--- ../../glob-virgin/glob2-0.8.23/src/AIEcho.cpp       2007-04-15 
02:02:38.000000000 +0100
+++ ./AIEcho.cpp        2007-04-22 20:01:31.000000000 +0100
@@ -4217,7 +4217,10 @@
                Building* 
b=echo->player->game->teams[team]->myBuildings[current_index];
                if(b)
                {
-                       if( (b->seenByMask&echo->player->team->me || 
echo->get_starting_buildings().find(b->gid)!=echo->get_starting_buildings().end())
 &&
+                       if( (b->seenByMask&echo->player->team->me
+                             // Don't allow AIs to cheat!!!!!!
+                             // || 
echo->get_starting_buildings().find(b->gid)!=echo->get_starting_buildings().end()
+                             ) &&
                                (building_type==-1 || 
b->type->shortTypeNum==building_type) &&
                                (level==-1 || b->type->level==(level-1)))
                        {
diff -ru ../../glob-virgin/glob2-0.8.23/src/AINicowar.cpp ./AINicowar.cpp
--- ../../glob-virgin/glob2-0.8.23/src/AINicowar.cpp    2007-04-15 
00:36:21.000000000 +0100
+++ ./AINicowar.cpp     2007-04-22 21:15:55.000000000 +0100
@@ -1200,7 +1200,17 @@
                {
                        if(echo.player->game->teams[*i]->isAlive)
                        {
+                          enemy_building_iterator ebi(echo, *i, -1, -1, 
indeterminate);
+                          /* Make sure we know of at least one
+                             building before committing to a
+                             particular enemy.  It used to be that we
+                             did not (normally) need to test this,
+                             because all starting buildings were
+                             known.  But that was cheating and has
+                             been fixed. */
+                          if (ebi != enemy_building_iterator()) {
                                available_targets.push_back(*i);
+                          }
                        }
                }
                if(available_targets.size()==0)
diff -ru ../../glob-virgin/glob2-0.8.23/src/Brush.cpp ./Brush.cpp
--- ../../glob-virgin/glob2-0.8.23/src/Brush.cpp        2007-04-17 
22:48:06.000000000 +0100
+++ ./Brush.cpp 2007-04-29 19:34:56.000000000 +0100
@@ -63,8 +63,35 @@
 
 void BrushTool::drawBrush(int x, int y, bool onlines)
 {
+  /* We use 2/3 intensity to indicate removing areas.  This was
+     formerly 78% intensity, which was bright enough that it was hard
+     to notice any difference, so the brightness has been lowered. */
+  int i = ((mode == MODE_ADD) ? 255 : 170);
+  drawBrush(x, y, Color(i,i,i), onlines);
+}
+
+void BrushTool::drawBrush(int x, int y, GAGCore::Color c, bool onlines)
+{
+       /* It violates good abstraction practices that Brush.cpp knows
+          this much about the visual layout of the GUI. */
        x = ((x+(onlines ? 16 : 0)) & ~0x1f) + (!onlines ? 16 : 0);
        y = ((y+(onlines ? 16 : 0)) & ~0x1f) + (!onlines ? 16 : 0);
+        int w = getBrushWidth(figure);
+        int h = getBrushHeight(figure);
+        /* Move x and y from center of focus point to upper left of
+           brush shape. */ 
+        const int cell_size = 32; // This file should not know this value!!!
+        x -= ((cell_size * getBrushDimX(figure)) + (cell_size / 2));
+        y -= ((cell_size * getBrushDimY(figure)) + (cell_size / 2));
+        const int inset = 2;
+        for (int cx = 0; cx < w; cx++) {
+          for (int cy = 0; cy < h; cy++) {
+            if (getBrushValue(figure, cx, cy)) {
+              globalContainer->gfx->drawRect(x + (cell_size * cx) + inset, y + 
(cell_size * cy) + inset, cell_size - inset, cell_size - inset, c); }}}
+        /* The following code is the old way of doing things.  It is
+           kept in case anyone wants to restore it, which might be
+           useful for some of the brush shapes. */
+        /*
        if (figure < 4)
        {
                int r = (getBrushWidth(figure) + getBrushHeight(figure)) * 8;
@@ -82,20 +109,27 @@
                else
                        globalContainer->gfx->drawRect(x-w, y-h, 2*w, 2*h, 200, 
200, 200);
        }
+        */
 }
 
 #define BRUSH_COUNT 8
 
+void BrushTool::setFigure(unsigned f)
+{
+  assert (figure < BRUSH_COUNT);
+  figure = f;
+}
+
 int BrushTool::getBrushWidth(unsigned figure)
 {
-       int dim[BRUSH_COUNT] = { 1, 3, 5, 7, 5, 5, 3, 5};
+       int dim[BRUSH_COUNT] = { 1, 3, 3, 3, 5, 5, 3, 5};
        assert(figure < BRUSH_COUNT);
        return dim[figure];
 }
 
 int BrushTool::getBrushHeight(unsigned figure)
 {
-       int dim[BRUSH_COUNT] = { 1, 3, 5, 7, 5, 5, 3, 5};
+       int dim[BRUSH_COUNT] = { 1, 3, 3, 3, 5, 5, 3, 5};
        assert(figure < BRUSH_COUNT);
        return dim[figure];
 }
@@ -117,18 +151,12 @@
        int brush1[] = {        0, 1, 0,
                                                1, 1, 1,
                                                0, 1, 0 };
-       int brush2[] = {        0, 1, 1, 1, 0,
-                                               1, 1, 1, 1, 1,
-                                               1, 1, 1, 1, 1,
-                                               1, 1, 1, 1, 1,
-                                               0, 1, 1, 1, 0 };
-       int brush3[] = {        0, 0, 1, 1, 1, 0, 0,
-                                               0, 1, 1, 1, 1, 1, 0,
-                                               1, 1, 1, 1, 1, 1, 1,
-                                               1, 1, 1, 1, 1, 1, 1,
-                                               1, 1, 1, 1, 1, 1, 1,
-                                               0, 1, 1, 1, 1, 1, 0,
-                                               0, 0, 1, 1, 1, 0, 0 };
+       int brush2[] = {        1, 0, 0,
+                               0, 1, 0,
+                               0, 0, 1, };
+       int brush3[] = {        0, 0, 1,
+                               0, 1, 0,
+                               1, 0, 0, };
        int brush4[] = {        1, 0, 1, 0, 1,
                                                0, 1, 0, 1, 0,
                                                1, 0, 1, 0, 1,
diff -ru ../../glob-virgin/glob2-0.8.23/src/Brush.h ./Brush.h
--- ../../glob-virgin/glob2-0.8.23/src/Brush.h  2007-04-17 22:48:06.000000000 
+0100
+++ ./Brush.h   2007-04-29 05:08:36.000000000 +0100
@@ -21,6 +21,7 @@
 #define __BRUSH_H
 
 #include <vector>
+#include "GraphicContext.h" // just to get Color, really this should only be 
in GameGUI
 
 //! A click of the brush tool to the map
 struct BrushApplication
@@ -59,10 +60,15 @@
 
        //! Draw the actual brush (not the brush tool)
        void drawBrush(int x, int y, bool onlines=false);
+       void drawBrush(int x, int y, GAGCore::Color c, bool onlines=false);
        //! Return the mode of the brush
        unsigned getType(void) { return static_cast<unsigned>(mode); }
+       //! Set the mode of the brush
+       void setType(Mode m) { mode = m; }
        //! Return the id of the actual figure
        unsigned getFigure(void) { return figure; }
+       //! Set the id of the actual figure
+       void setFigure(unsigned f);
        
        //! Return the full width of a brush
        static int getBrushWidth(unsigned figure);
diff -ru ../../glob-virgin/glob2-0.8.23/src/Game.cpp ./Game.cpp
--- ../../glob-virgin/glob2-0.8.23/src/Game.cpp 2007-04-17 22:48:06.000000000 
+0100
+++ ./Game.cpp  2007-04-19 21:05:44.000000000 +0100
@@ -2385,7 +2385,7 @@
                                        unsigned shadeValue = i0 + (i1<<1) + 
(i2<<2) + (i3<<3);
                                        
                                        if (shadeValue==15)
-                                               
globalContainer->gfx->drawFilledRect((x<<5)+16, (y<<5)+16, 32, 32, 0, 0, 0, 
127);
+                                               
globalContainer->gfx->drawFilledRect((x<<5)+16, (y<<5)+16, 32, 32, 0, 0, 0, 40);
                                        else if (shadeValue)
                                                
globalContainer->gfx->drawSprite((x<<5)+16, (y<<5)+16, 
globalContainer->terrainShader, shadeValue);
                                }
diff -ru ../../glob-virgin/glob2-0.8.23/src/GameGUI.cpp ./GameGUI.cpp
--- ../../glob-virgin/glob2-0.8.23/src/GameGUI.cpp      2007-04-17 
22:48:06.000000000 +0100
+++ ./GameGUI.cpp       2007-04-30 01:39:23.000000000 +0100
@@ -175,6 +175,8 @@
 
 }
 
+bool noRawMousewheel = false;
+
 void GameGUI::init()
 {
        notmenu = false;
@@ -199,7 +201,7 @@
        highlightSelection = 0.0f;
        miniMapPushed=false;
        putMark=false;
-       showUnitWorkingToBuilding=false;
+       showUnitWorkingToBuilding=true;
        chatMask=0xFFFFFFFF;
        hasSpaceBeenClicked=false;
        swallowSpaceKey=false;
@@ -259,6 +261,9 @@
        missionName="";
        
        initUnitCount();
+
+        if (getenv ("GLOB2_NO_RAW_MOUSEWHEEL")) {
+          noRawMousewheel = true; }
 }
 
 void GameGUI::adjustLocalTeam()
@@ -323,7 +328,7 @@
        }
 }
 
-void GameGUI::brushStep(int mx, int my)
+void GameGUI::brushStep(bool maybeToggleMode, int mx, int my)
 {
        // if we have an area over 32x32, which mean over 128 bytes, send it
        if (brushAccumulator.getAreaSurface() > 32*32)
@@ -334,6 +339,26 @@
        int mapX, mapY;
        game.map.displayToMapCaseAligned(mx, my, &mapX, &mapY,  viewportX, 
viewportY);
        int fig = brush.getFigure();
+        /* We treat any brush of size 1 by 1 specially.  If an attempt
+           is made to use the brush which would have no effect, we
+           first toggle the state of whether we are adding or removing
+           the area, so the use of the brush will have an effect.
+           This allows quickly repairing errors without having to
+           explicitly change the mode by hand.  We don't do this when
+           dragging, so only explicit mouse clicks can change the
+           mode. */
+        if (maybeToggleMode && (brush.getBrushHeight(fig) == 1) && 
(brush.getBrushWidth(fig) == 1)) {
+          int isAlreadyOn =
+            ((brushType == FORBIDDEN_BRUSH) && game.map.isForbiddenLocal(mapX, 
mapY))
+            || ((brushType == GUARD_AREA_BRUSH) && 
game.map.isGuardAreaLocal(mapX, mapY))
+            || ((brushType == CLEAR_AREA_BRUSH) && 
game.map.isClearAreaLocal(mapX, mapY));
+          unsigned mode = brush.getType();
+          if (((mode == BrushTool::MODE_ADD) && isAlreadyOn)
+              || ((mode == BrushTool::MODE_DEL) && !isAlreadyOn)) {
+            sendBrushOrders();
+            brush.setType((mode == BrushTool::MODE_ADD) ? BrushTool::MODE_DEL 
: BrushTool::MODE_ADD); 
+            brushStep(false, mx,my); // restart action after changing mode; 
set maybeToggleMode to false to guarantee no further recursion
+            return; }}
        brushAccumulator.applyBrush(&game.map, BrushApplication(mapX, mapY, 
fig));
        // we get coordinates
        int startX = mapX-BrushTool::getBrushDimX(fig);
@@ -394,10 +419,18 @@
        }
 }
 
-void GameGUI::dragStep(void)
+void GameGUI::dragStep(int mx, int my, int button)
 {
-       int mx, my;
-       Uint8 button = SDL_GetMouseState(&mx, &my);
+        /* We used to use SDL_GetMouseState, like the following
+           commented-out code, but that was buggy and prevented
+           dragging from correctly going through intermediate cells.
+           It is vital to use the mouse position and button status as
+           it was at the time in the middle of the event stream, not
+           as it is now.  So instead we make sure the correct data is
+           passed to us as a parameter. */
+       // int mx, my;
+       // Uint8 button = SDL_GetMouseState(&mx, &my);
+        // fprintf (stderr, "enter dragStep: button: %d, mx: %d, 
selectionMode: %d\n", button, mx, selectionMode);
        if ((button&SDL_BUTTON(1)) && (mx<globalContainer->gfx->getW()-128))
        {
                // Update flag
@@ -410,24 +443,81 @@
                // Update brush
                else if (selectionMode==BRUSH_SELECTION)
                {
-                       brushStep(mx, my);
+                       brushStep(false, mx, my);
                }
        }
+        // fprintf (stderr, "exit dragStep\n");
 }
 
+/* We need to keep track of the last recorded mouse position for use
+   in drag steps.  We can't simply use SDL_GetMouseState to get this
+   information, because we need the information as it was in the
+   middle of the event stream.  (There may be many later events we
+   have not yet processed.) */
+int lastMouseX = 0, lastMouseY = 0; // can't make these Uint16 because of 
SDL_GetMouseState
+Uint16 lastMouseButtonState = 0;
+
 void GameGUI::step(void)
 {
        SDL_Event event, mouseMotionEvent, windowEvent;
        bool wasMouseMotion=false;
        bool wasWindowEvent=false;
+        int oldMouseMapX = -1, oldMouseMapY = -1; // hopefully the values here 
will never matter
        // we get all pending events but for mousemotion we only keep the last 
one
        while (SDL_PollEvent(&event))
        {
                if (event.type==SDL_MOUSEMOTION)
                {
+                        lastMouseX = event.motion.x;
+                        lastMouseY = event.motion.y;
+                        lastMouseButtonState = event.motion.state;
+                        int mouseMapX, mouseMapY;
+                        bool onViewport = (lastMouseX < 
globalContainer->gfx->getW()-128);
+                        /* We keep track for each mouse motion event
+                           of which map cell it corresponds to.  When
+                           dragging, we will use this to make sure we
+                           process at least one event per map cell,
+                           and only discard multiple events when they
+                           are for the same map cell.  This is
+                           necessary to make dragging work correctly
+                           when drawing areas with the brush. */
+                        if (onViewport) {
+                          game.map.cursorToBuildingPos (lastMouseX, 
lastMouseY, 1, 1, &mouseMapX, &mouseMapY, viewportX, viewportY); }
+                        else {
+                          /* We interpret all locations outside the
+                             viewport as being equivalent, and
+                             distinct from any map location. */
+                          mouseMapX = -1;
+                          mouseMapY = -1; }
+                        // fprintf (stderr, "mouse motion: 
(lastMouseX,lastMouseY): (%d,%d), (mouseMapX,mouseMapY): (%d,%d), 
(oldMouseMapX,oldMouseMapY): (%d,%d)\n", lastMouseX, lastMouseY, mouseMapX, 
mouseMapY, oldMouseMapX, oldMouseMapY);
+                        /* Make sure dragging does not skip over map cells by
+                           processing the old stored event rather than throwing
+                           it away. */
+                        if (wasMouseMotion
+                            && (lastMouseButtonState & SDL_BUTTON(1)) // are 
we dragging? (should not be hard-coding this condition but should be abstract 
somehow)
+                            && ((mouseMapX != oldMouseMapX)
+                                || (mouseMapY != oldMouseMapY))) {
+                          // fprintf (stderr, "processing old event instead of 
discarding it\n");
+                          processEvent(&mouseMotionEvent); }
+                        oldMouseMapX = mouseMapX;
+                        oldMouseMapY = mouseMapY;
                        mouseMotionEvent=event;
                        wasMouseMotion=true;
                }
+                else if ((event.type == SDL_MOUSEBUTTONDOWN) || (event.type == 
SDL_MOUSEBUTTONUP)) {
+                  lastMouseButtonState = SDL_GetMouseState (&lastMouseX, 
&lastMouseY);
+                  /* We ignore what SDL_GetMouseState does to
+                     lastMouseX and lastMouseY, because that may
+                     reflect many subsequent events that we have not
+                     yet processed.  Technically, we shouldn't use
+                     SDL_GetMouseState at all but should calculate the
+                     button state by keeping track of what has
+                     happened.  However, I haven't had the programming
+                     energy to do this, so I am cheating in the line
+                     above. */
+                  lastMouseX = event.button.x;
+                  lastMouseY = event.button.y;
+                  processEvent (&event); }
                else if (event.type==SDL_ACTIVEEVENT)
                {
                        windowEvent=event;
@@ -454,7 +544,7 @@
        viewportY&=game.map.getMaskH();
 
        if ((viewportX!=oldViewportX) || (viewportY!=oldViewportY))
-               dragStep();
+               dragStep(lastMouseX, lastMouseY, lastMouseButtonState);
 
        assert(localTeam);
        if (localTeam->wasEvent(Team::UNIT_UNDER_ATTACK_EVENT))
@@ -994,9 +1084,11 @@
                                        if 
((selBuild->owner->teamNumber==localTeamNo) &&
                                                
(selBuild->buildingState==Building::ALIVE))
                                        {
+                                                /* fprintf (stderr, 
"s=SDL_GetModState(): %d, S=KMOD_SHIFT: %d, C=KMOD_CTRL: %d\n",
+                                                         SDL_GetModState(), 
KMOD_SHIFT, KMOD_CTRL); */
                                                if 
((selBuild->type->maxUnitWorking) &&
                                                        
(selBuild->maxUnitWorkingLocal<MAX_UNIT_WORKING)&&
-                                                       
!(SDL_GetModState()&KMOD_SHIFT))
+                                                        (noRawMousewheel ? 
(SDL_GetModState() & KMOD_CTRL) : !(SDL_GetModState()&KMOD_SHIFT)))
                                                {
                                                        int 
nbReq=(selBuild->maxUnitWorkingLocal+=1);
                                                        
orderQueue.push_back(new OrderModifyBuilding(selBuild->gid, nbReq));
@@ -1023,7 +1115,7 @@
                                        {
                                                if 
((selBuild->type->maxUnitWorking) &&
                                                        
(selBuild->maxUnitWorkingLocal>0)&&
-                                                       
!(SDL_GetModState()&KMOD_SHIFT))
+                                                        (noRawMousewheel ? 
(SDL_GetModState() & KMOD_CTRL) : !(SDL_GetModState()&KMOD_SHIFT)))
                                                {
                                                        int 
nbReq=(selBuild->maxUnitWorkingLocal-=1);
                                                        
orderQueue.push_back(new OrderModifyBuilding(selBuild->gid, nbReq));
@@ -1060,7 +1152,7 @@
                        miniMapPushed=false;
                        selectionPushed=false;
                        panPushed=false;
-                       showUnitWorkingToBuilding=false;
+                       // showUnitWorkingToBuilding=false;
                }
        }
 
@@ -1159,6 +1251,14 @@
        }
 }
 
+enum TwoKeyMode
+{
+  TWOKEY_NONE = 0,
+  TWOKEY_BUILDING = 1,
+  TWOKEY_FLAG = 2,
+  TWOKEY_AREA = 3,
+} twoKeyMode = TWOKEY_NONE;
+
 void GameGUI::handleKey(SDLKey key, bool pressed, bool shift, bool ctrl)
 {
        int modifier;
@@ -1171,6 +1271,104 @@
        if (typingInputScreen == NULL)
        {
                std::string action="";
+                // fprintf (stderr, "twoKeyMode: %d, key: %d\n", twoKeyMode, 
key);
+                if (twoKeyMode != TWOKEY_NONE) {
+                  if (pressed) {
+                    switch (twoKeyMode) {
+                    case TWOKEY_BUILDING:
+                      switch (key) {
+                      case SDLK_a: /* swArm */
+                        action = "select make swarm tool";
+                        break;
+                      case SDLK_i: /* Inn */
+                        action = "select make inn tool";
+                        break;
+                      case SDLK_h: /* Hospital */
+                        action = "select make hospital tool";
+                        break;
+                      case SDLK_r: /* Racetrack */
+                        action = "select make racetrack tool";
+                        break;
+                      case SDLK_p: /* swimming Pool */
+                        action = "select make swimming pool tool";
+                        break;
+                      case SDLK_b: /* Barracks */
+                        action = "select make barracks tool";
+                        break;
+                      case SDLK_s: /* School */
+                        action = "select make school tool";
+                        break;
+                      case SDLK_d: /* Defense tower */
+                        action = "select make defense tower tool";
+                        break;
+                      case SDLK_w: /* stone Wall */
+                        action = "select make stone wall tool";
+                        break;
+                      case SDLK_m: /* Market */
+                        action = "select make market tool";
+                        break; }
+                      break; 
+                    case TWOKEY_FLAG:
+                      switch (key) {
+                      case SDLK_e: /* Exploration */
+                        action = "select make exploration flag tool";
+                        break;
+                      case SDLK_w: /* War */
+                        action = "select make war flag tool";
+                        break;
+                      case SDLK_c: /* Clearing */
+                        action = "select make clearing flag tool";
+                        break; }
+                      break; 
+                    case TWOKEY_AREA:
+                      switch (key) {
+                      case SDLK_f: /* Forbidden */
+                        action = "select forbidden area tool";
+                        break;
+                      case SDLK_g: /* Guard */
+                        action = "select guard area tool";
+                        break;
+                      case SDLK_c: /* Clearing */
+                        action = "select clearing area tool";
+                        break;
+                      case SDLK_a: /* Add */
+                        action = "switch to adding areas";
+                        break;
+                      case SDLK_d: /* Delete */
+                        action = "switch to deleting areas";
+                        break;
+                      case SDLK_1:
+                        action = "switch to area brush 1";
+                        break;
+                      case SDLK_2:
+                        action = "switch to area brush 2";
+                        break;
+                      case SDLK_3:
+                        action = "switch to area brush 3";
+                        break;
+                      case SDLK_4:
+                        action = "switch to area brush 4";
+                        break;
+                      case SDLK_5:
+                        action = "switch to area brush 5";
+                        break;
+                      case SDLK_6:
+                        action = "switch to area brush 6";
+                        break;
+                      case SDLK_7:
+                        action = "switch to area brush 7";
+                        break;
+                      case SDLK_8:
+                        action = "switch to area brush 8";
+                        break; }
+                      break; }
+                    key = SDLK_UNKNOWN;
+                    twoKeyMode = TWOKEY_NONE; }
+                  else {
+                    /* this case happens when the initial prefix key is 
released */
+                  }}
+                // fprintf (stderr, "action: [%s]\n", action.c_str());
+                
                switch (key)
                {
                        case SDLK_ESCAPE:
@@ -1464,6 +1662,130 @@
                        if (pressed)
                                orderQueue.push_back(new 
PauseGameOrder(!gamePaused));
                }
+                else if ((action == "prefix key select area tool") && pressed) 
{
+                  twoKeyMode = TWOKEY_AREA; }
+                else if ((action == "prefix key select building tool") && 
pressed) {
+                  twoKeyMode = TWOKEY_BUILDING; }
+                else if ((action == "prefix key select flag tool") && pressed) 
{
+                  twoKeyMode = TWOKEY_FLAG; }
+                else if (pressed
+                         && ((action == "select make swarm tool")
+                             || (action == "select make inn tool")
+                             || (action == "select make hospital tool")
+                             || (action == "select make racetrack tool")
+                             || (action == "select make swimming pool tool")
+                             || (action == "select make barracks tool")
+                             || (action == "select make school tool")
+                             || (action == "select make defense tower tool")
+                             || (action == "select make stone wall tool")
+                             || (action == "select make market tool")
+                             || (action == "select make exploration flag tool")
+                             || (action == "select make war flag tool")
+                             || (action == "select make clearing flag tool")
+                             || (action == "select forbidden area tool")
+                             || (action == "select guard area tool")
+                             || (action == "select clearing area tool")
+                             || (action == "switch to adding areas")
+                             || (action == "switch to deleting areas")
+                             || (action == "switch to area brush 1")
+                             || (action == "switch to area brush 2")
+                             || (action == "switch to area brush 3")
+                             || (action == "switch to area brush 4")
+                             || (action == "switch to area brush 5")
+                             || (action == "switch to area brush 6")
+                             || (action == "switch to area brush 7")
+                             || (action == "switch to area brush 8"))) {
+                  clearSelection();
+                  char * buildingType = NULL;
+                  BrushType tmpBrushType;
+                  bool isArea = false;
+                  BrushTool::Mode tmpBrushMode = BrushTool::MODE_NONE;
+                  int brushFigure;
+                  bool isBrush = false;
+                  char * flagType = NULL;
+                  if (action == "select make swarm tool") {
+                    buildingType = "swarm"; }
+                  else if (action == "select make inn tool") {
+                    buildingType = "inn"; }
+                  else if (action == "select make hospital tool") {
+                    buildingType = "hospital"; }
+                  else if (action == "select make racetrack tool") {
+                    buildingType = "racetrack"; }
+                  else if (action == "select make swimming pool tool") {
+                    buildingType = "swimmingpool"; }
+                  else if (action == "select make barracks tool") {
+                    buildingType = "barracks"; }
+                  else if (action == "select make school tool") {
+                    buildingType = "school"; }
+                  else if (action == "select make defense tower tool") {
+                    buildingType = "defencetower"; }
+                  else if (action == "select make stone wall tool") {
+                    buildingType = "stonewall"; }
+                  else if (action == "select make market tool") {
+                    buildingType = "market"; }
+                  else if (action == "select make exploration flag tool") {
+                    flagType = "explorationflag"; }
+                  else if (action == "select make war flag tool") {
+                    flagType = "warflag"; }
+                  else if (action == "select make clearing flag tool") {
+                    flagType = "clearingflag"; }
+                  else if (action == "select forbidden area tool") {
+                    isArea = true;
+                    tmpBrushType = FORBIDDEN_BRUSH; }
+                  else if (action == "select guard area tool") {
+                    isArea = true;
+                    tmpBrushType = GUARD_AREA_BRUSH; }
+                  else if (action == "select clearing area tool") {
+                    isArea = true;
+                    tmpBrushType = CLEAR_AREA_BRUSH; }
+                  else if (action == "switch to adding areas") {
+                    tmpBrushMode = BrushTool::MODE_ADD; }
+                  else if (action == "switch to deleting areas") {
+                    tmpBrushMode = BrushTool::MODE_DEL; }
+                  else if (action == "switch to area brush 1") {
+                    brushFigure = 0;
+                    isBrush = true; }
+                  else if (action == "switch to area brush 2") {
+                    brushFigure = 1;
+                    isBrush = true; }
+                  else if (action == "switch to area brush 3") {
+                    brushFigure = 2;
+                    isBrush = true; }
+                  else if (action == "switch to area brush 4") {
+                    brushFigure = 3;
+                    isBrush = true; }
+                  else if (action == "switch to area brush 5") {
+                    brushFigure = 4;
+                    isBrush = true; }
+                  else if (action == "switch to area brush 6") {
+                    brushFigure = 5;
+                    isBrush = true; }
+                  else if (action == "switch to area brush 7") {
+                    brushFigure = 6;
+                    isBrush = true; }
+                  else if (action == "switch to area brush 8") {
+                    brushFigure = 7;
+                    isBrush = true; }
+                  if (buildingType) {
+                    if (isBuildingEnabled(std::string(buildingType))) {
+                      displayMode = BUILDING_VIEW; // Can hiddenGUIElements 
forbid showing building view if the particular building type is enabled?  Do I 
need to check this?
+                      setSelection(TOOL_SELECTION, (void *) buildingType); }}
+                  else if (flagType) {
+                    if (isFlagEnabled(std::string(flagType))) {
+                      displayMode = FLAG_VIEW;  // Can hiddenGUIElements 
forbid showing flag view if the particular flag type is enabled?  Do I need to 
check this?
+                      setSelection(TOOL_SELECTION, (void*) flagType); }}
+                  else if (isArea || (tmpBrushMode != BrushTool::MODE_NONE) || 
isBrush) {
+                    // Do I need to check if the GUI is enabled for this?
+                    displayMode = FLAG_VIEW;
+                    if (isArea) {
+                      brushType = tmpBrushType; }
+                    if (tmpBrushMode != BrushTool::MODE_NONE) {
+                      brush.setType(tmpBrushMode); }
+                    else if (brush.getType() == BrushTool::MODE_NONE) {
+                      brush.setType(BrushTool::MODE_ADD); }
+                    if (isBrush) {
+                      brush.setFigure (brushFigure); }
+                    setSelection(BRUSH_SELECTION); }}
        }
 }
 
@@ -1498,42 +1820,70 @@
        Uint8 *keystate = SDL_GetKeyState(NULL);
        if (notmenu == false)
        {
+                SDLMod modState = SDL_GetModState();
+                int xMotion = 1;
+                int yMotion = 1;
+                /* We check that only Control is held to avoid accidentally
+                   matching window manager bindings for switching windows
+                   and/or desktops. */
+                if ((modState & KMOD_CTRL) && ! (modState & 
(KMOD_ALT|KMOD_SHIFT))) {
+                  /* It violates good abstraction principles that I
+                     have to do the calculations in the next two
+                     lines.  There should be methods that abstract
+                     these computations. */
+                  /* We move by half screens if Control is held while
+                     the arrow keys are held.  So we shift by 6
+                     instead of 5.  (If we shifted by 5, it would be
+                     good to subtract 1 so that there would be a small
+                     overlap between what is viewable both before and
+                     after the motion.) */
+                  xMotion = ((globalContainer->gfx->getW()-128)>>6);
+                  yMotion = ((globalContainer->gfx->getH())>>6); }
+                else if (modState) {
+                  /* Probably some keys held down as part of window
+                     manager operations. */
+                  xMotion = 0;
+                  yMotion = 0; }
+                // int oldViewportX = viewportX;
+                // int oldViewportY = viewportY;
                if (keystate[SDLK_UP])
-                       viewportY--;
+                       viewportY -= yMotion;
                if (keystate[SDLK_KP8])
-                       viewportY--;
+                       viewportY -= yMotion;
                if (keystate[SDLK_DOWN])
-                       viewportY++;
+                       viewportY += yMotion;
                if (keystate[SDLK_KP2])
-                       viewportY++;
+                       viewportY += yMotion;
                if ((keystate[SDLK_LEFT]) && (typingInputScreen == NULL)) // we 
haave a test in handleKeyAlways, that's not very clean, but as every key check 
based on key states and not key events are here, it is much simpler and thus 
easier to understand and thus cleaner ;-)
-                       viewportX--;
+                       viewportX -= xMotion;
                if (keystate[SDLK_KP4])
-                       viewportX--;
+                       viewportX -= xMotion;
                if ((keystate[SDLK_RIGHT]) && (typingInputScreen == NULL)) // 
we haave a test in handleKeyAlways, that's not very clean, but as every key 
check based on key states and not key events are here, it is much simpler and 
thus easier to understand and thus cleaner ;-)
-                       viewportX++;
+                       viewportX += xMotion;
                if (keystate[SDLK_KP6])
-                       viewportX++;
+                       viewportX += xMotion;
                if (keystate[SDLK_KP7])
                {
-                       viewportX--;
-                       viewportY--;
+                       viewportX -= xMotion;
+                       viewportY -= yMotion;
                }
                if (keystate[SDLK_KP9])
                {
-                       viewportX++;
-                       viewportY--;
+                       viewportX += xMotion;
+                       viewportY -= yMotion;
                }
                if (keystate[SDLK_KP1])
                {
-                       viewportX--;
-                       viewportY++;
+                       viewportX -= xMotion;
+                       viewportY += yMotion;
                }
                if (keystate[SDLK_KP3])
                {
-                       viewportX++;
-                       viewportY++;
+                       viewportX += xMotion;
+                       viewportY += yMotion;
                }
+                // if ((oldViewportX != viewportX) || (oldViewportY != 
viewportY)) {
+                //   fprintf (stderr, "xMotion: %d, yMotion: %d, viewportX: 
%d, viewportY: %d\n", xMotion, yMotion, viewportX, viewportY); }
        }
 }
 
@@ -1597,7 +1947,7 @@
                viewportY=(panViewY+dy)&game.map.getMaskH();
        }
 
-       dragStep();
+       dragStep(mx, my, button);
 }
 
 void GameGUI::handleMapClick(int mx, int my, int button)
@@ -1636,7 +1986,7 @@
        }
        else if (selectionMode==BRUSH_SELECTION)
        {
-               brushStep(mouseX, mouseY);
+               brushStep(true, mouseX, mouseY);
        }
        else if (putMark)
        {
@@ -1707,7 +2057,7 @@
                                {
                                        setSelection(BUILDING_SELECTION, gbid);
                                        selectionPushed=true;
-                                       showUnitWorkingToBuilding=true;
+                                       // showUnitWorkingToBuilding=true;
                                        // handle dump of building 
characteristics
                                        if ((SDL_GetModState() & KMOD_SHIFT) != 
0)
                                        {
@@ -3287,7 +3637,37 @@
        else if (selectionMode==BRUSH_SELECTION)
        {
                globalContainer->gfx->setClipRect(0, 0, 
globalContainer->gfx->getW()-128, globalContainer->gfx->getH());
-               brush.drawBrush(mouseX, mouseY);
+                /* Instead of using a dimmer intensity to indicate
+                   removing of areas, this should rather use dashed
+                   lines.  (The intensities used below are 2/3 as
+                   bright for the case of removing areas.) */
+                /* This reasoning should be abstracted out and reused
+                   in MapEdit.cpp to choose a color for those cases
+                   where areas are being drawn. */
+                unsigned mode = brush.getType();
+                Color c = Color(0,0,0);
+                /* The following colors have been chosen to match the
+                   colors in the .png files for the animations of
+                   areas as of 2007-04-29.  If those .png files are
+                   updated with different colors, then the following
+                   code should change accordingly. */
+                if (brushType == FORBIDDEN_BRUSH) {
+                  if (mode == BrushTool::MODE_ADD) {
+                    c = Color(255,0,0); }
+                  else {
+                    c = Color(170,0,0); }}
+                else if (brushType == GUARD_AREA_BRUSH) {
+                  if (mode == BrushTool::MODE_ADD) {
+                    c = Color(27,0,255); }
+                  else {
+                    c = Color(18,0,170); }}
+                else if (brushType == CLEAR_AREA_BRUSH) {
+                  if (mode == BrushTool::MODE_ADD) {
+                    /* some of the clearing area images use (252,207,0) 
instead */
+                    c = Color(251,206,0); }
+                  else {
+                    c = Color(167,137,0); }}
+               brush.drawBrush(mouseX, mouseY, c);
        }
        else if (selectionMode==BUILDING_SELECTION)
        {
@@ -3568,7 +3948,7 @@
        // if paused, tint the game area
        if (gamePaused)
        {
-               globalContainer->gfx->drawFilledRect(0, 0, 
globalContainer->gfx->getW()-128, globalContainer->gfx->getH(), 0, 0, 0, 127);
+               globalContainer->gfx->drawFilledRect(0, 0, 
globalContainer->gfx->getW()-128, globalContainer->gfx->getH(), 0, 0, 0, 20);
                const char *s = 
Toolkit::getStringTable()->getString("[Paused]");
                int x = 
(globalContainer->gfx->getW()-globalContainer->menuFont->getStringWidth(s))>>1;
                globalContainer->gfx->drawString(x, 
globalContainer->gfx->getH()-80, globalContainer->menuFont, s);
@@ -4067,21 +4447,70 @@
                        }
                }
        }
+        else if (selectionMode == UNIT_SELECTION)
+          {
+            Unit * selUnit = selection.unit;
+            assert(selUnit);
+            Uint16 gid = selUnit->gid;
+            /* to be safe should check if gid is valid here? */
+            /* if looking at one of our pieces, continue with the next
+               one of our pieces of same type, otherwise start at the
+               beginning of our pieces of that type. */
+            Sint32 id = ((Unit::GIDtoTeam(gid) == localTeamNo) ? 
Unit::GIDtoID(gid) : 0);
+            /* It violates good abstraction principles that we know
+               that the size of the myUnits array is 1024.  This
+               information should be abstracted by some method that we
+               call instead to get the next unit. */
+            id %= 1024; /* just in case! */
+            // std::cerr << "starting id: " << id << std::endl;
+            Sint32 i = id;
+            while (1)
+              {
+                i = ((i + 1) % 1024);
+                if (i == id) break;
+                // std::cerr << "trying id: " << i << std::endl;
+                Unit * u = game.teams[localTeamNo]->myUnits[i];
+                if (u && (u->typeNum == selUnit->typeNum))
+                  {
+                    // std::cerr << "found id: " << i << std::endl;
+                    setSelection(UNIT_SELECTION, u);
+                    centerViewportOnSelection();
+                    break;
+                  }
+              }
+          }
 }
 
 void GameGUI::centerViewportOnSelection(void)
 {
-       if (selectionMode==BUILDING_SELECTION)
-       {
-               Building* b=selection.building;
-               //assert (selBuild);
-               //Building 
*b=game.teams[Building::GIDtoTeam(selectionGBID)]->myBuildings[Building::GIDtoID(selectionGBID)];
-               assert(b);
-               viewportX=b->getMidX()-((globalContainer->gfx->getW()-128)>>6);
-               viewportY=b->getMidY()-((globalContainer->gfx->getH())>>6);
-               viewportX=viewportX&game.map.getMaskW();
-               viewportY=viewportY&game.map.getMaskH();
-       }
+  if ((selectionMode==BUILDING_SELECTION) || (selectionMode==UNIT_SELECTION))
+    {
+      Sint32 posX, posY;
+      if (selectionMode==BUILDING_SELECTION)
+        {
+          Building* b=selection.building;
+          //assert (selBuild);
+          //Building 
*b=game.teams[Building::GIDtoTeam(selectionGBID)]->myBuildings[Building::GIDtoID(selectionGBID)];
+          assert(b);
+          posX = b->getMidX();
+          posY = b->getMidY();
+        }
+      else if (selectionMode==UNIT_SELECTION)
+        {
+          Unit * u = selection.unit;
+          assert (u);
+          posX = u->posX;
+          posY = u->posY;
+        }
+      /* It violates good abstraction principles that we know here
+         that the size of the right panel is 128 pixels, and that each
+         map cell is 32 pixels.  This information should be
+         abstracted. */
+      viewportX = posX - ((globalContainer->gfx->getW()-128)>>6);
+      viewportY = posY - ((globalContainer->gfx->getH())>>6);
+      viewportX = viewportX & game.map.getMaskW();
+      viewportY = viewportY & game.map.getMaskH();
+    }
 }
 
 void GameGUI::enableBuildingsChoice(const std::string &name)
@@ -4102,6 +4531,16 @@
        }
 }
 
+bool GameGUI::isBuildingEnabled(const std::string &name)
+{
+       for (size_t i=0; i<buildingsChoiceName.size(); ++i)
+       {
+               if (name == buildingsChoiceName[i])
+                  return buildingsChoiceState[i];
+       }
+        assert (false);
+}
+
 void GameGUI::enableFlagsChoice(const std::string &name)
 {
        for (size_t i=0; i<flagsChoiceName.size(); ++i)
@@ -4120,6 +4559,16 @@
        }
 }
 
+bool GameGUI::isFlagEnabled(const std::string &name)
+{
+       for (size_t i=0; i<flagsChoiceName.size(); ++i)
+       {
+               if (name == flagsChoiceName[i])
+                  return flagsChoiceState[i];
+       }
+        assert (false);
+}
+
 void GameGUI::enableGUIElement(int id)
 {
        hiddenGUIElements &= ~(1<<id);
diff -ru ../../glob-virgin/glob2-0.8.23/src/GameGUI.h ./GameGUI.h
--- ../../glob-virgin/glob2-0.8.23/src/GameGUI.h        2007-04-17 
22:48:06.000000000 +0100
+++ ./GameGUI.h 2007-04-29 21:08:35.000000000 +0100
@@ -108,8 +108,10 @@
        // Script interface
        void enableBuildingsChoice(const std::string &name);
        void disableBuildingsChoice(const std::string &name);
+       bool isBuildingEnabled(const std::string &name);
        void enableFlagsChoice(const std::string &name);
        void disableFlagsChoice(const std::string &name);
+       bool isFlagEnabled(const std::string &name);
        void enableGUIElement(int id);
        void disableGUIElement(int id);
        bool isSpaceSet() { return hasSpaceBeenClicked; }
@@ -181,11 +183,11 @@
        
        void moveFlag(int mx, int my, bool drop);
        //! Update the brush and the local map due to mouse motion
-       void brushStep(int mx, int my);
+       void brushStep(bool maybeToggleMode, int mx, int my);
        //! Send a brush order and reinitialize the brush accumulator
        void sendBrushOrders(void);
        //! One viewport has moved and a flag or a brush is selected, update 
its position
-       void dragStep(void);
+       void dragStep(int mx, int my, int button);
        //! on each step, check if we have won or lost
        void checkWonConditions(void);
        
diff -ru ../../glob-virgin/glob2-0.8.23/src/Map.cpp ./Map.cpp
--- ../../glob-virgin/glob2-0.8.23/src/Map.cpp  2007-04-17 22:48:06.000000000 
+0100
+++ ./Map.cpp   2007-04-29 06:00:02.000000000 +0100
@@ -1115,6 +1115,11 @@
        
        if (game)
        {
+                /* Must set game field before following action as they
+                   may need it (in particular
+                   makeDiscoveredAreasExplored uses it). */
+               this->game=game;
+
                // This is a game, so we do compute gradients
                for (int t=0; t<sessionGame->numberOfTeam; t++)
                        for (int r=0; r<MAX_RESSOURCES; r++)
@@ -1144,9 +1149,8 @@
                        assert(exploredArea[t] == NULL);
                        exploredArea[t] = new Uint8[size];
                        initExploredArea(t);
+                        makeDiscoveredAreasExplored(t);
                }
-               
-               this->game=game;
        }
 
        // We load sectors:
@@ -4881,6 +4885,23 @@
        std::fill(exploredArea[teamNumber], exploredArea[teamNumber] + size, 0);
 }
 
+void Map::makeDiscoveredAreasExplored (int teamNumber)
+{
+  /* This function is a stupid hack to make up for the fact that
+     exploredArea is not saved in saved games.  It allows doing
+     something less awful than simply making everything considered
+     unexplored (which completely messes up explorer behavior and
+     makes them explore the entire world all over again) when games
+     are reloaded. */
+  assert(game->teams[teamNumber]);
+  assert(game->teams[teamNumber]->me);
+  assert(exploredArea[teamNumber]);
+  for (int x = 0; x < getW(); x++) {
+    for (int y = 0; y < getH(); y++) {
+      if (isMapDiscovered (x, y, game->teams[teamNumber]->me)) {
+        setMapExploredByUnit (x, y, 1, 1, teamNumber); }}}
+}
+
 void Map::updateExploredArea(int teamNumber)
 {
        for (size_t i = 0; i < size; i++)
diff -ru ../../glob-virgin/glob2-0.8.23/src/Map.h ./Map.h
--- ../../glob-virgin/glob2-0.8.23/src/Map.h    2007-04-17 22:48:06.000000000 
+0100
+++ ./Map.h     2007-04-22 04:03:07.000000000 +0100
@@ -582,6 +582,7 @@
        void updateGuardAreasGradient();
        
        void initExploredArea(int teamNumber);
+       void makeDiscoveredAreasExplored(int teamNumber);
        void updateExploredArea(int teamNumber);
        
 protected:
diff -ru ../../glob-virgin/glob2-0.8.23/src/Settings.cpp ./Settings.cpp
--- ../../glob-virgin/glob2-0.8.23/src/Settings.cpp     2007-04-17 
22:48:06.000000000 +0100
+++ ./Settings.cpp      2007-04-29 21:32:04.000000000 +0100
@@ -112,14 +112,14 @@
 
 void Settings::restoreDefaultShortcuts()
 {
-       keyboard_shortcuts["akey"]="toggle draw accessibility aids";
-       keyboard_shortcuts["bkey"]="";
+       keyboard_shortcuts["akey"]="prefix key select area tool";
+       keyboard_shortcuts["bkey"]="prefix key select building tool";
        keyboard_shortcuts["ckey"]="";
        keyboard_shortcuts["dkey"]="destroy building";
        keyboard_shortcuts["ekey"]="";
-       keyboard_shortcuts["fkey"]="";
+       keyboard_shortcuts["fkey"]="prefix key select flag tool";
        keyboard_shortcuts["gkey"]="";
-       keyboard_shortcuts["hkey"]="";
+       keyboard_shortcuts["hkey"]="toggle draw accessibility aids";
        keyboard_shortcuts["ikey"]="toggle draw information";
        keyboard_shortcuts["jkey"]="";
        keyboard_shortcuts["kkey"]="";
diff -ru ../../glob-virgin/glob2-0.8.23/src/SettingsScreen.cpp 
./SettingsScreen.cpp
--- ../../glob-virgin/glob2-0.8.23/src/SettingsScreen.cpp       2007-04-17 
22:48:06.000000000 +0100
+++ ./SettingsScreen.cpp        2007-04-29 22:25:48.000000000 +0100
@@ -233,6 +233,47 @@
        shortcut_actions.push_back("record voice");
        shortcut_names.push_back(Toolkit::getStringTable()->getString("[pause 
game]"));
        shortcut_actions.push_back("pause game");
+        char * (commands[]) = {
+          "prefix key select area tool",
+          "prefix key select building tool",
+          "prefix key select flag tool",
+          "select make swarm tool",
+          "select make inn tool",
+          "select make hospital tool",
+          "select make racetrack tool",
+          "select make swimming pool tool",
+          "select make barracks tool",
+          "select make school tool",
+          "select make defense tower tool",
+          "select make stone wall tool",
+          "select make market tool",
+          "select make exploration flag tool",
+          "select make war flag tool",
+          "select make clearing flag tool",
+          "select forbidden area tool",
+          "select guard area tool",
+          "select clearing area tool",
+          "switch to adding areas",
+          "switch to deleting areas",
+          "switch to area brush 1",
+          "switch to area brush 2",
+          "switch to area brush 3",
+          "switch to area brush 4",
+          "switch to area brush 5",
+          "switch to area brush 6",
+          "switch to area brush 7",
+          "switch to area brush 8", };
+        // fprintf (stderr, "before loop: sizeof(commands): %d\n", sizeof 
(commands));
+        for (int i = 0; i < (sizeof (commands) / (sizeof (commands[0]))); i++) 
{
+          // fprintf (stderr, "i: %d\n", i);
+          char buffer[100];
+          snprintf (buffer, sizeof(buffer), "[%s]", commands[i]);
+          buffer[99] = '\0';
+          const char * message = Toolkit::getStringTable()->getString(buffer);
+          // fprintf (stderr, "commands[%d]: {%s}, buffer: {%s}, message: 
{%s}\n", i, commands[i], buffer, message);
+          shortcut_names.push_back (message);
+          shortcut_actions.push_back (commands[i]); }
+        // fprintf (stderr, "after loop\n");
 
        
editor_shortcut_names.push_back(Toolkit::getStringTable()->getString("[switch 
to building view]"));
        editor_shortcut_actions.push_back("switch to building view");
diff -ru ../../glob-virgin/glob2-0.8.23/src/Unit.cpp ./Unit.cpp
--- ../../glob-virgin/glob2-0.8.23/src/Unit.cpp 2007-04-17 22:48:06.000000000 
+0100
+++ ./Unit.cpp  2007-04-29 06:06:27.000000000 +0100
@@ -720,6 +720,23 @@
 
 void Unit::handleMedical(void)
 {
+        /* Make sure explorers try to immediately feed after healing to 
increase their range. */
+        if ((typeNum == EXPLORER)
+            && (displacement == DIS_EXITING_BUILDING)) {
+          medical=MED_FREE;
+          if ((destinationPurprose == HEAL)
+              && (hungry < ((HUNGRY_MAX * 9) / 10))) {
+            // fprintf (stderr, "forcing explorer hunger: gid: %d, hungry: 
%d\n", gid, hungry);
+            needToRecheckMedical = 1;
+            medical = MED_HUNGRY;
+            return; }
+          else if ((destinationPurprose == FEED)
+                   && (hp < (((performance[HP]) * 9) / 10))) {
+            // fprintf (stderr, "forcing explorer healing: gid: %d, hp: %d\n", 
gid, hp);
+            needToRecheckMedical = 1;
+            medical = MED_DAMAGED;
+            return; }}
+
        if ((displacement==DIS_ENTERING_BUILDING) || (displacement==DIS_INSIDE) 
|| (displacement==DIS_EXITING_BUILDING))
                return;
        
@@ -773,8 +790,15 @@
 
 void Unit::handleActivity(void)
 {
+        if ((displacement==DIS_EXITING_BUILDING)
+            && (typeNum == EXPLORER)) {
+          // fprintf (stderr, "exiting explorer: gid: %d, medical: %d, 
destinationPurprose: %d\n", gid, medical, destinationPurprose);
+        }
+
        // freeze unit health when inside a building
-       if ((displacement==DIS_ENTERING_BUILDING) || (displacement==DIS_INSIDE) 
|| (displacement==DIS_EXITING_BUILDING))
+       if ((displacement==DIS_ENTERING_BUILDING) || (displacement==DIS_INSIDE)
+            || ((displacement==DIS_EXITING_BUILDING)
+                && ! ((typeNum == EXPLORER) && (medical != MED_FREE))))
                return;
        
        if (verbose)
@@ -853,6 +877,10 @@
                {
                        Building *b;
                        b=owner->findNearestFood(this);
+                        if (typeNum == EXPLORER) {
+                          // fprintf (stderr, "gid: %d, b: %x\n", gid, b);
+                        }
+
                        if (b!=NULL)
                        {
                                Team *currentTeam=owner;
@@ -1464,6 +1492,12 @@
                                                dxdyfromDirection();
                                                movement = MOV_GOING_DXDY;
                                                found = true;
+                                                /* 
+                                                fprintf (stderr, "gid = %d; 
changed direction: direction = %d, dx = %d, dy = %d; tab = {", gid, direction, 
dx, dy);
+                                                for (int i = 0; i < 8; i++) {
+                                                  fprintf (stderr, "%d%s", 
tab[i], ((i < 7) ? ", " : "")); }
+                                                fprintf (stderr, "}\n");
+                                                */
                                                break;
                                        }
                                }
@@ -1471,16 +1505,25 @@
                                {
                                        int scoreX = 0;
                                        int scoreY = 0;
-                                       for (int delta = -3; delta <= 3; 
delta++)
-                                       {
-                                               scoreX += 
owner->map->getExplored(posX - 4, posY + delta, owner->teamNumber);
-                                               scoreX -= 
owner->map->getExplored(posX + 4, posY + delta, owner->teamNumber);
-                                               scoreY += 
owner->map->getExplored(posX + delta, posY - 4, owner->teamNumber);
-                                               scoreY -= 
owner->map->getExplored(posX + delta, posY + 4, owner->teamNumber);
-                                       }
+                                        /* The next line should really be 
calculated only once per game.  How to do this?  The point is to avoid wrapping 
around the torus in considering what area is closer to us. */
+                                        int maxRange = 
(std::min(owner->map->getW(), owner->map->getH())) / 2;
+                                        /* We sample cells at various
+                                           distances to decide in what
+                                           direction there is more
+                                           unexplored territory. */
+                                        for (int range = 1; range <= maxRange; 
range *= 2)
+                                          {
+                                            for (int delta = -3; delta <= 3; 
delta++)
+                                              {
+                                               scoreX += 
owner->map->getExplored(posX - (4*range), posY + (delta*range), 
owner->teamNumber);
+                                               scoreX -= 
owner->map->getExplored(posX + (4*range), posY + (delta*range), 
owner->teamNumber);
+                                               scoreY += 
owner->map->getExplored(posX + (delta*range), posY - (4*range), 
owner->teamNumber);
+                                               scoreY -= 
owner->map->getExplored(posX + (delta*range), posY + (4*range), 
owner->teamNumber);
+                                              }
+                                          }
                                        int cdx, cdy;
                                        simplifyDirection(scoreX, scoreY, &cdx, 
&cdy);
-                                       //printf("score = (%2d, %2d), cd = (%d, 
%d)\n", scoreX, scoreY, cdx, cdy);
+                                       // fprintf(stderr, "gid = %d, maxRange 
= %d, score = (%2d, %2d), cd = (%d, %d)\n", gid, maxRange, scoreX, scoreY, cdx, 
cdy);
                                        if (cdx == 0 && cdy == 0)
                                                movement = MOV_RANDOM_FLY;
                                        else
@@ -2290,12 +2333,18 @@
        else if (ldy<-(maph>>1))
                ldy+=maph;
 
-       if (abs(ldx)>(2*abs(ldy)))
+        /* We consider a cell to be vertical or horizontal in
+           direction (rather than diagonal) if it is 2.41 times more
+           vertical than horizontal, or vice versa.  This is because
+           the halfway point between 45 degrees and 90 degrees is 67.5
+           degrees and sin(67.5 deg) / cos(67.5 deg) =
+           2.41421356237. */
+       if ((100 * abs(ldx)) > (241 * abs(ldy)))
        {
                *cdx=SIGN(ldx);
                *cdy=0;
        }
-       else if (abs(ldy)>(2*abs(ldx)))
+       else if ((100 * abs(ldy)) > (241 * abs(ldx)))
        {
                *cdx=0;
                *cdy=SIGN(ldy);

Attachment: data-gfx.tar.gz
Description: Binary data


reply via email to

[Prev in Thread] Current Thread [Next in Thread]