function square ( l, obj )
{
  if ( l[0] < 0 || l[0] >= this.width || l[1] < 0 || l[1] >= this.height ) { return null }
  if ( ( ! this.map ) || ( ! this.map[l[1]] ) ) { return null }
  if ( obj ) {
     return this.mapLinks[l[1]][l[0]]; 
  }
  else
  {
    return this.map[l[1]][l[0]]; 
  }
}

function lineOfSite( pos1, pos2 )
{
  if ( this.losCache[pos1[0]+'x'+pos1[1]+':'+pos2[0]+'x'+pos2[1]] != null )
  {
    return this.losCache[pos1[0]+'x'+pos1[1]+':'+pos2[0]+'x'+pos2[1]];
  }
  
  var d = [ pos1[0] - pos2[0],
  pos1[1] - pos2[1] ]

      var slope = d;

  if ( ! ( slope[0] && slope[1] ) )
  {
    slope = [ slope[0] ? slope[0] / Math.abs(slope[0]) : 0 ,
    slope[1] ? slope[1] / Math.abs(slope[1]) : 0 ];
  }
  else if ( Math.abs(slope[0]) > Math.abs(slope[1]) )
  {
    slope = [ slope[0] / Math.abs(slope[0]),
    slope[1] / Math.abs(slope[0]) ];
  }
  else
  {
    slope = [ slope[0] / Math.abs(slope[1]),
    slope[1] / Math.abs(slope[1]) ];

  }

  var cur = [ pos1[0], pos1[1] ];
  var res = true;
  var count = 0;

  while ( ( Math.round(cur[0]) != pos2[0] || Math.round(cur[1]) != pos2[1] ) && res )
  {
    cur[0] -= slope[0];
    cur[1] -= slope[1]; 
 
    var check = [];    

    for ( var x = Math.floor(cur[0]); x <= Math.ceil(cur[0]); x++ )
    {
      for ( var y = Math.floor(cur[1]); y <= Math.ceil(cur[1]); y++ )
      {
        check[check.length] = [x,y];
      }
    }
  
    var count = 0;
    for ( var i = 0; ( i < check.length ) && res; i++ )
    { 
      if ( this.buildingData[ this.square(check[i]) ] 
	    && this.buildingData[ this.square(check[i]) ].seeThrough ) { continue }
      if ( this.square( check[i] ) == null ) { continue }				  
      if ( 
            ( check[i][0] != pos2[0] || check[i][1] != pos2[1] ) 
         && ( this.square(check[i]) != this.square(pos1) )
		  ) 
      { 
        count++;        
      }
      if ( count > ( check.length / 4 ) ) { res = false }
    } 
         
  }

  this.losCache[pos1[0]+'x'+pos1[1]+':'+pos2[0]+'x'+pos2[1]] = res;  
  
  return(res);   
}

function dis( pos1, pos2 )
{ 
  return ( Math.sqrt( ( ( pos1[0] - pos2[0] ) * ( pos1[0] - pos2[0] ) ) 
      + ( ( pos1[1] - pos2[1] ) * ( pos1[1] - pos2[1] ) ) ) ); 
}

function moveTo( l )
{  

  var d = dis( this.location, l );

  var oldHome = this.map.square( this.location , true);
  var newHome = this.map.square( l , true);
    
  if ( d >= 2 ) { return }

  if ( newHome.sqData.noEnter ) { return }    
  var moved = false;
  if ( newHome.buildingID == oldHome.buildingID )
  { 
    moved = true; 
  }
  else
  {
    if ( newHome.sqData.autoJump ) 
    { 
      moved = true;  
    }
    else
    {
      if ( oldHome.sqData.autoJump ) 
      {
        if ( this.test('enterBuilding') ) { moved = true; }
      }
      else if ( this.test('jumpBuilding') )
      {
        moved = true;
      }          
    }
  }
  if ( ! moved ) { return }
  this.location = l;     
  newHome.appendChild( this.marker );
  
  if ( this.typeOf == 'player' )
  {
    var leftShift = ( this.map.win.offsetWidth / 2 ) - ( ( this.location[0] * 40 ) + 16 ) - ( this.marker.offsetWidth / 2 );
    var topShift  = ( this.map.win.offsetHeight / 2 ) - ( ( this.location[1] * 40 ) + 16 )- ( this.marker.offsetHeight / 2 );

    this.map.layer.style.left =  leftShift + 'px';
    this.map.layer.style.top  =  topShift  + 'px';
  
    oldHome.updateView( false );
    newHome.updateView( true );
    
  }
}

