Author Sticky: Post Working Scripts Here
Bagofbones Posted: Tuesday, 09 July 04:10AM
1. itools_chess

2. Include file for functions to implement a human chess game with NPC characters as well as help in other chess related traps etc.

3. Notes:

These functions assume they are called from an area containing two waypoints, with the tags CHS_WP_WHITE and CHS_WP_BLACK, that define the chessboard. In this version the chessboard must have ranks that run east/west with white's king's rook in the south-east corner.Any board size can be defined. I tested with the chessboard terrain rotated to put white at the bottom right.

The commands will place blue and red shafts of light on given chess squares. These indicate the squares the "pieces" will be moved to and from respectivly. The chs_MakeIndicatedMove() command will find to closest reature object to the blue shaft of light nad move to the location of the red shaft light. If the target location is occupied by a piece it is captured (destroyed). I tested this using male and female commoners. I changed their appearances to simulate the monsters I wanted to use.

These commands do not try to enforce any chess rules in this version. Many of then may have a general purpose use in a chess related module. See the include file comments for a list of the functions.

4. itools_chess verstion 1.4
NWScript:
//::///////////////////////////////////////////////

//:: FileName itools_chess

//:://////////////////////////////////////////////

//:://////////////////////////////////////////////

//:: Created By: Bagofbones@earthlink.net

//:: Created On: 6/29/02 6:04:29 PM

//::

//:: Version  Modified  Change

//:: 1.2      7/03/02   added chs_SetIndicatorRank

//::                    and chs_SetIndicatorFile

//:: 1.3      7/07/02   added chs_getPieceAtLocation

//::

//:: 1.4      7/08/02   added chs_MakeIndicatedMove

//:://////////////////////////////////////////////



//::///////////////////////////////////////////////

//:: include file for human chess functions

//:://////////////////////////////////////////////

/*

These functions assume they are called from an area

containing two waypoints that define the chessbord.

In this version the chessboard must have Ranks that run

east/west with white's king's rook in the south.

the indicator used can be changed by changeing the blueprint and

tag strings in the appropriate files.  Currently I use a shaft

of blue light to indicate the source square and a shaft of red light

to indicate a destination square.

Functions in this include file:

location  chs_GetBoardLocation( int nRank, int nFile, int bFacingBlack );

int  chs_LocationToRank( location lTest );

int  chs_LocationToFile( location lTest );

int  chs_SetIndicatorFile( int nFile, int bFromMarker = TRUE );

int  chs_SetIndicatorRank( int nRank, int bFromMarker );

int  chs_SetIndicatorPositon( int nRank, int nFile, int bFromMarker = TRUE );

object chs_getPieceAtLocation( location lTest );

int  chs_MakeIndicatedMove();

TODO:

Add  SettupBoard() and ClearBoard;

*/



//::///////////////////////////////////////////////

//:: Name  chs_GetBoardLocation

//::

//:://////////////////////////////////////////////

/*

Input:

int nRank -the chess square's rank 1(white)-8(black)

int nFile -the chess square's file 1(File A)-8(File H)

int bFacingBlack - the locations facing direction

                   TRUE - at Black , FALSE - at White

Output:

location  -  square center facing opponent. locaion's

area object will be OBJECT_INVALID if there is an error.

Description:



*/

//:://////////////////////////////////////////////

//:: Created By:

//:: Created On: 7/02/02

//:://////////////////////////////////////////////

location

chs_GetBoardLocation( int nRank, int nFile, int bFacingBlack )

