[comp.sources.bugs] v01i099: ogre - tank warfare in the 21st century

dupuy@amsterdam.columbia.edu (Alexander Dupuy) (07/28/87)

The game Ogre (which I had no trouble compiling) is really wonderful; bringing
back the memory of many hours spent playing the paper version.  However, there
is an inconsistency in the electronic version which I can't figure.  Lacking a
copy of the paper game, I can't go to the rules.  Perhaps someone (the author?)
who does can advise.

This version of ogre(6) allows you to place the Command Post in a crater.  This
is an extremely effective defense technique, since it is no longer possible for
the Ogre to ram the CP (you can't enter craters, right?).  You can just blast
away at the batteries and missiles, and once those are gone, take your time at
finishing off the treads for the win.  You don't even need to take out the
anti-personnel guns.

In fact, if the CP is in a crater, once the batteries and missiles are gone,
you cannot lose the game.  The best the Ogre can hope for is a stalemate, by
destroying any infantry with AP, and destroying any armor by ramming (not easy)
before all its treads are gone.

In fact, it is even possible to place the CP on top of another unit (or units
of infantry), even though placing units on top of the CP is disallowed.  This
is definitely an inconsistency.

Although I haven't yet beat the Ogre without placing the CP in a crater, the
poor checking on CP placement would seem to be a bug.  If in fact it violates
the rules, here is a fix:

*** init.c.dist	Mon Jul 27 20:28:10 1987
--- init.c	Tue Jul 28 16:08:05 1987
***************
*** 112,118 ****
  		break ;
  			
              case CP:
!                 if(cp_set) {
                      bad_char = TRUE;
                  }
                  else {
--- 112,118 ----
  		break ;
  			
              case CP:
!                 if(occupied(a, b) || blocked(a, b) || cp_set) {
                      bad_char = TRUE;
                  }
                  else {

Some other trivia; there is a sequel to the Ogre game called G.E.V. which pits
"defenders" against defenders (no ogre).  I don't recollect it fully, but I
seem to remember that there were some additional armored unit types.
I believe that it was only in G.E.V. (and the re-release of Ogre) that the
second movement phase of GEVs was reduced to three hexes in order to bring it
more into line with other units (in the original Ogre, GEVs moved 4 + 4).

If anyone could send me details, I would be happy to implement the extensions.

@alex
---
arpanet: dupuy@columbia.edu
uucp:	...!seismo!columbia!dupuy

hyc@umix.cc.umich.edu (Howard Chu) (07/30/87)

Actually, AntiPersonnel weapons are sufficient for destroying the
Command Post. I have a copy of both Ogre and GEV, but they aren't
handy right now. I also have The Ogre Book, which includes such
niceties as new scenarios, strategy & tactics, and a few new units,
such as the Marks I, II, IV, and VI, as well as a few "hybrid"
units. (The Mark IV was also present in GEV.) Several of these
newer units are also in GEV, including light tanks, mobile howitzers,
and other goodies. Including the units would be no problem, but
fixing up the map would be a challenge. In GEV, the map is about
50% larger and has *terrain*. Roads, swamps, forests, rivers, lakes,
gullies, cities... Terrain is a Real Nice thing to have in a game
of ground based armor units. Ah well. There are also new rules
for stacking, ie allowing multiple units per hex, overrun attacks,
and other good stuff that would be nice to take into account.

Ah well. I can't check to see if this is a real "bug" or not, but
I'm gonna keep that patch handy...
-- 
  -- Howard Chu
UUCP:	...!seismo!umix!hyc
ARPA:	hyc@umix.cc.umich.edu

dupuy@amsterdam.columbia.edu (Alexander Dupuy) (08/01/87)

I found my copies of Ogre and G.E.V. so I can say that the bug I reported
earlier is in fact a bug.  The rules state clearly that objects cannot be
placed on top of each other, or on craters.

Once I had the rules to G.E.V. I couldn't resist adding the new unit types to
ogre.  So I am enclosing patches to add the Ogre Mark IV, and the 'L' (light
tank) and 'B' (mobile howitzer) type units.  Note that you get two light tanks
for each armor point.

If anyone with The Ogre Book can send me the specs on the Mark I, II, and VI
Ogres, I can add them as well.  Or they can just send out the patches
themselves.  Anyone who is really inspired could try implementing the terrain
rules.  Overrun combat is another possibility, but perhaps too complex to be
worth it.

The Ogre Mark IV has a different missile weapon system, with 3 missile racks,
but 15 missiles.  Missile racks (but not missiles) can be attacked, and when
they are destroyed, one missile is destroyed.  Only one missile can be fired
per turn per rack (they take time to reload).  Missile racks also have a
defense of 4 instead of 3.  The Mark IV is also faster, with a movement of 4.
It has fewer main and secondary batteries, though, so it is considered on a par
with the Mark V.

To be able to implement all Ogres with the same structure, I modified the the
Mark III and Mark V Ogres.  They both now have 2 missile racks, and the same
number of missiles as before.  The justification for this is that there is a
rule in Ogre which says they can fire no more than 2 missiles per turn.  The
Mark V has 6 missiles (according to the Ogre rulebook) not 5.  Was this changed
in later versions of Ogre (I have the original)?

One other discrepancy I noted between the Ogre rules and the implementation is
the number of armor and infantry points which the defender gets.  The paper
rules give you far more points than the program.  Is this because the dumb
computer needs a handicap?

The patches which jpochma@polyslo.UUCP (John H Pochmara) posted to fix up
problems with _doprnt() on some machines had a flaw: they failed to erase to
end of line, as the display() routine had.

The rest of this posting is a set of patches which should be applied to the
original ogre, as posted to comp.sources.games (dust off those shar files now).
They fix the _doprnt problem, and the CP placement bug.  A number of other
cosmetic changes are included as well.  And of course, the new units and Ogre
types.

@alex
---
arpanet: dupuy@columbia.edu
uucp:	...!seismo!columbia!dupuy

: This is a shar archive.  Extract with sh, not csh.
: The rest of this file will extract: 
:
:	attack.c.pat
:	init.c.pat
:	main.c.pat
:	map.c.pat
:	ogre.6.pat
:	ogre.h.pat
:	ogrecom.c.pat
:	ogrestat.c.pat
:	resolve.c.pat
:
echo x - attack.c.pat
sed 's/^X//' > attack.c.pat << '//go.sysin dd *'
X*** attack.c.dist	Mon Jul 27 20:28:05 1987
X--- attack.c	Fri Jul 31 17:32:00 1987
X***************
X*** 167,194 ****
X  
X          case MAIN:
X  
X!             display_xy(18, 40, "%d/%d (%s)", allocated.main_bats, DEF_MAIN,
X                  odd_str(allocated.main_bats, DEF_MAIN));
X              break;
X  
X          case SECONDARY:
X  
X!             display_xy(19, 40, "%d/%d (%s)", allocated.sec_bats, DEF_SECONDARY,
X                  odd_str(allocated.sec_bats, DEF_SECONDARY));
X              break;
X  
X          case MISSILE:
X  
X!             display_xy(20, 40, "%s", odd_str(allocated.missiles, DEF_MISSILES));
X              break;
X  
X          case AP:
X  
X!             display_xy(21, 40, "%s", odd_str(allocated.ap, DEF_AP));
X              break;
X  
X          case TREAD:
X!             display_xy(22, 40, "1/1 (%d)", allocated.treads);
X              break;
X  
X      }
X--- 167,196 ----
X  
X          case MAIN:
X  
X!             DISPLAY_XY3(18, 40, "%d/%d (%s)", allocated.main_bats, DEF_MAIN,
X                  odd_str(allocated.main_bats, DEF_MAIN));
X              break;
X  
X          case SECONDARY:
X  
X!             DISPLAY_XY3(19, 40, "%d/%d (%s)", allocated.sec_bats, DEF_SECONDARY,
X                  odd_str(allocated.sec_bats, DEF_SECONDARY));
X              break;
X  
X          case MISSILE:
X  
X!             DISPLAY_XY3(20, 40, "%d/%d (%s)", allocated.missiles, DEF_MISSILES,
X!                 odd_str(allocated.missiles, DEF_MISSILES));
X              break;
X  
X          case AP:
X  
X!             DISPLAY_XY3(21, 40, "%d/%d (%s)", allocated.ap, DEF_AP,
X!                 odd_str(allocated.ap, DEF_AP));
X              break;
X  
X          case TREAD:
X!             DISPLAY_XY1(22, 40, "1/1 [%d]", allocated.treads);
X              break;
X  
X      }
//go.sysin dd *
echo x - init.c.pat
sed 's/^X//' > init.c.pat << '//go.sysin dd *'
X*** init.c.dist	Mon Jul 27 20:28:10 1987
X--- init.c	Fri Jul 31 17:58:29 1987
X***************
X*** 8,13 ****
X--- 8,14 ----
X  init_units(mark)
X  {
X      int unitcmp();
X+     char *halve();
X  
X  	init_screen();
X  
X***************
X*** 17,28 ****
X      switch(mark) {
X  
X          case 3:
X!             armor_points = 10;
X              infantry_points = 18;
X              break;
X  
X          case 5: 
X!             armor_points = 18;
X              infantry_points = 27;
X              break;
X      }
X--- 18,30 ----
X      switch(mark) {
X  
X          case 3:
X!             armor_points = 20;
X              infantry_points = 18;
X              break;
X  
X+         case 4:
X          case 5: 
X!             armor_points = 36;
X              infantry_points = 27;
X              break;
X      }
X***************
X*** 31,39 ****
X      cp_set = FALSE;
X  
X      while(armor_points > 0 || infantry_points > 0 || !cp_set) {
X!         display(16, "left to place: %d armor, %d infantry%s",
X!             armor_points, infantry_points,
X!             (cp_set) ? "." : ", CP");
X          getunit();
X      }
X  
X--- 33,41 ----
X      cp_set = FALSE;
X  
X      while(armor_points > 0 || infantry_points > 0 || !cp_set) {
X!         DISPLAY3(16, "left to place: %s armor, %d infantry%s",
X!             halve(armor_points), infantry_points,
X!             (cp_set) ? "" : ", CP");
X          getunit();
X      }
X  
X***************
X*** 96,108 ****
X  		    }
X  		if (unit[i].type == CP) {
X  			cp_set = FALSE ;
X! 			armor_points += unit[i].movement ;
X  			}
X  		else if (unit[i].type == INFANTRY) infantry_points += 1 ;
X! 		else if (unit[i].type == HOWITZER) armor_points += 2 ;
X! 		else if (unit[i].type == HVYTANK) armor_points += 1 ;
X! 		else if (unit[i].type == MSLTANK) armor_points += 1 ;
X! 		else if (unit[i].type == GEV) armor_points += 1 ;
X  		else broken("Internal error in init!") ;
X  
X  		if (i < n_free) n_free = i ;
X--- 98,112 ----
X  		    }
X  		if (unit[i].type == CP) {
X  			cp_set = FALSE ;
X! 			armor_points += unit[i].movement * 2;
X  			}
X  		else if (unit[i].type == INFANTRY) infantry_points += 1 ;
X! 		else if (unit[i].type == LTTANK) armor_points += 1 ;
X! 		else if (unit[i].type == GEV) armor_points += 2 ;
X! 		else if (unit[i].type == MSLTANK) armor_points += 2 ;
X! 		else if (unit[i].type == HVYTANK) armor_points += 2 ;
X! 		else if (unit[i].type == MHWZ) armor_points += 4 ;
X! 		else if (unit[i].type == HOWITZER) armor_points += 4 ;
X  		else broken("Internal error in init!") ;
X  
X  		if (i < n_free) n_free = i ;
X***************
X*** 112,118 ****
X  		break ;
X  			
X              case CP:
X!                 if(cp_set) {
X                      bad_char = TRUE;
X                  }
X                  else {
X--- 116,122 ----
X  		break ;
X  			
X              case CP:
X!                 if(occupied(a, b) || blocked(a, b) || cp_set) {
X                      bad_char = TRUE;
X                  }
X                  else {
X***************
X*** 122,139 ****
X                  }
X                  break;
X  
X              case HVYTANK:
X              case MSLTANK:
X              case GEV:
X!                 if(occupied(a, b) || blocked(a, b) || armor_points == 0) {
X                      bad_char = TRUE;
X                      break;
X                  }
X                  add_unit(a, b, dir);
X                  no_new = FALSE;
X!                 armor_points--;
X                  break;
X      
X              case INFANTRY:
X  		dir = '3' ;
X  	    case '3':
X--- 126,165 ----
X                  }
X                  break;
X  
X+             case HOWITZER:
X+             case MHWZ:
X+                 if(occupied(a, b) || blocked(a, b) || armor_points <= 3) {
X+                     bad_char = TRUE;
X+                     break;
X+                 }
X+                 add_unit(a, b, dir);
X+                 no_new = FALSE;
X+                 armor_points -= 4;
X+                 break;
X+     
X              case HVYTANK:
X              case MSLTANK:
X              case GEV:
X!                 if(occupied(a, b) || blocked(a, b) || armor_points <= 1) {
X                      bad_char = TRUE;
X                      break;
X                  }
X                  add_unit(a, b, dir);
X                  no_new = FALSE;
X!                 armor_points -= 2;
X                  break;
X      
X+             case LTTANK:
X+ 
X+                 if(occupied(a, b) || blocked(a, b) || armor_points <= 0) {
X+                     bad_char = TRUE;
X+                     break;
X+                 }
X+                 add_unit(a, b, dir);
X+                 no_new = FALSE;
X+                 armor_points -= 1;
X+                 break;
X+     
X              case INFANTRY:
X  		dir = '3' ;
X  	    case '3':
X***************
X*** 151,172 ****
X  			break ;
X  			}
X  		while (dir--) {
X!                     add_unit(a, b, 'I');
X                      infantry_points -= 1 ;
X  		    }
X                  no_new = FALSE;
X                  break;
X      
X-             case HOWITZER:
X-                 if(occupied(a, b) || blocked(a, b) || armor_points <= 1) {
X-                     bad_char = TRUE;
X-                     break;
X-                 }
X-                 add_unit(a, b, dir);
X-                 no_new = FALSE;
X-                 armor_points -= 2;
X-                 break;
X-     
X              default:
X                  bad_char = TRUE;
X                  break;
X--- 177,188 ----
X  			break ;
X  			}
X  		while (dir--) {
X!                     add_unit(a, b, INFANTRY);
X                      infantry_points -= 1 ;
X  		    }
X                  no_new = FALSE;
X                  break;
X      
X              default:
X                  bad_char = TRUE;
X                  break;
X***************
X*** 221,234 ****
X              unit[i].range = 0;
X              unit[i].defend = 0;
X  	    j = 200 ;
X! 	    while (j > armor_points || j > 2 || j < 0) {
X! 		display(17, "Movement points for CP? ", 0) ;
X  		j = readchar() ;
X  		j -= '0' ;
X  		}
X  	    movecur(17, 0); eeol() ;
X              unit[i].movement = j;
X! 	    armor_points -= j;
X              break; 
X  
X          case HVYTANK:
X--- 237,250 ----
X              unit[i].range = 0;
X              unit[i].defend = 0;
X  	    j = 200 ;
X! 	    while (j > armor_points || j > 4 || j < 0) {
X! 		DISPLAY0(17, "Movement points for CP? ") ;
X  		j = readchar() ;
X  		j -= '0' ;
X  		}
X  	    movecur(17, 0); eeol() ;
X              unit[i].movement = j;
X! 	    armor_points -= 2 * j;
X              break; 
X  
X          case HVYTANK:
X***************
X*** 239,244 ****
X--- 255,268 ----
X              unit[i].movement = 3;
X              break; 
X  
X+         case LTTANK:
X+             unit[i].type = LTTANK;
X+             unit[i].attack = 2;
X+             unit[i].range = 2;
X+             unit[i].defend = 2;
X+             unit[i].movement = 3;
X+             break; 
X+ 
X          case MSLTANK:
X              unit[i].type = MSLTANK;
X              unit[i].attack = 3;
X***************
X*** 263,268 ****
X--- 287,300 ----
X              unit[i].movement = 0;
X              break; 
X  
X+         case MHWZ:
X+             unit[i].type = MHWZ;
X+             unit[i].attack = 6;
X+             unit[i].range = 6;
X+             unit[i].defend = 2;
X+             unit[i].movement = 1;
X+             break; 
X+ 
X  	case INFANTRY:
X              unit[i].type = INFANTRY;
X              unit[i].attack = 1;
X***************
X*** 324,343 ****
X              ogre.treads = 45;
X              ogre.init_treads = 45;
X              ogre.movement = 3;
X              ogre.missiles = 2;
X              ogre.main_bats = 1;
X              ogre.sec_bats  = 4;
X              ogre.ap = 8;
X              break;
X  
X          case 5:
X              ogre.treads = 60;
X              ogre.init_treads = 60;
X              ogre.movement = 3;
X!             ogre.missiles = 5;
X              ogre.main_bats = 2;
X              ogre.sec_bats  = 6;
X!             ogre.ap = 10;
X              break;
X  
X      }
X--- 356,391 ----
X              ogre.treads = 45;
X              ogre.init_treads = 45;
X              ogre.movement = 3;
X+             ogre.init_move = 3;
X              ogre.missiles = 2;
X+             ogre.missracks = 2;
X              ogre.main_bats = 1;
X              ogre.sec_bats  = 4;
X              ogre.ap = 8;
X              break;
X  
X+         case 4:
X+             ogre.treads = 60;
X+             ogre.init_treads = 60;
X+             ogre.movement = 4;
X+             ogre.init_move = 4;
X+             ogre.missiles = 15;
X+             ogre.missracks = 3;
X+             ogre.main_bats = 1;
X+             ogre.sec_bats  = 2;
X+             ogre.ap = 8;
X+             break;
X+ 
X          case 5:
X              ogre.treads = 60;
X              ogre.init_treads = 60;
X+             ogre.init_move = 3;
X              ogre.movement = 3;
X!             ogre.missiles = 6;
X!             ogre.missracks = 2;
X              ogre.main_bats = 2;
X              ogre.sec_bats  = 6;
X!             ogre.ap = 12;
X              break;
X  
X      }
X***************
X*** 389,399 ****
X--- 437,468 ----
X  
X              break;
X  
X+         case MHWZ:
X+             switch(u2 -> type) {
X+ 
X+                 case CP: 
X+                 case HOWITZER: 
X+                     cmp = 1;
X+                     break;
X+ 
X+                 case MHWZ:
X+                     cmp = 0;
X+                     break;
X+ 
X+                 default:
X+                     cmp = -1;
X+                     break;
X+ 
X+             }
X+ 
X+             break;
X+ 
X          case HVYTANK:
X              switch(u2 -> type) {
X  
X                  case CP:
X                  case HOWITZER:
X+                 case MHWZ:
X                      cmp = 1;
X                      break;
X  
X***************
X*** 412,421 ****
X          case MSLTANK:
X              switch(u2 -> type) {
X  
X!                 case CP:
X!                 case HOWITZER:
X!                 case HVYTANK:
X!                     cmp = 1;
X                      break;
X  
X                  case MSLTANK:
X--- 481,490 ----
X          case MSLTANK:
X              switch(u2 -> type) {
X  
X! 	        case INFANTRY:
X! 	        case LTTANK:
X! 	        case GEV:
X!                     cmp = -1;
X                      break;
X  
X                  case MSLTANK:
X***************
X*** 423,429 ****
X                      break;
X  
X                  default:
X!                     cmp = -1;
X                      break;
X  
X              }
X--- 492,498 ----
X                      break;
X  
X                  default:
X!                     cmp = 1;
X                      break;
X  
X              }
X***************
X*** 434,439 ****
X--- 503,509 ----
X              switch(u2 -> type) {
X  
X                  case INFANTRY:
X+                 case LTTANK:
X                      cmp = -1;
X                      break;
X  
X***************
X*** 449,454 ****
X--- 519,543 ----
X  
X              break;
X  
X+         case LTTANK:
X+             switch(u2 -> type) {
X+ 
X+                 case INFANTRY:
X+                     cmp = -1;
X+                     break;
X+ 
X+                 case LTTANK:
X+                     cmp = 0;
X+                     break;
X+ 
X+                 default:
X+                     cmp = 1;
X+                     break;
X+ 
X+             }
X+ 
X+             break;
X+ 
X          case INFANTRY:
X              switch(u2 -> type) {
X  
X***************
X*** 470,479 ****
X  
X  }
X  
X! broken(thing) char *thing; {
X  
X! 	clear_screen() ;
X! 	reset_term() ;
X!     	printf("Internal error: %s\n", thing) ;
X! 	exit(1) ;
X! 	}
X--- 559,578 ----
X  
X  }
X  
X! char *halve(number)
X! int number;
X! {
X!     static char buffer[16];
X  
X!     sprintf(buffer, "%d%s", number / 2, (number % 2) ? ".5" : "");
X!     return(buffer);
X! }
X! 
X! broken(thing)
X! char *thing;
X! {
X!     clear_screen() ;
X!     reset_term() ;
X!     printf("Internal error: %s\n", thing) ;
X!     exit(1) ;
X! }
//go.sysin dd *
echo x - main.c.pat
sed 's/^X//' > main.c.pat << '//go.sysin dd *'
X*** main.c.dist	Mon Jul 27 20:28:13 1987
X--- main.c	Wed Jul 29 00:26:32 1987
X***************
X*** 32,37 ****
X--- 32,41 ----
X                  mark = 3;
X                  break;
X  
X+             case '4':
X+                 mark = 4;
X+                 break;
X+ 
X              case '5':
X                  mark = 5;
X                  break;
X***************
X*** 61,67 ****
X          move_def();
X          attack_def();
X  
X!         /* Let the GEVs move their extra 3 turns. */
X          init_gev2();
X          move_def();
X  
X--- 65,71 ----
X          move_def();
X          attack_def();
X  
X!         /* Let the GEVs move their extra 3 hexes. */
X          init_gev2();
X          move_def();
X  
//go.sysin dd *
echo x - map.c.pat
sed 's/^X//' > map.c.pat << '//go.sysin dd *'
X*** map.c.dist	Mon Jul 27 20:28:16 1987
X--- map.c	Fri Jul 31 17:51:27 1987
X***************
X*** 310,377 ****
X      switch(unit[i].type) {
X  
X          case HOWITZER:
X!             display(16, "%s howitzer (%d/%d D%d M%d)", action,
X                  unit[i].attack, unit[i].range, 
X                  unit[i].defend, unit[i].moves_left);
X              break;
X  
X          case MSLTANK:
X!             display(16, "%s missile tank (%d/%d D%d M%d)", action,
X                  unit[i].attack, unit[i].range, 
X                  unit[i].defend, unit[i].moves_left);
X              break;
X  
X          case GEV:
X!             display(16, "%s GEV (%d/%d D%d M%d)", action,
X                  unit[i].attack, unit[i].range, 
X                  unit[i].defend, unit[i].moves_left);
X              break;
X  
X!         case HVYTANK:
X!             display(16, "%s heavy tank (%d/%d D%d M%d)", action,
X                  unit[i].attack, unit[i].range, 
X                  unit[i].defend, unit[i].moves_left);
X              break;
X  
X          case INFANTRY:
X!             display(16, "%s infantry (%d/%d D%d M%d)", action,
X                  unit[i].attack, unit[i].range, 
X                  unit[i].defend, unit[i].moves_left);
X              break;
X  
X  	case CP:
X! 	    display(16, "%s CP (%d/%d D%d M%d)", action,
X                  unit[i].attack, unit[i].range, 
X                  unit[i].defend, unit[i].moves_left);
X  	    break;
X      }
X  
X  }
X- 
X- /* VARARGS */
X- display(line, format, args)
X- int line;
X- char *format;
X- int args;
X- {
X- 
X-     movecur(line, 0);
X-     eeol();
X-     _doprnt(format, &args, stdout);
X- 
X- }
X- 
X- /* VARARGS */
X- display_xy(line, col, format, args)
X- int line, col;
X- char *format;
X- int args;
X- {
X- 
X-     movecur(line, col);
X-     eeol();
X-     _doprnt(format, &args, stdout);
X- 
X- }
X- 
X- 
X--- 310,365 ----
X      switch(unit[i].type) {
X  
X          case HOWITZER:
X!             DISPLAY5(16, "%s howitzer (%d/%d D%d M%d)", action,
X                  unit[i].attack, unit[i].range, 
X                  unit[i].defend, unit[i].moves_left);
X              break;
X  
X+         case MHWZ:
X+             DISPLAY5(16, "%s mobile howitzer (%d/%d D%d M%d)", action,
X+                 unit[i].attack, unit[i].range, 
X+                 unit[i].defend, unit[i].moves_left);
X+             break;
X+ 
X+         case HVYTANK:
X+             DISPLAY5(16, "%s heavy tank (%d/%d D%d M%d)", action,
X+                 unit[i].attack, unit[i].range, 
X+                 unit[i].defend, unit[i].moves_left);
X+             break;
X+ 
X          case MSLTANK:
X!             DISPLAY5(16, "%s missile tank (%d/%d D%d M%d)", action,
X                  unit[i].attack, unit[i].range, 
X                  unit[i].defend, unit[i].moves_left);
X              break;
X  
X          case GEV:
X!             DISPLAY5(16, "%s GEV (%d/%d D%d M%d)", action,
X                  unit[i].attack, unit[i].range, 
X                  unit[i].defend, unit[i].moves_left);
X              break;
X  
X!         case LTTANK:
X!             DISPLAY5(16, "%s light tank (%d/%d D%d M%d)", action,
X                  unit[i].attack, unit[i].range, 
X                  unit[i].defend, unit[i].moves_left);
X              break;
X  
X          case INFANTRY:
X!             DISPLAY5(16, "%s infantry (%d/%d D%d M%d)", action,
X                  unit[i].attack, unit[i].range, 
X                  unit[i].defend, unit[i].moves_left);
X              break;
X  
X  	case CP:
X! 	    DISPLAY5(16, "%s CP (%d/%d D%d M%d)", action,
X                  unit[i].attack, unit[i].range, 
X                  unit[i].defend, unit[i].moves_left);
X  	    break;
X+ 
X+         default:
X+             broken("Internal error in describe_action!");
X+ 	    
X      }
X  
X  }
//go.sysin dd *
echo x - ogre.6.pat
sed 's/^X//' > ogre.6.pat << '//go.sysin dd *'
X*** ogre.6.dist	Mon Jul 27 20:28:20 1987
X--- ogre.6	Fri Jul 31 19:34:32 1987
X***************
X*** 3,9 ****
X  .SH NAME
X  Ogre - a game of tank warfare in the 21st century.
X  .SH SYNOPSIS
X! /usr/games/ogre [ogre type (3 or 5)]
X  .SH DESCRIPTION
X  .PP
X  Ogre is a game of tank warfare in the 21st century.  You command a force of
X--- 3,9 ----
X  .SH NAME
X  Ogre - a game of tank warfare in the 21st century.
X  .SH SYNOPSIS
X! /usr/games/ogre [ogre type (3, 4 or 5)]
X  .SH DESCRIPTION
X  .PP
X  Ogre is a game of tank warfare in the 21st century.  You command a force of
X***************
X*** 32,40 ****
X--- 32,42 ----
X              place a:
X  
X          H   howitzer
X+         B   mobile howitzer
X          T   heavy tank
X          M   missile tank
X          G   GEV
X+         L   light tank
X          1   1 infantry unit
X          2   2 infantry units
X          3   3 infantry units
X***************
X*** 108,114 ****
X  5) Second movement phase for GEVs.  Just like step 3, except that only GEVs
X  can move.
X  .PP
X! 6) The Ogre moves.  If it runs over any of your units, they are damaged
X  or destroyed.
X  .PP
X  7) The Ogre fires at all units in range.  Destroyed units are removed from
X--- 110,116 ----
X  5) Second movement phase for GEVs.  Just like step 3, except that only GEVs
X  can move.
X  .PP
X! 6) The Ogre moves.  If it runs over any of your units, they may be disabled
X  or destroyed.
X  .PP
X  7) The Ogre fires at all units in range.  Destroyed units are removed from
X***************
X*** 131,138 ****
X  The display "a/r Dd Mm" means the unit concerned attacks at a, at range r,
X  defends at d, and moves m hexes per turn.
X  .PP
X! The Ogre by default is a Mark III.  An argument of '5' on the command line
X! makes it a Mark V, and gives you more armor points.
X  .PP
X  The game can be interrupted at any point with a control-C.  There's now
X  no way to restart.
X--- 133,140 ----
X  The display "a/r Dd Mm" means the unit concerned attacks at a, at range r,
X  defends at d, and moves m hexes per turn.
X  .PP
X! The Ogre by default is a Mark III.  An argument of '4' or '5' on the command
X! line makes it a Mark IV or Mark V, and gives you more armor points.
X  .PP
X  The game can be interrupted at any point with a control-C.  There's now
X  no way to restart.
X***************
X*** 153,155 ****
X--- 155,159 ----
X  .PP
X  The Ogre sometimes gets confused and doesn't know where to go, so it
X  oscillates from one hex to another, and then back.
X+ 
X+ Ogre Mark IVs don't use their missilies as effectively as they could.
//go.sysin dd *
echo x - ogre.h.pat
sed 's/^X//' > ogre.h.pat << '//go.sysin dd *'
X*** ogre.h.dist	Mon Jul 27 20:28:21 1987
X--- ogre.h	Fri Jul 31 18:13:07 1987
X***************
X*** 17,22 ****
X--- 17,23 ----
X  typedef struct {
X  
X      char    missiles;
X+     char    missracks;
X      char    main_bats;
X      char    sec_bats;
X      char    ap;
X***************
X*** 26,31 ****
X--- 27,33 ----
X      char    l_hex;
X      char    r_hex;
X      char    init_treads;
X+     char    init_move;
X      char    where;
X  
X  } OGRE;
X***************
X*** 33,45 ****
X  /* unit types */
X  
X  #define CP          'C'
X  #define HVYTANK     'T'
X  #define MSLTANK     'M'
X  #define GEV         'G'
X! #define HOWITZER    'H'
X  #define INFANTRY    'I'
X  
X  
X  /* unit statuses */
X  #define OK          1
X  #define DISABLED    2
X--- 35,63 ----
X  /* unit types */
X  
X  #define CP          'C'
X+ #define HOWITZER    'H'
X+ #define MHWZ        'B'
X  #define HVYTANK     'T'
X  #define MSLTANK     'M'
X  #define GEV         'G'
X! #define LTTANK      'L'
X  #define INFANTRY    'I'
X  
X+ /* display macros */
X  
X+ #define DISPLAY0(l,f)	movecur(l,0);eeol();printf(f)
X+ #define DISPLAY1(l,f,ar)	movecur(l,0);eeol();printf(f,ar)
X+ #define DISPLAY2(l,f,ar1,ar2)	movecur(l,0);eeol();printf(f,ar1,ar2)
X+ #define DISPLAY3(l,f,ar1,ar2,ar3)	movecur(l,0);eeol();printf(f,ar1,ar2,ar3)
X+ #define DISPLAY4(l,f,ar1,ar2,ar3,ar4)	movecur(l,0);eeol();printf(f,ar1,ar2,ar3,ar4)
X+ #define DISPLAY5(l,f,ar1,ar2,ar3,ar4,ar5)	movecur(l,0);eeol();printf(f,ar1,ar2,ar3,ar4,ar5)
X+ 
X+ #define DISPLAY_XY1(l,c,f,ar)	movecur(l,c);eeol();printf(f,ar)
X+ #define DISPLAY_XY2(l,c,f,ar1,ar2)	movecur(l,c);eeol();printf(f,ar1,ar2)
X+ #define DISPLAY_XY3(l,c,f,ar1,ar2,ar3)	movecur(l,c);eeol();printf(f,ar1,ar2,ar3)
X+ #define DISPLAY_XY4(l,c,f,ar1,ar2,ar3,ar4)	movecur(l,c);eeol();printf(f,ar1,ar2,ar3,ar4)
X+ #define DISPLAY_XY5(l,c,f,ar1,ar2,ar3,ar4,ar5)	movecur(l,c);eeol();printf(f,ar1,ar2,ar3,ar4,ar5)
X+ 
X  /* unit statuses */
X  #define OK          1
X  #define DISABLED    2
X***************
X*** 62,68 ****
X  
X  #define N_UNITS     47
X  
X! #define DEF_MISSILES    3
X  #define DEF_MAIN        4
X  #define DEF_SECONDARY   3
X  #define DEF_AP          1
X--- 80,86 ----
X  
X  #define N_UNITS     47
X  
X! #define DEF_MISSILES    4
X  #define DEF_MAIN        4
X  #define DEF_SECONDARY   3
X  #define DEF_AP          1
//go.sysin dd *
echo x - ogrecom.c.pat
sed 's/^X//' > ogrecom.c.pat << '//go.sysin dd *'
X*** ogrecom.c.dist	Mon Jul 27 20:28:24 1987
X--- ogrecom.c	Fri Jul 31 17:49:14 1987
X***************
X*** 5,10 ****
X--- 5,14 ----
X  
X  #include "ext.h"
X  
X+ #define INCR(i) i = (i == n_units - 1) ? 0 : i + 1
X+ 
X+ #define MIN(a, b) (((a) < (b)) ? (a) : (b))
X+ 
X  move_ogre()
X  {
X  
X***************
X*** 62,68 ****
X          osccnt = 0;
X      oscdir = max;
X  
X! /* display(17, "max %d weight %d cnt %d odir %d ndir %d",
X  	max, weight[max], osccnt, oscdir, mapdir[oscdir]);
X     cycle(); */
X  
X--- 66,72 ----
X          osccnt = 0;
X      oscdir = max;
X  
X! /* DISPLAY5(17, "max %d weight %d cnt %d odir %d ndir %d",
X  	max, weight[max], osccnt, oscdir, mapdir[oscdir]);
X     cycle(); */
X  
X***************
X*** 133,139 ****
X      int to_target;
X      int i;
X  
X!     total_attacks = ogre.missiles + ogre.main_bats + ogre.sec_bats;
X  
X      for(i = 1; i < n_units; i++) {
X  
X--- 137,144 ----
X      int to_target;
X      int i;
X  
X!     total_attacks = MIN(ogre.missracks, ogre.missiles)
X!                     + ogre.main_bats + ogre.sec_bats;
X  
X      for(i = 1; i < n_units; i++) {
X  
X***************
X*** 153,159 ****
X  
X          if(total_attacks <= 0) continue;
X  
X!         if(to_target <= RANGE_MISSILES && ogre.missiles > 0) {
X              weight += unit[i].attack;
X              weight += 4 - unit[i].movement;
X              total_attacks -= 1;
X--- 158,165 ----
X  
X          if(total_attacks <= 0) continue;
X  
X!         if(to_target <= RANGE_MISSILES
X!                 && MIN(ogre.missracks, ogre.missiles) > 0) {
X              weight += unit[i].attack;
X              weight += 4 - unit[i].movement;
X              total_attacks -= 1;
X***************
X*** 191,197 ****
X  
X      if(off_map(a, b) || blocked(a, b)) weight = - INFINITY;
X  /*
X! display(17, "%d %d weight %d", a, b, weight); cycle();
X  */
X  
X      return(weight);
X--- 197,203 ----
X  
X      if(off_map(a, b) || blocked(a, b)) weight = - INFINITY;
X  /*
X! DISPLAY3(17, "%d %d weight %d", a, b, weight); cycle();
X  */
X  
X      return(weight);
X***************
X*** 198,207 ****
X  
X  }
X  
X- #define INCR(i) i = (i == n_units - 1) ? 0 : i + 1
X- 
X- #define MIN(a, b) (((a) > (b)) ? (a) : (b))
X- 
X  /* 
X      Figure out who the Ogre will fire at. In this code, the "fired" element
X      of the unit description is the number of hit points assigned against that
X--- 204,209 ----
X***************
X*** 272,278 ****
X  
X      unitno = nextunit(RANGE_MISSILES, unitno);
X  
X!     nmissiles = ogre.missiles;
X  
X      for(i = 0; i < nmissiles; i++) {
X  
X--- 274,280 ----
X  
X      unitno = nextunit(RANGE_MISSILES, unitno);
X  
X!     nmissiles = MIN(ogre.missracks, ogre.missiles);
X  
X      for(i = 0; i < nmissiles; i++) {
X  
X***************
X*** 299,305 ****
X  {
X  
X      fflush(stdout);
X!     sleep(1);
X  
X  }
X  
X--- 301,307 ----
X  {
X  
X      fflush(stdout);
X!     sleep(2);
X  
X  }
X  
X***************
X*** 314,320 ****
X      /* No point if the unit is already destroyed. */
X      if(unit[target].status == DESTROYED) return;
X  
X!     display(16, "Ogre fires %s at unit at hex %d%d", weapon,
X          unit[target].l_hex, unit[target].r_hex);
X  
X      movecur_hex(unit[target].l_hex, unit[target].r_hex);
X--- 316,322 ----
X      /* No point if the unit is already destroyed. */
X      if(unit[target].status == DESTROYED) return;
X  
X!     DISPLAY3(16, "Ogre fires %s at unit at hex %d%d", weapon,
X          unit[target].l_hex, unit[target].r_hex);
X  
X      movecur_hex(unit[target].l_hex, unit[target].r_hex);
//go.sysin dd *
echo x - ogrestat.c.pat
sed 's/^X//' > ogrestat.c.pat << '//go.sysin dd *'
X*** ogrestat.c.dist	Mon Jul 27 20:28:26 1987
X--- ogrestat.c	Fri Jul 31 19:25:12 1987
X***************
X*** 19,50 ****
X                       1234567890123456789012345678901234567890       */
X  
X      if(redraw || last.main_bats != ogre.main_bats)
X!         if(ogre.main_bats > 0)
X!         display(18, "Main Batteries:      %d (4/3 D4)", ogre.main_bats);
X!         else display(18, " ");
X  
X      if(redraw || last.sec_bats != ogre.sec_bats)
X!         if(ogre.sec_bats > 0)
X!         display(19, "Secondary Batteries: %d (3/2 D3)", ogre.sec_bats);
X!         else display(19, " ");
X  
X!     if(redraw || last.missiles != ogre.missiles)
X!         if(ogre.missiles > 0)
X!         display(20, "Missiles:            %d (6/5 D3)", ogre.missiles);
X!         else display(20, " ");
X  
X      if(redraw || last.ap != ogre.ap)
X!         if(ogre.ap > 0)
X!         display(21, "Anti-personnel:     %2d (1/1 D1)", ogre.ap);
X!         else display(21, " ");
X  
X      if(redraw || last.treads != ogre.treads)
X!         if(ogre.treads > 0)
X!         display(22, "Treads:             %2d (1/* D1)", ogre.treads);
X!         else display(22, " ");
X  
X!     if(redraw || last.movement != ogre.movement)
X!         display(23, "Movement:            %d", ogre.movement);
X  
X      copy(&last, &ogre, sizeof(last));
X  
X--- 19,52 ----
X                       1234567890123456789012345678901234567890       */
X  
X      if(redraw || last.main_bats != ogre.main_bats)
X!         if(ogre.main_bats > 0) {
X!         DISPLAY1(18, "Main Batteries:      %d (4/3 D4)", ogre.main_bats);
X!         } else { DISPLAY0(18, " ");}
X  
X      if(redraw || last.sec_bats != ogre.sec_bats)
X!         if(ogre.sec_bats > 0) {
X!         DISPLAY1(19, "Secondary Batteries: %d (3/2 D3)", ogre.sec_bats);
X!         } else { DISPLAY0(19, " ");}
X  
X!     if(redraw || last.missiles != ogre.missiles
X!             || last.missracks != ogre.missracks)
X! 	if(ogre.missracks > 0 && ogre.missiles > 0) {
X!         DISPLAY2(20, "Missiles: %-2d  Racks: %d (6/5 D4)",
X! 		ogre.missiles, ogre.missracks);
X!         } else { DISPLAY0(20, " "); }
X  
X      if(redraw || last.ap != ogre.ap)
X!         if(ogre.ap > 0) {
X!         DISPLAY1(21, "Anti-personnel:     %2d (1/1 D1)", ogre.ap);
X!         } else { DISPLAY0(21, " ");} 
X  
X      if(redraw || last.treads != ogre.treads)
X!         if(ogre.treads > 0) {
X!         DISPLAY1(22, "Treads:             %2d (1/* D1)", ogre.treads);
X!         } else { DISPLAY0(22, " ");}
X  
X!     if(redraw || last.movement != ogre.movement) {
X!         DISPLAY1(23, "Movement:            %d", ogre.movement);}
X  
X      copy(&last, &ogre, sizeof(last));
X  
//go.sysin dd *
echo x - resolve.c.pat
sed 's/^X//' > resolve.c.pat << '//go.sysin dd *'
X*** resolve.c.dist	Mon Jul 27 20:28:28 1987
X--- resolve.c	Fri Jul 31 17:28:04 1987
X***************
X*** 57,67 ****
X  OGRE *allocations;
X  {
X  
X!     display(16, "Resolving..."); cycle();
X  
X      if(allocations -> missiles > 0) {
X          if(crt[roll()][odds(allocations -> missiles, DEF_MISSILES)] ==
X!             DESTROYED) ogre.missiles -= 1;
X      }
X  
X      if(allocations -> main_bats > 0) {
X--- 57,71 ----
X  OGRE *allocations;
X  {
X  
X!     DISPLAY0(16, "Resolving..."); cycle();
X  
X      if(allocations -> missiles > 0) {
X          if(crt[roll()][odds(allocations -> missiles, DEF_MISSILES)] ==
X!             DESTROYED) {
X!             ogre.missracks -= 1;
X!             ogre.missiles -= 1;
X!         }
X! 	
X      }
X  
X      if(allocations -> main_bats > 0) {
X***************
X*** 213,220 ****
X      ogre.treads  -= attack;
X      ogre.movement = 0;
X      if(ogre.treads > 0)  ogre.movement = 1;
X!     if(ogre.treads > ogre.init_treads / 3) ogre.movement = 2;
X!     if(ogre.treads > 2 * ogre.init_treads / 3) ogre.movement = 3;
X  
X  }
X  
X--- 217,225 ----
X      ogre.treads  -= attack;
X      ogre.movement = 0;
X      if(ogre.treads > 0)  ogre.movement = 1;
X!     if(ogre.treads > ogre.init_treads / ogre.init_move) ogre.movement = 2;
X!     if(ogre.treads > (2 * ogre.init_treads)/ ogre.init_move) ogre.movement = 3;
X!     if(ogre.treads > (3 * ogre.init_treads)/ ogre.init_move) ogre.movement = 4;
X  
X  }
X  
//go.sysin dd *
exit
---
arpanet: dupuy@columbia.edu
uucp:	...!seismo!columbia!dupuy