function test( skill, mods )
{
  mods = mods == null ? 0 : mods;
  if ( this.map.damageMods[skill] )
  {
    for ( var i = 0; i < this.map.damageMods[skill].length; i++ )
    {
      mods += this.damageTotal( this.map.damageMods[skill][i] );
    }
  }

  if ( this.skills[skill] == null ) { return false }
  var roll = rnd( 100 );
  var modSkill = this.skills[skill] - mods;

  var pass = ( roll <= modSkill || roll == 0 );

  if ( ! pass ) 
  {
    if ( this.map.los( this.map.player.location, this.location ) 
	&& this.map.messages.skills[skill] 
	&& this.map.messages.skills[skill][this.typeOf]
    && this.map.messages.skills[skill][this.typeOf].fail )
    {
      message( this.map.messages.skills[skill][this.typeOf].fail[rnd( this.map.messages.skills[skill][this.typeOf].fail.length )] );
    }
  }
  else
  {
    if ( this.map.los( this.map.player.location, this.location ) 
	&& this.map.messages.skills[skill] 
	&& this.map.messages.skills[skill][this.typeOf]
    && this.map.messages.skills[skill][this.typeOf].pass )
    {
      message( this.map.messages.skills[skill][this.typeOf].pass[rnd( this.map.messages.skills[skill][this.typeOf].pass.length )] );
    }
    
    pass = modSkill - roll;
  }
  if ( this.skills.learn && ( rnd(100)<= this.skills.learn ) )
  {
    this.learn( skill );
    this.learn( 'learn' );
  }

  return ( pass );
}

function learn( skill )
{
  var roll = rnd(100);
  if ( roll == 100 || roll > this.skills[skill] )
  {
    this.skills[skill]++;
    if ( this.map.messages.skills[skill] && this.map.messages.skills[skill][this.typeOf]
    && this.map.messages.skills[skill][this.typeOf].learn )
    {
      message( this.map.messages.skills[skill][this.typeOf].learn[rnd( this.map.messages.skills[skill][this.typeOf].learn.length )] );
    }
  }
}

function surround( x, y )
{

  var list = [];
  for ( var i = -1; i < 2; i++ )
  {
    for ( var j = -1; j < 2; j++ )
    {
      if ( ( Math.abs(i) || Math.abs(j) )
      && ( x+i >= 0 && x+i < this.width && y+j >= 0 && y+j < this.height ) )
      {
        list[list.length] = [x+i,y+j];
      }	 
    }
  }
  return list;
}

function message ( message )
{
  var div = document.createElement( 'DIV' );
  div.appendChild(document.createTextNode(message));
  var mb = document.getElementById('messageBlock');
  mb.appendChild(div); 
  if ( mb.scrollHeight > mb.offsetHeight )
  {
      mb.scrollTop = mb.scrollHeight - mb.offsetHeight;
  }
}

function messageFlush()
{
  var mb = document.getElementById('messageBlock');
  for ( var i = 0; i < mb.childNodes.length; i++ )
  {
    var t = mb.childNodes[i]
    if ( t.nodeName == 'DIV' )
    {
      if ( t.className == 'last' ) { t.className = 'old' }
      if ( t.className != 'last' && t.className != 'old' ) { t.className = 'last' }
    }
  }    
}

function checkSee( vals )
{
  var start = vals[0];
  var loc = vals[1];
  var checked = vals[2];
  var range = vals[3];
  
  if ( range == null ) { range = 100 }

  if ( checked[loc[0]+'x'+loc[1]] ) { return [[],checked] }

  checked[loc[0]+'x'+loc[1]] = 1;

  var newlist = [];

  var see = this.los( start, loc );

  if ( see && ( dis( start, loc ) < range ) )
  {
    newlist[newlist.length] = this.square(loc,true);
  }
  else
  {
    return( [ [], checked ] );
  }

  var checklist = this.surround( loc[0], loc[1] );

  for ( var i = 0; i < checklist.length; i++ )
  {
    var res = this.checkView( [ start, checklist[i], checked, range ] );
    var reslist = res[0];
    var newcheck = res[1];
    for ( var j = 0; j < reslist.length; j++ )
    {
      newlist[newlist.length] = reslist[j];
    }
    for ( var c in newcheck ) { checked[c] = newcheck[c] }
  }

  return [ newlist, checked ];
}