{

   // Start with the assumption that the board ranks run east-west

   // with white to the south

   // Create an Invalid location to return on error

   vector vSquare = Vector(0.0,0.0,0.0 );

   float fFacing = 0.0;

   location lSquare =  Location( OBJECT_INVALID , vSquare, fFacing );

   if( nRank < 1 || nRank > 8 || nFile < 1 || nFile > 8 )

   {

     // Invalid Rank/File parameters

     return lSquare;

   }

   object oWhiteWaypoint= GetWaypointByTag("CHS_WP_WHITE");

   if( !GetIsObjectValid(oWhiteWaypoint) )

   {

     // Could not find white's waypoint

     return lSquare;

   }

   vector vWhite = GetPosition( oWhiteWaypoint );

   object oBlackWaypoint = GetWaypointByTag( "CHS_WP_BLACK" );

   if( !GetIsObjectValid(oBlackWaypoint) )

   {

     // Could not find black's waypoint

     // TODO: calculate assuming standard chessboard terrain

     return lSquare;

   }

   vector vBlack = GetPosition( oBlackWaypoint );

   // math to determine square center ( adjusted to center of square )

   float fRank = IntToFloat(nRank)-0.5;

   float fFile = IntToFloat(nFile)-0.5;

   vSquare.x = vBlack.x +  ( vWhite.x - vBlack.x )*(fFile/8.0);

   vSquare.y = vWhite.y +  ( vBlack.y - vWhite.y )*(fRank/8.0);

   vSquare.z = vBlack.z;

   // use the black or white waypoints to determine which way the piece should face

   if( bFacingBlack )

   {

     lSquare =  Location( GetArea( oWhiteWaypoint) , vSquare, GetFacing(oWhiteWaypoint) );

   }

   else

   {

     lSquare =  Location( GetArea( oWhiteWaypoint) , vSquare, GetFacing(oBlackWaypoint) );

   }

   return lSquare;

}

//::///////////////////////////////////////////////

//:: Name  chs_LocationToRank

//::

//:://////////////////////////////////////////////

/*

Input:

  location - finds the chessboard rank of this location

             or 0 if not on the board.

Output:

  int -  0 =  location not on board 1 = White's King's rank

                                    8 - Black's King's rank

Description:

Tests a location to see if it lies on a chessboard

defined by two waypoints with the tags, CHS_WP_WHITE

and CHS_WP_BLACK. If it does, the chess Rank will be

returned. If not then 0 will be returned.

*/

//:://////////////////////////////////////////////

//:: Created By:

//:: Created On: 7/02/02

//:://////////////////////////////////////////////

int

chs_LocationToRank( location lTest )

{

   // Start with the assumption that the board ranks run east-west

   // with white to the south

   // int bWhiteGreaterThanBlack = TRUE;

   // int bRanksParallelToXAxis = TRUE;

   int nRank = 0; // assume invalid to start with

   float fDistance = 1.0;

   float fBoardHight = 1.0;



   object oWhiteWaypoint= GetWaypointByTag("CHS_WP_WHITE");

   if( !GetIsObjectValid(oWhiteWaypoint) )

   {

     // Could not find white's waypoint

     return 0;

   }

   vector vWhite = GetPosition( oWhiteWaypoint );

   object oBlackWaypoint = GetWaypointByTag( "CHS_WP_BLACK" );

   if( !GetIsObjectValid(oBlackWaypoint) )

   {

     // Could not find black's waypoint

     // TODO: calculate assuming standard chessboard terrain

     return 0;

   }

   vector vBlack = GetPosition( oBlackWaypoint );

   // math to determine what rank and file the loaction is in

   // TODO: test area?

   vector vTest = GetPositionFromLocation( lTest );

   // are we in the box?

   // TODO: test for bWhiteGreaterThanBlack, and bRanksParallelToXAxis

   //       and handle arbitrary board orientation.

   if(  vTest.x > vBlack.x  &&  vTest.x < vWhite.x && vTest.y < vBlack.y  && vTest.y > vWhite.y )

   {

     fDistance =  vTest.y - vWhite.y;

     fBoardHight = vBlack.y - vWhite.y;

     // looks like FloatToInt truncates rather than roundint to the

     // nearest int as the documentation implies

     nRank = FloatToInt((8.0* fDistance/fBoardHight) + 0.999);

     return nRank;

   }

   // The location was not on the board

   return 0;

}

//::///////////////////////////////////////////////

//:: Name  chs_LocationToFile

//::

//:://////////////////////////////////////////////

