WAR and PIECES

The simplest definition of a pieces is "the little cardboard counters
you move around on the map."  In other words, they are the mobile and
mutable objects which you and your opponents command.  You may
remember our definition of a WarGame as "force applied through space
and time".  In keeping with that, I would like to discuss pieces in
those components.  Note that not all pieces need to support all these
protocols:


			       A.  Time

This is a very simple protocol:

@protocol Clockable
	-(float) tick:(float)time;
@end

Basically, a piece gets a clock tick, which (optionally) tells it what
the current time is.  The piece is responsible for knowing what (if
anything) it is supposed to do at that time.  It may be something as
simple as "reset yourself since the turn has ended", or as complex as
"move along a path towards the nearest enemy, and fire when within
range".  All that information is encapsulated.

I do not think we need a protocol for a Clock, since it is either an
integral part of the game or called directly from the user interface.
More likely, we can just have sample WarClock classes.

			      B.  Space

A piece needs to know what region it is in:

	-<region>region;

since that is how it and others find out their location.

A piece also needs to know how to move.  There may not be a general
mechanism, but keeping track of movement points is an exceedingly
common one, and probably worthy of a protocol.

@protocol <MovementPoints>
	- (float) MP; // current value
	- (float) setMP:(float)amount;
	- (float) subMP:(float)amount;
	- (float) calcMP:(float)length across:<Terrain>terrain;
	- (float) checkMP:(float)length across:<Terrain>terrain;
	- (float) moveMP:(float)length across:<Terrain>terrain;
	- (float) maxMP; // maximum value
	- (float) resetMP; // reset, return maximum value
@end

All these routines return the current MP level, except for "checkMP"
which returns the amount left (possibly negative) if the move  were to
be taken.  Note, as usual, that terrain can be 'nil' where it doesn't
matter.  Yes, checkMP and moveMP are redundant, but sending messages
can be expensive across a connection, so its worthwhile to optimize
common behavior like this (I think).

			      C.  Force

There are three principal ways pieces interact with each other.  Of
course, more complicated pieces will have many more methods, but these
are the 'core' of a wargame piece.

@protocol Sensor <WarMap>
	-<space> space;
	-<space> spaceAt:Location;
@end

A Sensor is used to locate other pieces.  It basically does its work
by calling the "fill:in:" method of Region.  Actually, I think that
should be:
	Region -fill:<WarMap> in:<WarSpace>;

and Sensor is just a WarMap that overrides "place:at:".  After all,
isn't a sensor just something that creates an internal representation
of the outside world?  Since the Sensor stores the location, it can
even introduce errors (for inaccurate sensors).

I think Sensor "isa" WarMap instead of 'hasa', but I could be wrong.
I think it "hasa" WarSpace (its effective range), which should be set
relative to the current location.  I don't think they are is any other
general information.  There could sometimes be fields for sensor
types, but that information could just come from the class hierarchy.

Combat

I view combat as being initiated by the attacker, but managed by the
defender.

The attacking piece first determines that the intended victim is
within range of the given weapon (using a sensor).  Then the victim
(defender) is told it is being attacked by that weapon.  The victim
then queries the attacker for various characteristics, then takes the
damage.  It returns a float, which can be the damage done to the
attacker.

@protocol Defender
	-(float) sensedBy:<Sensor>sense at:(Location)location;
	// could just be a BOOL yes/no
	-(float) attackedBy:<Attacker>attack at:(Location)location;
	// controls the flow of battle
	// returns damage to attacker?
	-(float) inflict:(float)damage;
	// separate method, so can be called by others
@end

@protocol Attacker
	- (float) strength:sender;
	- (float) skill:sender;
@end

This may seem pretty simplistic, but I think it is quite general.  For
instance, I think this protocol is powerful enough to support full
champions combat [if restricted to killing attacks].  Most information
that can be easily parametrized is contained in these methods.  Other
information tends to be "isKindOf" queries.

Note that a piece may not respond to the "Attacker" protocol itself,
but have sub-objects (i.e., weapons) which it uses to attack.

			      D. Summary

As a truism, I think it is true that every piece has to be capable of
being attacked.  So the 'basic' piece is:

@protocol WarPiece <Defender>
	-(Location)location;
	//even if not stored locally, want to be able to find out
	-<region>region;
	-(int)owner;
@end

The owner entry is simply a quick way to check whose side you are own.
Since we are potentially dealing with remote object proxies, we can
not guarantee that the 'id' of a player object would be the same. And
ints are easy and cheap to compare.  Note that the owner could refer
to an internal variable, for pieces which can change sides in the
course of play.

			      E. Example

Let me try to give a quick example of how these protocols might be
used.  This is not meant to be definitive, merely one small
possibility to show what the protocols are capable of.

Assume senseMap adds any pieces that respond to 'sensedBy:' with a
non-zero value.  Note that many methods are omitted for simplicity.


@class Defending <Clockable>
{
	float dcv; // Defense Combat skill
	float health; // decremented by inflict, restored by tick.
	id random;
}

// Uses champion-style rules
// Assumes the existence of a Random class

- (float) attackedBy:<Attacker>attacker at:loc
{
	float ocv = [attacker skill:self];
	if (![random erf:(ocv - dcv)]) return 0.0;
// erf = error function [for a normal distribution]
// basically rolls a random number, returns true or false
	
	float damage = [random d6:[attacker strength:self] ];
// assumes strength is number of dice of damage

	[self inflict:damage]; //ouch, applies armor et al.
	// can even take care of hit locations and so forth

	return 0.0;
	// Pure defender, can't hit back
}

@class Attacking  : Defending
{
	id<Sensor> senseMap;
	id weapons;
	int currentWeapon;  // next usable weapon
}

- (int) attackFrom:loc
// takes current location as an argument
// returns number of things attacked
{	
	id targets;
	int i, n;

	[[self region]	fill:senseMap in:[senseMap spaceAt:loc]];
	// assume that all weapons use the same sensor
	targets = [senseMap pieces];
	n = [targets count];
	for (i=0, i < n; ++i) {
	  id weapon;
	  float damage;
	  id target = [targets objectAt:i];
	
	  if ([target owner] == [self owner]) continue;
		// don't attack your allies!
	  weapon = [weapons objectAt:currentWeapon++];
	  if (!weapon) break;
	  damage = [target attackedBy:weapon at:loc];
	  if (damage) [self inflict:damage];
	  if (health < 0) return i;
	}
	return i;
}

// Attacking classes hit back!
// assume it gets automatic hit if in range, and has a weapon

- (float) attackedBy:<Attacker>attacker at:loc
{
	Location diff = [self location] - loc;
	id weapon  = [weapons objectAt:currentWeapon];
	[super attackedBy:attacker at:loc];
	
	if (diff.mag() < [weapon range]) {
	  ++currentWeapon;
	  return [random d6:[weapon strength:attacker]];
	} 
	return 0.0;
}	

@end


This is an extremely crude and incomplete example.  However, I hope it
at least gives you a feel for what we are working towards.  It
probably also indicates we need to start doing actual implementations,
to start beating our theoretical speculations into some correspondence
with reality.

First, though, we have to figure out how to deal with the user...