function tn( text )
{
	return document.createTextNode( text );
}

function br()
{
	return document.createElement( 'br' );
}

function describe()
{
  this.describeWindow.innerHTML = '';

  var p = document.createElement( 'P' );
  this.describeWindow.appendChild( p );
  
  p.appendChild(tn('You are standing '));
  if ( this.square( this.player.location ) == null )
  {
     p.appendChild(tn(' on a road.'));
  }
  else
  {
	if ( this.buildingData[ this.square( this.player.location ) ] 
	&& this.buildingData[ this.square( this.player.location ) ].inside )
	{
		p.appendChild(tn(this.buildingData[ this.square( this.player.location ) ].inside));
	}
	else
	{
		p.appendChild(tn(' in a building.'));
	}
  }

  if ( this.player.damage.length > 0 )
  {
	 p.appendChild(br());
	 p.appendChild(tn('You have ' ));
 
     var list = [];
	 for ( var x in this.player.damage )
	 {
		var sp = document.createElement('SPAN');
		sp.className = 'selectRange';
		sp.title = 'Apply first aid';
		sp.wound = x;
		sp.target = this.player;
		sp.onclick = bandage;
		sp.appendChild(tn(this.player.damage[x].description))
	    list[list.length] = sp;
	 }
	 for ( var i = 0; i < list.length; i++ )
	 {
	   p.appendChild( list[i] );
	   if ( list.length > 1 && i != list.length - 1) 
	   {
		 if ( i != list.length - 2 )
		 {
		   p.appendChild( tn(', ') );
		 }
		 else
		 {
		   p.appendChild( tn(' and ') );
		 }
	   }
	 }

  }
  
  var equipped = this.player.listItems( 'equipped' );
  if ( equipped.length > 0 )
  {
	 var list = [];
	 for ( var x in equipped )
	 {
	   var desc = equipped[x].description;
	   if ( equipped[x].ammo != null ) { desc += ' ('+equipped[x].ammo+')' }
	   list[list.length] = desc;
	 }
	 var end = list[list.length-1];
	 list.length--;
	 
	 var ds = list.join( ', ');
	 if ( ds ) { ds = ds + ' and '+end; }
	 else { ds = end }
	 p.appendChild(br());
	 p.appendChild(tn('You are using '+ds));
  }
  
  var carried = this.player.listItems( 'carried' );
  if ( carried.length > 0 )
  {
	 var list = [];
	 for ( var x in carried )
	 {
	   var desc = carried[x].description;
	   if ( carried[x].ammo != null ) { desc += ' ('+carried[x].ammo+')' }
	   list[list.length] = desc;
	 }
	 var end = list[list.length-1];
	 list.length--;
	 
	 var ds = list.join( ', ');
	 if ( ds ) { ds = ds + ' and '+end; }
	 else { ds = end }
	 p.appendChild(br());
	 p.appendChild(tn('You are carrying '+ds));
  }

} 
 
function bandage()
{
  var check = ['pain', 'upper', 'lower' ];
  var mod = 0;
  for ( var x in check )
  {
    mod += this.target.damage[this.wound][check[x]];
  }
  if ( this.target.test( 'first aid', mod ) )
  {
	var list = [];
	for ( var x in this.target.damage )
	{
		if ( x != this.wound ) 
		{
			var o = new Object;
			for ( var i in this.target.damage[x] )
			{
				o[i] = this.target.damage[x][i];
			}
			list[list.length] = o; 
		}
	}
	this.target.damage = list;
  }
  this.target.map.refresh();
}
 