/*

Input:

  location - finds the chessboard file of this location

             or 0 if it is not on the board.

Output:

  int -  0 =  location not on board

         1 - 8 =  Files A-H

Description:

Tests a location to see if it lies on a chessboard

defined by two waypoints with the tags, CHS_WP_WHITE

and CHS_WP_BLACK. If it does, the ches Rank will be

returned. If not then 0 will be returned.

*/

//:://////////////////////////////////////////////

//:: Created By:

//:: Created On: 7/02/02

//:://////////////////////////////////////////////

int

chs_LocationToFile( location lTest )

{

   // Start with the assumption that the board ranks run east-west

   // with white to the south

   // int bWhiteGreaterThanBlack = TRUE;

   // int bRanksParallelToXAxis = TRUE;

   int nFile = 0; // assume invalid to start with

   float fDistance = 1.0;

   float fBoardWidth = 1.0;



   object oWhiteWaypoint= GetWaypointByTag("CHS_WP_WHITE");

   if( !GetIsObjectValid(oWhiteWaypoint) )

   {

     // Could not find white's waypoint

     return 0;

   }

   vector vWhite = GetPosition( oWhiteWaypoint );

   object oBlackWaypoint = GetWaypointByTag( "CHS_WP_BLACK" );

   if( !GetIsObjectValid(oBlackWaypoint) )

   {

     // Could not find black's waypoint

     // TODO: calculate assuming standard chessboard terrain

     return 0;

   }

   vector vBlack = GetPosition( oBlackWaypoint );

   // math to determine what rank and file the loaction is in

   // TODO: test area?

   vector vTest = GetPositionFromLocation( lTest );

   // are we in the box?

   // TODO: test for bWhiteGreaterThanBlack, and bRanksParallelToXAxis

   //       and handle arbitrary board orientation.

   if(  vTest.x > vBlack.x  &&  vTest.x < vWhite.x && vTest.y < vBlack.y  && vTest.y > vWhite.y )

   {

     fDistance =  vTest.x - vBlack.x;

     fBoardWidth = vWhite.x- vBlack.x;

     nFile = FloatToInt((8.0* fDistance/fBoardWidth) + 0.999);

     return nFile;

   }

   // The location was not on the board

   return 0;

}

//::///////////////////////////////////////////////

//:: Name  chs_SetIndicatorPositon

//::

//:://////////////////////////////////////////////

/*

Input:

int nRank -the chess square's rank 1(white)-8(black)

int nFile -the chess square's file 1(File A)-8(File H)

int bFromMarker - true for blue "from" marker

                - FLASE for red "to" marker

Output:

int -  non zero on success

Description:

Create

*/

//:://////////////////////////////////////////////

//:: Created By:

//:: Created On: 7/02/02

//:://////////////////////////////////////////////

int

chs_SetIndicatorPositon( int nRank, int nFile, int bFromMarker = TRUE )

{

  object oFromShaft = GetNearestObjectByTag("Shaft of Light - Blue"); // , GetPCSpeaker(), 1);

  if(  GetIsObjectValid(oFromShaft) )

  {

     // destroy the old Shaft

     DestroyObject( oFromShaft );

  }

  location lNewFromShaft = chs_GetBoardLocation( nRank, nFile, FALSE );

  if( GetIsObjectValid( GetAreaFromLocation( lNewFromShaft )  ) )

  {

    object oNewFromShaft = CreateObject(OBJECT_TYPE_PLACEABLE, "plc_solblue", lNewFromShaft, TRUE);

    return TRUE;

  }

  return FALSE;

}

//::///////////////////////////////////////////////

//:: Name  chs_SetIndicatorRank

//::

//:://////////////////////////////////////////////

/*

Input:

int nRank -the chess square's rank 1(white)-8(black)

Output:

int -  non zero on success

Description:

*/

//:://////////////////////////////////////////////

//:: Created By:

//:: Created On: 7/02/02

//:://////////////////////////////////////////////

int chs_SetIndicatorRank( int nRank, int bFromMarker )