function createMap( win, describer )
{
  // display the intro
  this.intro = true;
  this.win = win;
  this.describeWindow = describer;
  win.gameData = this;
      var layer = document.createElement( 'DIV' );  
  layer.id = 'mapLayer';
  layer.style.width = (this.width * 40) + 'px';
  layer.style.height = (this.height * 40) + 'px';
  layer.style.top = '0px';
  layer.style.left = '0px';
  win.appendChild( layer );
  this.layer = layer;
    
  for ( var y=0;y < this.height; y++)
  { 
    this.mapLinks[y] = new Array;
    for ( var x = 0;x < this.width; x++ )
    {
      var sq = document.createElement( 'DIV' );
      sq.xPos = x;
      sq.yPos = y;
      sq.map = this;
      sq.sqData = new Object;

      sq.buildingID = this.map[y][x]; 
      for ( var i in this.buildingData.def )
      {
        if ( this.buildingData[sq.buildingID] && this.buildingData[sq.buildingID][i] != null )
        {
          sq.sqData[i] = this.buildingData[sq.buildingID][i];
        }
        else
        {
          sq.sqData[i] = this.buildingData.def[i];
        }
      } 
            
      if ( ! this[sq.sqData.type] )
      {
        this[sq.sqData.type] = new Array;
      }
      this.squares[this.squares.length] = sq;
      this[sq.sqData.type][this[sq.sqData.type].length] = sq;
      
      sq.onclick = function () 
        {   this.map.player.moveTo( [ this.xPos, this.yPos ] ); 
            this.map.refresh() };
      sq.id= x+"x"+y;
      sq.setClass = function( see ) { 
        if ( see ) { this.seen = true }
        var st = 'square ';
        if ( this.seen ) { st = st + ' seen ' }
        st = st + ' ' + this.sqData.type;
        if ( see ) { st = st + 'canSee visible' } 
        
         this.className = st;  
      }
      sq.updateView = function( see ) {
        var loc = [ this.xPos, this.yPos ];
          var los = this.map.checkView( [ loc, loc, {}, this.map.player.skills.viewDistance ] )[0];
          for ( var x in los )
          {
            los[x].setClass( see );
          }
      }
           
      sq.setClass();  
      layer.appendChild( sq );  
      this.mapLinks[y][x] = sq;
      sq.seen = false;
      sq.title = sq.sqData.outside;
      
      
      if ( this.square([x-1,y]) == this.square([x,y]) )
      {
        sq.style.borderLeft = '0px';
        sq.style.paddingLeft = '3px';
      }
      if ( this.square([x+1,y]) == this.square([x,y]) )
      {
        sq.style.borderRight = '0px';
        sq.style.paddingRight = '3px';
      }
      if ( this.square([x,y-1]) == this.square([x,y]) )
      {
        sq.style.borderTop = '0px';
        sq.style.paddingTop = '3px';
      }
      if ( this.square([x,y+1]) == this.square([x,y]) )
      {
        sq.style.borderBottom = '0px';
        sq.style.paddingBottom = '3px';
      }
    }
  }

  
  this.zombies = new Array;

  for ( var i = 0; i < 100; i ++ )
  {
    var brains = 10 + rnd(20);
    var hunger = 20 + rnd(50);
     
    this.zombies[i] = new Character ( { 'location':[3,3], 
      'skills':{'enterBuilding': brains - 20, 'brains': brains, 'hunger': hunger,
        'chase' : ( brains + hunger + rnd(20) ), 'shamble': ( brains + rnd(50) ), 
        'attack': ( hunger + rnd(25) ), 'learn': 0,
        'animation': ( brains + hunger ) * 2, 'punch':(20+rnd(30) ), 
        'bite':(20+rnd(30) )} 
        ,  'map':this, 'typeOf':'zombie', 'start':'road', 'inherent':['punch','bite']
    } );        
    this.zombies[i].moveTo( this.zombies[i].location );                                     
    this.zombies[i].drawMe(); 
    this.zombies[i].marker.onclick = displayAttacks;
  }
  
  this.player.moveTo( this.player.location );
  this.player.drawMe( 13, 13 );
  this.player.marker.className = 'character player x13 y13';
    
  this.refresh();
}

function updateMap( )
{
  var layer = this.layer;
  var win = this.win;
  
  for ( var i = 0; i < this.zombies.length ; i++ )
  {
    this.zombies[i].think();

  }

  if ( this.end && this.end() )
  {
	message('Congratulations. You have won.');
	this.player.damage.length = 0;
    messageFlush();
    this.describe();
	for ( var i = 0; i < this.squares.length; i++ )
	{
		this.squares[i].onclick = function () {};
    }
    for ( var i = 0; i < this.zombies.length; i++ )
    {
      this.zombies[i].marker.onclick = function () {};
    }
	
  }
  
  else if ( this.player.test( 'breath' ) )
  {
     messageFlush();
     this.describe();
  }
  else
  {
    message('You have died of your wounds.');
	messageFlush();
    for ( var i = 0; i < this.squares.length; i++ )
    {
      this.squares[i].onclick = function () {};
    }
    for ( var i = 0; i < this.zombies.length; i++ )
    {
      this.zombies[i].marker.onclick = function () {};
    }
    this.describeWindow.innerHTML = '';
  }

  if ( this.intro )
  {
	this.intro = false;
	var i = document.getElementById('intro');
	var out = document.createElement('H2');
	i.appendChild(out);
	out.appendChild( tn('Game Ready. Click to play') );
	out.tar = i;
	out.onclick = function(){ this.tar.style.display = 'none'; }
  }
}

function drawMe( x, y )
{
 
  if ( this.skills.animation != null && this.skills.animation == 0 ) { return }
  
  if ( ! this.marker.className )
  {
    this.marker.className = this.typeOf + ' character';
  }
  if ( ! x ) { x = rnd( this.marker.parentNode.clientWidth - this.marker.offsetWidth ) }
  if ( ! y ) { y = rnd( this.marker.parentNode.clientHeight - this.marker.offsetHeight ) }
  this.marker.className = this.typeOf + ' character' + ' x'+x+' y'+y;
}

function displayAttacks(e)
{
  if ( window.onclick ) { window.onclick(); }
  var person = this.self.map.player;
  var range = dis( this.self.location, person.location );
  var attackList = person.attacksAvailable( range );
  if ( attackList && attackList.length > 0)
  {
    var list = document.createElement( 'UL' );
    list.className = 'attackList';
    this.appendChild( list );
    for ( var i = 0; i < attackList.length; i++ )
    {
      var item = attackList[i];
      var li = document.createElement( 'LI' );
      li.appendChild( document.createTextNode( item.type ) );
      list.appendChild(li);
      li.person = person;
      li.zombie = this.self;
      li.item = item; 
      li.onclick = doAttack;
      window.targetZombie = this;
      window.onclick = clearAttacks;
      if ( ! e ) e = window.event;
      e.cancelBubble = true;
      if (e.stopPropagation) e.stopPropagation();
    }
    this.parentNode.appendChild(this);
    this.onclick = null;
  }
}

function doAttack()
{
  this.person.attack( this.zombie, this.item ); 
  var dam = 0;
  for ( var i in {'upper':1, 'lower':1} )
  {
    dam += this.zombie.damageTotal( i );
    dam = Math.floor( dam / 10 );
    dam = dam > 5 ? 5 : dam;
    var list = this.zombie.map.zombieDesc[dam];
    this.zombie.marker.title = list[rnd(list.length)];
  }
  window.onclick();
  this.zombie.map.refresh();
}

function clearAttacks(e)
{
  var div = this.targetZombie;
  if ( div )
  {
    for ( var i = 0; i < div.childNodes.length; i++ )
    {
      if ( div.childNodes[i].nodeName == 'UL' )
      {
        div.removeChild(div.childNodes[i]);
        div.onclick = displayAttacks;
      } 
    }
  }
  window.onclick = null;
  window.targetZombie = null;
  if ( ! e ) e = window.event;
  if ( e ) {
     e.cancelBubble = true;
     if (e.stopPropagation) e.stopPropagation();
  }
}

function rnd( x )
{
  return Math.floor( Math.random() * x );
}

function startIn( map, type )
{
  var list = map[type];
  var pos = rnd(list.length);
   
  return [list[pos].xPos, list[pos].yPos];
}