{

  // Assume a blue shaft of light on file A to start with

  string sMarkerTag = "Shaft of Light - Blue";

  string sMarkerTemplate = "plc_solblue";

  int nFile = 1;

  if( !bFromMarker )

  {

    sMarkerTag = "Shaft of Light - Red";

    sMarkerTemplate = "plc_solred";

  }

  object oObject = GetNearestObjectByTag(sMarkerTag ); // , GetPCSpeaker(), 1);

  if(  GetIsObjectValid(oObject) )

  {

     // destroy the old Shaft but rember its location

     location lOldLocation = GetLocation( oObject );

     // Get the file

     nFile =chs_LocationToFile( lOldLocation );

     if( nFile <1 || nFile > 8 )

     {

       nFile = 1; // revert to a file  on error

     }

     DestroyObject( oObject );

  }

  location lNewShaft = chs_GetBoardLocation( nRank, nFile, FALSE );

  if( GetIsObjectValid( GetAreaFromLocation( lNewShaft )  ) )

  {

    object oNewObject = CreateObject(OBJECT_TYPE_PLACEABLE, sMarkerTemplate, lNewShaft, TRUE);

    return TRUE;

  }

  // Problem getting board location

  return FALSE;

}



//::///////////////////////////////////////////////

//:: Name  chs_SetIndicatorFile

//::

//:://////////////////////////////////////////////

/*

Input:

int nRank -the chess square's rank 1(white)-8(black)

Output:

int -  non zero on success

Description:

*/

//:://////////////////////////////////////////////

//:: Created By:

//:: Created On: 7/02/02

//:://////////////////////////////////////////////

int

chs_SetIndicatorFile( int nFile, int bFromMarker = TRUE )

{

  // Assume a blue shaft of light on the white kings rank

  // to start with

  string sMarkerTag = "Shaft of Light - Blue";

  string sMarkerTemplate = "plc_solblue";

  int nRank = 1;

  if( !bFromMarker )

  {

    sMarkerTag = "Shaft of Light - Red";

    sMarkerTemplate = "plc_solred";

  }

  object oObject = GetNearestObjectByTag(sMarkerTag); // , GetPCSpeaker(), 1);

  location lOldLocation;

  if(  GetIsObjectValid(oObject) )

  {

     // destroy the old Shaft but rember its location

     lOldLocation = GetLocation( oObject );

     // Get the file

     nRank =chs_LocationToRank( lOldLocation );

     if( nRank <1 || nRank > 8 )

     {

       nRank = 1; // revert to a file  on error

     }

     DestroyObject( oObject );

  }

  location lNewShaft = chs_GetBoardLocation( nRank, nFile, FALSE );

  if( GetIsObjectValid( GetAreaFromLocation( lNewShaft )  ) )

  {

    object oNewObject = CreateObject(OBJECT_TYPE_PLACEABLE, sMarkerTemplate, lNewShaft, TRUE);

    return TRUE;

  }

  // Problem getting board location

  return FALSE;

}

//::///////////////////////////////////////////////

//:: Name  chs_getPieceAtLocation

//::

//:://////////////////////////////////////////////

/*

Output:

  object - the pice in the square or OBJECT_INVALID if none

Description:

  I assume the pieces are creatures.

*/

//:://////////////////////////////////////////////

//:: Created By:

//:: Created On: 7/02/02

//:://////////////////////////////////////////////

object

chs_getPieceAtLocation( location lTest )

{

 WriteTimestampedLogEntry("Start GetPieceAtLocation:");

 // I assume the pieces are creatures

 object oPiece = GetNearestObjectToLocation( OBJECT_TYPE_CREATURE, lTest);

 if( !GetIsObjectValid(oPiece ) )

 {

   PrintString("First Piece was invalid");

   return oPiece;

 }

 PrintString( "Found piece at location: " + GetTag(oPiece ));

 location lPiece = GetLocation( oPiece );

 // Make sure the piece is in the same square as the indicator

 if( chs_LocationToRank(lPiece ) != chs_LocationToRank( lTest ) )

 {

   PrintString( "bad Rank. Piece Rank:");

   PrintInteger( chs_LocationToRank(lPiece ) );

   PrintString( "Location Rank:");

   PrintInteger( chs_LocationToRank(lTest ) );

   return OBJECT_INVALID;

 }

 if( chs_LocationToFile(lPiece ) != chs_LocationToFile( lTest ) )

 {

   PrintString( "bad File. Piece File:");

   PrintInteger( chs_LocationToFile(lPiece ) );

   PrintString( "Location File:");

   PrintInteger( chs_LocationToFile(lTest ) );

   return OBJECT_INVALID;

 }

 return oPiece;

}