function brain()
{
  var cl = this.location;
  if ( this.skills.animation != 0 && ! this.test( 'animation' ) )
  { 
    this.marker.style.background = '#eee';
    this.marker.title = 'a dead body';
    this.skills.animation = 0;
    return; 
  }
  if ( this.skills.animation == 0 ) { return }
  
  var food = this.map.player;
  var pos = this.map.surround( this.location[0], this.location[1] );

  if ( dis( this.location, food.location ) == 0 && this.test( 'attack' ) )
  {
    var attacks = this.attacksAvailable();
     
    this.attack( food, attacks[rnd(attacks.length)] );
  }
  else if ( this.map.los( this.location, food.location ) && this.test( 'chase' ) )
  {
    var sh = 1000;
    var l = this.location;
    for ( var i=0; i < pos.length; i++ )
    {
      if ( dis( pos[i], food.location ) < sh )
      {
        l = pos[i]; 
        sh = dis( pos[i], food.location );
      } 
      this.moveTo( l );

    }      
  } 
  else if ( this.test('shamble' ) )
  {
    this.moveTo( pos[rnd(pos.length)] );
  }

  if ( ( this.location[0] != cl[0] || this.location[1] != cl[1] ) 
  && ( this.map.los( food.location, this.location ) ) 
  && ( dis( this.location, food.location ) <= food.skills.viewDistance ))
  {
    this.drawMe();
  }
}

function totalDamage( type )
{
  var t= 0;
  for ( var i = 0; i < this.damage.length; i++ )
  {
    if ( this.damage[i][type] )
    { 
      t+=this.damage[i][type];
    }
  }
  return t;  
}

function attacksAvailable( range )
{
  range = range == null ? 0 : range;
  var check = { 'inherent':true, 'equipped':true }
  var posList = this.listItems( check );
  var list = [];
  for ( var i = 0; i < posList.length; i++ )
  {
      var item = posList[i];
      if ( item.attack == true && item.range >= range && item.ammo != 0 )
      {
        list[list.length] = item;
      }
  }
  return list;      
}

function attack( who, item )
{
   // Defender gets to dodge.
  var mod = who.test('dodge');
  mod = mod ? mod : 0;

  // Range
  var range = dis ( this.location, who.location );
  range = Math.floor( range * 5 );
  mod = mod + range;
  
  if ( item.ammo != null )
  {
    if ( item.ammo == 0 ) { return }
    item.ammo--;   
    message( 'Your '+item.type + ' has '+item.ammo+' shots left.' );
  }
  
  var result = this.test( item.type, mod );
  if ( result )
  {
    result = result % 10 > 0 ? result % 10 : 1;
    var baseDamage = ( rnd(item.damage[1]) + item.damage[0] ) * result;
    var loc = rnd(100);
    if ( loc < 40 ) { loc = 'lower'; }
    else if ( loc < 80 ) { loc = 'upper'; }
    else { loc = 'head'; }

    var check = [ 'upper', 'lower', 'pain' ];
    var wound = {};
    for ( var i = 0; i < check.length; i++ )
    {
      wound[check[i]] = Math.floor( baseDamage * this.map.hitLocs[who.typeOf][loc][check[i]] );
    }

    var res = Math.floor(baseDamage / 10) > 5 ? 5 : Math.floor(baseDamage / 10);
    res = ( res > 0 ) ? res : 1;

    if ( this.map.damageDesc[who.typeOf] )
    {
      var base = this.map.damageDesc[who.typeOf].base[rnd( this.map.damageDesc[who.typeOf].base.length )];
      var damage = this.map.damageDesc[who.typeOf][loc][res][rnd( this.map.damageDesc[who.typeOf][loc][res].length )];
      message( base + damage + '.' );
      wound.description = damage;
    }
    who.damage[who.damage.length] = wound;

  }
}

function listItems( type )
{
    if ( typeof(type) == typeof('x') ) { var x = type; type = {}; type[x] = true; }
	else if ( type == null ) { type = {'equipped':true,'carried':true} };
    var list = [];
	for ( var i = 0; i < this.equipment.length; i++ )
	{
		var item = this.equipment[i];
		if ( type[item.location] )
		{
			list[list.length] = this.equipment[i];
		}
	}
	return list;   
}

function Item ( type, data )
{
  this.type = type;
  for ( var key in data.item[type] )
  {
    this[key] = data.item[type][key]; 
  }  
}  