//::///////////////////////////////////////////////

//:: Name  chs_MakeIndicatedMove

//::

//:://////////////////////////////////////////////

/*

Output:

  int -  0  if the waypoints that define the board cannot

            be found or if no "piece" is in the same square

            as the source marker.

         1  if the piece was found an moved to an empty square

         2  if the piece was found and captured another piece

Description:

 If an object is found near the source marker it is

 given a command to move to the target markers location

 and any object in the same square as a target marker is

 "captured" ( destroyed ).  No test is made to insure that a move is

 legal or that it is not capturing its own side's piece.

*/

//:://////////////////////////////////////////////

//:: Created By:

//:: Created On: 7/02/02

//:://////////////////////////////////////////////

int

chs_MakeIndicatedMove()

{

  WriteTimestampedLogEntry("Start MakeIndicatedMove:");

  // TODO: add code for battles?

  string sFromMarkerTag = "Shaft of Light - Blue";

  string sFromMarkerTemplate = "plc_solblue";

  string sToMarkerTag = "Shaft of Light - Red";

  string sToMarkerTemplate = "plc_solred";

  object oFromMarker = GetNearestObjectByTag(sFromMarkerTag);

  object oToMarker = GetNearestObjectByTag(sToMarkerTag);

  if(!GetIsObjectValid(oFromMarker))

  {

    PrintString("Could not find from marker");

    return 0;

  }

  if(!GetIsObjectValid(oToMarker))

  {

    PrintString("Could not find to marker");

    return 0;

  }

  location lFromLocation = GetLocation( oFromMarker );

  // make sure we have a piece in this square. I assume the piece is a creature

  object oPieceToMove = chs_getPieceAtLocation( lFromLocation );

  if( !GetIsObjectValid( oPieceToMove ) )

  {

    PrintString("Could not find the Piece to move");

    return 0;

  }

  PrintString("Found a piece to move: "+ GetTag( oPieceToMove));

  location lToLocation = GetLocation( oToMarker );

  object oPieceToCapture = chs_getPieceAtLocation( lToLocation );

  PrintString("Found a piece to capture");

  AssignCommand( oPieceToMove , ActionForceMoveToLocation(lToLocation, FALSE, 10.0 ));

  if( GetIsObjectValid( oPieceToCapture ))

  {

    PrintString("Found a piece to capture: "+ GetTag( oPieceToCapture));

    DestroyObject( oPieceToCapture );

    // we captured a piece so return 2

    return 2;

  }

  // we moved to an empty space so return 1

  return 1;

}




Examples:

I used a conversation with a "ChessMaster" NPC as the UI to move chess pieces.

A script attached to the action taken for the players response of "The piece shall be moved from the C file" might look like this:

NWScript:
#include "itools_chess"

void main()

{

  // Set the "Move From" indicator to the "C" File

  chs_SetIndicatorFile( 3,TRUE);

}




After the to and from indicators are in valid locations the player response
"Move the piece now"

might be implement like this:

NWScript:
#include "itools_chess"

void main()

{

 int iReturn = chs_MakeIndicatedMove();

 if( iReturn == 0 )

 {

   // the indicated move was not valid so make a scream

   PlaySound("as_pl_screamm1");

 }

 if( iReturn == 1 )

 {

   // The indicated move was to an open space, make an evil laugh

   PlaySound("as_pl_laughingm1");

 }

 if( iReturn == 2 )

 {

   // the indicated move captured a piece,  make mob noises

   PlaySound("as_pl_prisinmob1");

 }

}




One know problem is that pieces can be pushed off thier spaces by other pieces. This could be fixed by storing the current location in each piece and sending them back to that location when necessary.

Good Luck and Have fun making chess mods!