function Character( data )
{
  this.marker = document.createElement('DIV');
  
  this.map = data.map;

  if ( data.start )
  {
    this.location = startIn( data.map, data.start );       
  } 
  else if ( data.location )
  {
    this.location = data.location;
  }

  this.skills = data.skills || {};    

  if ( data.typeOf == 'zombie' )
  {
    this.think = brain;
  }

  this.equipment = [];
  var types = [ 'inherent','equipped','carried' ]
  {
    for ( var i = 0; i < types.length; i++ )
    {
      for ( var j = 0; data[types[i]] != null && j < data[types[i]].length; j++ )
      {
        var equip = new Item( data[types[i]][j], data.map );
        equip.location = types[i];
        this.equipment[this.equipment.length] = equip;
  
      }
    }
  }

    this.moveTo = moveTo;
    this.test = test;
    this.learn = learn;
    this.typeOf = data.typeOf;
    this.drawMe = drawMe;
    this.listItems = listItems;
    this.attacksAvailable = attacksAvailable;
    this.attack = attack;
    this.damage = [];
    this.damageTotal = totalDamage;
    this.marker.self = this;

} 

var cityMap = mapData;

cityMap.zombieDesc = zombieDamage;
cityMap.damageDesc = textDamageDesc;
cityMap.damageMods = { 
  'breath': [ 'pain','upper','lower' ],
  'animation': [ 'upper','lower' ],
  'dodge' : [ 'pain', 'lower' ],
  'punch' : [ 'pain', 'upper' ],
  'kick' : [ 'pain', 'lower' ],
  'bite'  : [ 'pain', 'upper' ],
  'pistol': [ 'pain','upper' ],
'chainsaw': [ 'pain', 'upper' ],
'first aid': ['pain']  };
  
cityMap.item = { 
  'punch': 
  {
    'attack':true, 'locations': 1, 'damage': [1,2], 'description':'a fist',
  'hands':0, 'space':0, 'dropable': false, 'ammo': null, 'range':0 
  },
  'kick': 
  {
    'attack':true, 'locations': 1, 'damage': [2,2], 'description':'a foot',
  'hands':0, 'space':0, 'dropable': false, 'ammo': null, 'range':0 
  },
  'bite': 
  { 
    'attack':true, 'locations': 1, 'damage': [3,2], 'description':'bity teeth',
      'hands':0, 'space':0, 'dropable': false, 'ammo': null, 'range':0 
  },
  'pistol' : 
  {
    'attack':true, 'locations': 1, 'damage': [5,10], 'description':'a pistol',
    'hands':1, 'space':1, 'dropable': true, 'ammo': 15, 'range': 5
  },
  'chainsaw' : 
  {
    'attack':true, 'locations': 1, 'damage': [5,20], 'description':'a rusty chainsaw',
    'hands':1, 'space':1, 'dropable': true, 'ammo': null, 'range': 0
  },
  'bible' : 
  {
    'attack':false, 'locations': null, 'damage': null, 'description':'a tatty bible',
    'hands':0, 'space':0.5, 'dropable': true, 'ammo': null, 'range': null
  }
};

cityMap.hitLocs = { 
  'player': { 
          'upper' : { 'upper': 1, 'lower':0.25, 'pain':0.5 },
        'lower' : { 'upper': 0.25, 'lower':1, 'pain':0.5 },
        'head' : { 'upper': 0.5, 'lower':0, 'pain':1 } 
  },
  'zombie': { 
        'upper' : { 'upper': 1, 'lower':0.25, 'pain':0 },
        'lower' : { 'upper': 0.25, 'lower':1, 'pain':0 },
        'head' : { 'upper': 0.5, 'lower':0, 'pain':0 } 
  } 
};

             
cityMap.messages = textMessages;
cityMap.width = cityMap.map[0].length;
cityMap.height = cityMap.map.length;
cityMap.losCache = {};
cityMap.square = square;
cityMap.los = lineOfSite;
cityMap.player = new Character ( { 'location':[9,9], 
          'skills':
          {
            'enterBuilding':100, 'jumpBuilding': 50, 'learn':75, 
            'punch':( 20+rnd(30) ), 'dodge':( 20+rnd(30) ), 'breath':( 125 + rnd(100) ),
            'pistol' : ( 15 + rnd(40) ), 'kick' : ( 15 + rnd(40) ), 
            'chainsaw': ( 10 + rnd(20) ), 'first aid':(20+rnd(20)), 'viewDistance':3
          } ,  

            'map':cityMap, 'typeOf':'player', 'inherent':['punch','kick'], 'equipped':['pistol','chainsaw'], 'carried':['bible']
        } ); 
  
  
        cityMap.refresh = updateMap;
        cityMap.attach = createMap;
        cityMap.surround = surround;
        cityMap.checkView = checkSee;
cityMap.describe = describe;
