Logo Search packages:      
Sourcecode: freecraft version File versions

commands.c

//   ___________             _________                _____  __
//   \_       _____/______   ____   ____ \_   ___ \____________ _/ ____\/  |_
//    |    __) \_  __ \_/ __ \_/ __ \/    \  \/\_  __ \__  \\   __\\   __|
//    |     \   |  | \/\  ___/\  ___/\     \____|  | \// __ \|  |   |  |
//    \___  /   |__|    \___  >\___  >\______  /|__|  (____  /__|   |__|
//      \/            \/         \/      \/              \/
//  ______________________                           ______________________
//                  T H E   W A R   B E G I N S
//       FreeCraft - A free fantasy real time strategy game engine
//
/**@name commands.c     -     Global command handler - network support. */
//
//    (c) Copyright 2000-2003 by Lutz Sammer, Andreas Arens, and Jimmy Salmon.
//
//    FreeCraft is free software; you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published
//    by the Free Software Foundation; only version 2 of the License.
//
//    FreeCraft is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    $Id: commands.c,v 1.54 2003/03/06 21:09:58 jsalmon3 Exp $

//@{

//----------------------------------------------------------------------------
//    Includes
//----------------------------------------------------------------------------

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if !defined(_MSC_VER) || !defined(_WIN32_WCE)
#include <time.h>
#endif

#include "freecraft.h"
#include "unit.h"
#include "map.h"
#include "actions.h"
#include "player.h"
#include "network.h"
#include "netconnect.h"
#include "campaign.h"               // for CurrentMapPath
#include "ccl.h"
#include "commands.h"
#include "interface.h"
#include "iocompat.h"
#include "settings.h"

//----------------------------------------------------------------------------
//    Declaration
//----------------------------------------------------------------------------

//----------------------------------------------------------------------------
//    Variables
//----------------------------------------------------------------------------

global int CommandLogDisabled;            /// True if command log is off
global ReplayType ReplayGameType;   /// Replay game type
local int DisabledLog;              /// Disabled log for replay
local int DisabledShowTips;         /// Disabled show tips
local SCM ReplayLog;                /// Replay log
local FILE* LogFile;                /// Replay log file
local unsigned long NextLogCycle;   /// Next log cycle number
local int InitReplay;               /// Initialize replay
local char *ReplayPlayers[PlayerMax];     /// Player names


//----------------------------------------------------------------------------
//    Log commands
//----------------------------------------------------------------------------

/**@name log */
//@{

/**
**    Log commands into file.
**
**    This could later be used to recover, crashed games.
**
**    @param name Command name (move,attack,...).
**    @param unit Unit that receive the command.
**    @param flag Append command or flush old commands.
**    @param x    optional X map position.
**    @param y    optional y map position.
**    @param dest optional destination unit.
**    @param value      optional command argument (unit-type,...).
**    @param num  optional number argument
*/
global void CommandLog(const char* name,const Unit* unit,int flag,
      int x,int y,const Unit* dest,const char* value,int num)
{
    if( CommandLogDisabled ) {            // No log wanted
      return;
    }

    //
    //      Create and write header of log file. The player number is added
    //  to the save file name, to test more than one player on one computer.
    //
    if( !LogFile ) {
      time_t now;
      char buf[PATH_MAX];
      char* s;
      char* s1;

#ifdef USE_WIN32
      strcpy(buf,"logs");
      mkdir(buf);
#else
      sprintf(buf,"%s/%s",getenv("HOME"),FREECRAFT_HOME_PATH);
      mkdir(buf,0777);
      strcat(buf,"/logs");
      mkdir(buf,0777);
#endif

      sprintf(buf,"%s/log_of_freecraft_%d.log",buf,ThisPlayer->Player);
      LogFile=fopen(buf,"wb");
      if( !LogFile ) {
          return;
      }

      time(&now);
      s=ctime(&now);
      if( (s1=strchr(s,'\n')) ) {
          *s1='\0';
      }

      //
      //    Parseable header
      //
      fprintf(LogFile,"(replay-log\n");
      fprintf(LogFile,"  'comment\t\"Generated by FreeCraft Version " VERSION "\"\n");
      fprintf(LogFile,"  'comment\t\"Visit http://FreeCraft.Org for more information\"\n");
      fprintf(LogFile,"  'comment\t\"$Id: commands.c,v 1.54 2003/03/06 21:09:58 jsalmon3 Exp $\"\n");
      if( NetworkFildes==-1 ) {
          fprintf(LogFile,"  'type\t\"%s\"\n","single-player");
          fprintf(LogFile,"  'race\t%d\n",GameSettings.Presets[0].Race);
      } else {
          int i;
          fprintf(LogFile,"  'type\t\"%s\"\n","multi-player");
          for( i=0; i<PlayerMax; ++i ) {
            fprintf(LogFile,"  'player\t(list 'number %d 'name \"%s\" 'race %d 'team %d 'type %d)\n",
                i,Players[i].Name,GameSettings.Presets[i].Race,
                GameSettings.Presets[i].Team,GameSettings.Presets[i].Type);
          }
          fprintf(LogFile,"  'local-player\t%d\n",ThisPlayer->Player);
      }
      fprintf(LogFile,"  'date\t\"%s\"\n",s);
      fprintf(LogFile,"  'map\t\"%s\"\n",TheMap.Description);
      fprintf(LogFile,"  'map-id\t%u\n",TheMap.Info->MapUID);
      fprintf(LogFile,"  'map-path\t\"%s\"\n",CurrentMapPath);
      fprintf(LogFile,"  'resources\t%d\n",GameSettings.Resources);
      fprintf(LogFile,"  'num-units\t%d\n",GameSettings.NumUnits);
      fprintf(LogFile,"  'tileset\t%d\n",GameSettings.Terrain);
      fprintf(LogFile,"  'no-fow\t%d\n",TheMap.NoFogOfWar);
      fprintf(LogFile,"  'reveal-map\t%d\n",GameSettings.RevealMap);
      fprintf(LogFile,"  'game-type\t%d\n",GameSettings.GameType);
      fprintf(LogFile,"  'opponents\t%d\n",GameSettings.Opponents);
      fprintf(LogFile,"  'engine\t'(%d %d %d)\n",
          FreeCraftMajorVersion,FreeCraftMinorVersion,FreeCraftPatchLevel);
      fprintf(LogFile,"  'network\t'(%d %d %d)\n",
          NetworkProtocolMajorVersion,
          NetworkProtocolMinorVersion,
          NetworkProtocolPatchLevel);
      fprintf(LogFile,"  )\n");
    }

    if( !name ) {
      return;
    }

    //
    //      Frame, unit, (type-ident only to be better readable).
    //
    if( unit ) {
      fprintf(LogFile,"(log %lu 'unit %d 'ident '%s 'name '%s 'flag '%s",
            GameCycle,UnitNumber(unit),unit->Type->Ident,name,
            flag ? "flush" : "append");
    } else {
      fprintf(LogFile,"(log %lu 'name '%s 'flag '%s",
            GameCycle,name, flag ? "flush" : "append");
    }

    //
    //      Coordinates given.
    //
    if( x!=-1 || y!=-1 ) {
      fprintf(LogFile," 'pos '(%d %d)",x,y);
    }
    //
    //      Destination given.
    //
    if( dest ) {
      fprintf(LogFile," 'dest '%d",UnitNumber(dest));
    }
    //
    //      Value given.
    //
    if( value ) {
      fprintf(LogFile," 'value \"%s\"",value);
    }
    //
    //      Number given.
    //
    if( num!=-1 ) {
      fprintf(LogFile," 'num %d",num);
    }
    if( unit ) {
      fprintf(LogFile,") ;%d:%d %X",unit->Player->Player,unit->Refs,
            SyncRandSeed);
    } else {
      fprintf(LogFile,") ;-:- %X",SyncRandSeed);
    }

    fprintf(LogFile,"\n");
    fflush(LogFile);
}

/**
**    Parse log
*/
local SCM CclLog(SCM list)
{
    SCM var;

    var=gh_symbol2scm("*replay_log*");
    if( gh_null_p(symbol_value(var,NIL)) ) {
      setvar(var,cons(list,NIL),NIL);
    } else {
      SCM tmp;
      tmp=symbol_value(var,NIL);
      while( !gh_null_p(gh_cdr(tmp)) ) {
          tmp=gh_cdr(tmp);
      }
      setcdr(tmp,cons(list,NIL));
    }

    return SCM_UNSPECIFIED;
}

/**
**    Parse replay-log
*/
local SCM CclReplayLog(SCM list)
{
    SCM value;
    SCM sublist;
    const char* comment;
    const char* logtype;
    const char* logdate;
    const char* map;
    unsigned int mapid;
    const char* mappath;
    int ever1;
    int ever2;
    int ever3;
    int nver1;
    int nver2;
    int nver3;

    while( !gh_null_p(list) ) {
      value=gh_car(list);
      list=gh_cdr(list);

      if( gh_eq_p(value,gh_symbol2scm("comment")) ) {
          comment=get_c_string(gh_car(list));
          list=gh_cdr(list);
      } else if( gh_eq_p(value,gh_symbol2scm("type")) ) {
          logtype=get_c_string(gh_car(list));
          if( !strcmp(logtype,"multi-player") ) {
            ExitNetwork1();
            NetPlayers=2;
          }
          list=gh_cdr(list);
      } else if( gh_eq_p(value,gh_symbol2scm("date")) ) {
          logdate=get_c_string(gh_car(list));
          list=gh_cdr(list);
      } else if( gh_eq_p(value,gh_symbol2scm("map")) ) {
          map=get_c_string(gh_car(list));
          list=gh_cdr(list);
      } else if( gh_eq_p(value,gh_symbol2scm("map-id")) ) {
          mapid=gh_scm2int(gh_car(list));
          list=gh_cdr(list);
      } else if( gh_eq_p(value,gh_symbol2scm("map-path")) ) {
          mappath=get_c_string(gh_car(list));
          strcpy(CurrentMapPath,mappath);
          list=gh_cdr(list);
      } else if( gh_eq_p(value,gh_symbol2scm("race")) ) {
          GameSettings.Presets[0].Race=gh_scm2int(gh_car(list));
          list=gh_cdr(list);
      } else if( gh_eq_p(value,gh_symbol2scm("resources")) ) {
          GameSettings.Resources=gh_scm2int(gh_car(list));
          list=gh_cdr(list);
      } else if( gh_eq_p(value,gh_symbol2scm("num-units")) ) {
          GameSettings.NumUnits=gh_scm2int(gh_car(list));
          list=gh_cdr(list);
      } else if( gh_eq_p(value,gh_symbol2scm("tileset")) ) {
          GameSettings.Terrain=gh_scm2int(gh_car(list));
          list=gh_cdr(list);
      } else if( gh_eq_p(value,gh_symbol2scm("no-fow")) ) {
          TheMap.NoFogOfWar=GameSettings.NoFogOfWar=gh_scm2int(gh_car(list));
          list=gh_cdr(list);
      } else if( gh_eq_p(value,gh_symbol2scm("reveal-map")) ) {
          FlagRevealMap=GameSettings.RevealMap=gh_scm2int(gh_car(list));
          list=gh_cdr(list);
      } else if( gh_eq_p(value,gh_symbol2scm("game-type")) ) {
          GameSettings.GameType=gh_scm2int(gh_car(list));
          list=gh_cdr(list);
      } else if( gh_eq_p(value,gh_symbol2scm("opponents")) ) {
          GameSettings.Opponents=gh_scm2int(gh_car(list));
          list=gh_cdr(list);
      } else if( gh_eq_p(value,gh_symbol2scm("engine")) ) {
          sublist=gh_car(list);
          ever1=gh_scm2int(gh_car(sublist));
          sublist=gh_cdr(sublist);
          ever2=gh_scm2int(gh_car(sublist));
          sublist=gh_cdr(sublist);
          ever3=gh_scm2int(gh_car(sublist));
          // FIXME: check engine version
          list=gh_cdr(list);
      } else if( gh_eq_p(value,gh_symbol2scm("network")) ) {
          sublist=gh_car(list);
          nver1=gh_scm2int(gh_car(sublist));
          sublist=gh_cdr(sublist);
          nver2=gh_scm2int(gh_car(sublist));
          sublist=gh_cdr(sublist);
          nver3=gh_scm2int(gh_car(sublist));
          // FIXME: check network version
          list=gh_cdr(list);
      } else if( gh_eq_p(value,gh_symbol2scm("player")) ) {
          int num;
          int race;
          int team;
          int type;
          char *name;

          ReplayGameType=ReplayMultiPlayer;
          num=-1;
          race=team=type=SettingsPresetMapDefault;
          name=NULL;
          sublist=gh_car(list);
          while( !gh_null_p(sublist) ) {
            value=gh_car(sublist);
            sublist=gh_cdr(sublist);
            if( gh_eq_p(value,gh_symbol2scm("number")) ) {
                num=gh_scm2int(gh_car(sublist));
                sublist=gh_cdr(sublist);
            } else if( gh_eq_p(value,gh_symbol2scm("name")) ) {
                name=gh_scm2newstr(gh_car(sublist),NIL);
                sublist=gh_cdr(sublist);
            } else if( gh_eq_p(value,gh_symbol2scm("race")) ) {
                race=gh_scm2int(gh_car(sublist));
                sublist=gh_cdr(sublist);
            } else if( gh_eq_p(value,gh_symbol2scm("team")) ) {
                team=gh_scm2int(gh_car(sublist));
                sublist=gh_cdr(sublist);
            } else if( gh_eq_p(value,gh_symbol2scm("type")) ) {
                type=gh_scm2int(gh_car(sublist));
                sublist=gh_cdr(sublist);
            }
          }
          if( num!=-1 ) {
            GameSettings.Presets[num].Race=race;
            GameSettings.Presets[num].Team=team;
            GameSettings.Presets[num].Type=type;
            ReplayPlayers[num]=name;
          }

          list=gh_cdr(list);
      } else if( gh_eq_p(value,gh_symbol2scm("local-player")) ) {
          NetLocalPlayerNumber=gh_scm2int(gh_car(list));
          list=gh_cdr(list);
      }
    }

    return SCM_UNSPECIFIED;
}

/**
**    Load a log file to replay a game
**
**    @param name name of file to load.
*/
global int LoadReplay(char* name)
{
    int i;

    for( i=0; i<PlayerMax; ++i ) {
      if( ReplayPlayers[i] ) {
          free(ReplayPlayers[i]);
          ReplayPlayers[i]=NULL;
      }
    }
    ReplayGameType=ReplaySinglePlayer;

    gh_new_procedureN("log",CclLog);
    gh_new_procedureN("replay-log",CclReplayLog);
    gh_define("*replay_log*",NIL);
    vload(name,0,1);

    ReplayLog=symbol_value(gh_symbol2scm("*replay_log*"),NIL);
    NextLogCycle=~0UL;
    if( !CommandLogDisabled ) {
      CommandLogDisabled=1;
      DisabledLog=1;
    }
    if( ShowTips ) {
      ShowTips=0;
      DisabledShowTips=1;
    } else {
      DisabledShowTips=0;
    }
    GameObserve=1;
    InitReplay=1;

    return 0;
}

/**
**    End logging
*/
global void EndReplayLog(void)
{
    if( LogFile ) {
      fclose(LogFile);
      LogFile=NULL;
    }
}

/**
**    Clean replay log
*/
global void CleanReplayLog(void)
{
    ReplayLog=NIL;
    // FIXME: LoadGame disables the log since replays aren't saved in the
    // FIXME: saved games yet.  Always enable the log again for now even
    // FIXME: though it ignores the -l command line option.
//    if( DisabledLog ) {
      CommandLogDisabled=0;
      DisabledLog=0;
//    }
    if( DisabledShowTips ) {
      ShowTips=1;
      DisabledShowTips=0;
    }
    GameObserve=0;
    NetPlayers=0;
    ReplayGameType=ReplayNone;
}

/**
**    Do next replay
*/
local void DoNextReplay(void)
{
    SCM value;
    SCM list;
    int unit;
    const char* ident;
    const char* name;
    const char* flag;
    int flags;
    int posx;
    int posy;
    const char* val;
    int num;
    Unit* dunit;

    list=gh_car(ReplayLog);

    NextLogCycle=gh_scm2int(gh_car(list));
    list=gh_cdr(list);

    if( NextLogCycle!=GameCycle ) {
      return;
    }

    NextLogCycle=~0UL;
    unit=-1;
    name=NULL;
    flags=0;
    posx=-1;
    posy=-1;
    dunit=NoUnitP;
    val=NULL;
    num=-1;
    while( !gh_null_p(list) ) {
      value=gh_car(list);
      list=gh_cdr(list);

      if( gh_eq_p(value,gh_symbol2scm("unit")) ) {
          unit=gh_scm2int(gh_car(list));
          list=gh_cdr(list);
      } else if( gh_eq_p(value,gh_symbol2scm("ident")) ) {
          ident=get_c_string(gh_car(list));
          list=gh_cdr(list);
      } else if( gh_eq_p(value,gh_symbol2scm("name")) ) {
          name=get_c_string(gh_car(list));
          list=gh_cdr(list);
      } else if( gh_eq_p(value,gh_symbol2scm("flag")) ) {
          flag=get_c_string(gh_car(list));
          if( !strcmp(flag,"flush") ) {
            flags=1;
          }
          list=gh_cdr(list);
      } else if( gh_eq_p(value,gh_symbol2scm("pos")) ) {
          SCM sublist;
          sublist=gh_car(list);
          posx=gh_scm2int(gh_car(sublist));
          sublist=gh_cdr(sublist);
          posy=gh_scm2int(gh_car(sublist));
          list=gh_cdr(list);
      } else if( gh_eq_p(value,gh_symbol2scm("dest")) ) {
          dunit=UnitSlots[gh_scm2int(gh_car(list))];
          list=gh_cdr(list);
      } else if( gh_eq_p(value,gh_symbol2scm("value")) ) {
          val=get_c_string(gh_car(list));
          list=gh_cdr(list);
      } else if( gh_eq_p(value,gh_symbol2scm("num")) ) {
          num=gh_scm2int(gh_car(list));
          list=gh_cdr(list);
      }
    }

    if( !strcmp(name,"stop") ) {
      SendCommandStopUnit(UnitSlots[unit]);
    } else if( !strcmp(name,"stand-ground") ) {
      SendCommandStandGround(UnitSlots[unit],flags);
    } else if( !strcmp(name,"follow") ) {
      SendCommandFollow(UnitSlots[unit],dunit,flags);
    } else if( !strcmp(name,"move") ) {
      SendCommandMove(UnitSlots[unit],posx,posy,flags);
    } else if( !strcmp(name,"repair") ) {
      SendCommandRepair(UnitSlots[unit],posx,posy,dunit,flags);
    } else if( !strcmp(name,"attack") ) {
      SendCommandAttack(UnitSlots[unit],posx,posy,dunit,flags);
    } else if( !strcmp(name,"attack-ground") ) {
      SendCommandAttackGround(UnitSlots[unit],posx,posy,flags);
    } else if( !strcmp(name,"patrol") ) {
      SendCommandPatrol(UnitSlots[unit],posx,posy,flags);
    } else if( !strcmp(name,"board") ) {
      SendCommandBoard(UnitSlots[unit],posx,posy,dunit,flags);
    } else if( !strcmp(name,"unload") ) {
      SendCommandUnload(UnitSlots[unit],posx,posy,dunit,flags);
    } else if( !strcmp(name,"build") ) {
      SendCommandBuildBuilding(UnitSlots[unit],posx,posy,UnitTypeByIdent(val),flags);
    } else if( !strcmp(name,"cancel-build") ) {
      SendCommandCancelBuilding(UnitSlots[unit],dunit);
    } else if( !strcmp(name,"harvest") ) {
      SendCommandHarvest(UnitSlots[unit],posx,posy,flags);
    } else if( !strcmp(name,"mine") ) {
      SendCommandMineGold(UnitSlots[unit],dunit,flags);
    } else if( !strcmp(name,"haul") ) {
      SendCommandHaulOil(UnitSlots[unit],dunit,flags);
    } else if( !strcmp(name,"return") ) {
      SendCommandReturnGoods(UnitSlots[unit],dunit,flags);
    } else if( !strcmp(name,"train") ) {
      SendCommandTrainUnit(UnitSlots[unit],UnitTypeByIdent(val),flags);
    } else if( !strcmp(name,"cancel-train") ) {
      SendCommandCancelTraining(UnitSlots[unit],num,val?UnitTypeByIdent(val):NULL);
    } else if( !strcmp(name,"upgrade-to") ) {
      SendCommandUpgradeTo(UnitSlots[unit],UnitTypeByIdent(val),flags);
    } else if( !strcmp(name,"cancel-upgrade-to") ) {
      SendCommandCancelUpgradeTo(UnitSlots[unit]);
    } else if( !strcmp(name,"research") ) {
      SendCommandResearch(UnitSlots[unit],UpgradeByIdent(val),flags);
    } else if( !strcmp(name,"cancel-research") ) {
      SendCommandCancelResearch(UnitSlots[unit]);
    } else if( !strcmp(name,"demolish") ) {
      SendCommandDemolish(UnitSlots[unit],posx,posy,dunit,flags);
    } else if( !strcmp(name,"spell-cast") ) {
      SendCommandSpellCast(UnitSlots[unit],posx,posy,dunit,num,flags);
    } else if( !strcmp(name,"auto-spell-cast") ) {
      SendCommandAutoSpellCast(UnitSlots[unit],num,posx);
    } else if( !strcmp(name,"diplomacy") ) {
      int state;
      if( !strcmp(val,"neutral") ) {
          state=DiplomacyNeutral;
      } else if( !strcmp(val,"allied") ) {
          state=DiplomacyAllied;
      } else if( !strcmp(val,"enemy") ) {
          state=DiplomacyEnemy;
      } else if( !strcmp(val,"crazy") ) {
          state=DiplomacyCrazy;
      } else {
          DebugLevel0Fn("Invalid diplomacy command: %s" _C_ val);
          state=-1;
      }
      SendCommandDiplomacy(posx,state,posy);
    } else if( !strcmp(name,"shared-vision") ) {
      int state;
      state=atoi(val);
      if( state!=0 && state!=1 ) {
          DebugLevel0Fn("Invalid shared vision command: %s" _C_ val);
          state=0;
      }
      SendCommandSharedVision(posx,state,posy);
    } else if( !strcmp(name,"input") ) {
      if (val[0]=='(') {
          CclCommand(val);
      } else {
          HandleCheats(val);
      }
    } else if( !strcmp(name,"quit") ) {
      CommandQuit(posx);
    } else {
      DebugLevel0Fn("Invalid name: %s" _C_ name);
    }

    ReplayLog=gh_cdr(ReplayLog);
}

/**
**    Replay user commands from log each cycle
*/
local void ReplayEachCycle(void)
{
    if( InitReplay ) {
      int i;
      for( i=0; i<PlayerMax; ++i ) {
          if( ReplayPlayers[i] ) {
            PlayerSetName(&Players[i], ReplayPlayers[i]);
          }
      }
      InitReplay=0;
    }

    if( gh_null_p(ReplayLog) ) {
      return;
    }

    if( NextLogCycle!=~0UL && NextLogCycle!=GameCycle ) {
      return;
    }

    do {
      DoNextReplay();
    } while( !gh_null_p(ReplayLog)
          && (NextLogCycle==~0UL || NextLogCycle==GameCycle) );

    if( gh_null_p(ReplayLog) ) {
      SetMessage("End of replay");
      GameObserve=0;
    }
}

/**
**    Replay user commands from log each cycle, single player games
*/
global void SinglePlayerReplayEachCycle(void)
{
    if( ReplayGameType==ReplaySinglePlayer ) {
      ReplayEachCycle();
    }
}

/**
**    Replay user commands from log each cycle, multiplayer games
*/
global void MultiPlayerReplayEachCycle(void)
{
    if( ReplayGameType==ReplayMultiPlayer ) {
      ReplayEachCycle();
    }
}
//@}

//----------------------------------------------------------------------------
//    Send game commands, maybe over the network.
//----------------------------------------------------------------------------

/**@name send */
//@{

/**
**    Send command: Unit stop.
**
**    @param unit pointer to unit.
*/
global void SendCommandStopUnit(Unit* unit)
{
    if( NetworkFildes==-1 ) {
      CommandLog("stop",unit,FlushCommands,-1,-1,NoUnitP,NULL,-1);
      CommandStopUnit(unit);
    } else {
      NetworkSendCommand(MessageCommandStop,unit,0,0,NoUnitP,0,FlushCommands);
    }
}

/**
**    Send command: Unit stand ground.
**
**    @param unit pointer to unit.
**    @param flush      Flag flush all pending commands.
*/
global void SendCommandStandGround(Unit* unit,int flush)
{
    if( NetworkFildes==-1 ) {
      CommandLog("stand-ground",unit,flush,-1,-1,NoUnitP,NULL,-1);
      CommandStandGround(unit,flush);
    } else {
      NetworkSendCommand(MessageCommandStand,unit,0,0,NoUnitP,0,flush);
    }
}

/**
**    Send command: Follow unit to position.
**
**    @param unit pointer to unit.
**    @param dest follow this unit.
**    @param flush      Flag flush all pending commands.
*/
global void SendCommandFollow(Unit* unit,Unit* dest,int flush)
{
    if( NetworkFildes==-1 ) {
      CommandLog("follow",unit,flush,-1,-1,dest,NULL,-1);
      CommandFollow(unit,dest,flush);
    } else {
      NetworkSendCommand(MessageCommandFollow,unit,0,0,dest,0,flush);
    }
}

/**
**    Send command: Move unit to position.
**
**    @param unit pointer to unit.
**    @param x    X map tile position to move to.
**    @param y    Y map tile position to move to.
**    @param flush      Flag flush all pending commands.
*/
global void SendCommandMove(Unit* unit,int x,int y,int flush)
{
    if( NetworkFildes==-1 ) {
      CommandLog("move",unit,flush,x,y,NoUnitP,NULL,-1);
      CommandMove(unit,x,y,flush);
    } else {
      NetworkSendCommand(MessageCommandMove,unit,x,y,NoUnitP,0,flush);
    }
}

/**
**    Send command: Unit repair.
**
**    @param unit pointer to unit.
**    @param x    X map tile position to repair.
**    @param y    Y map tile position to repair.
**    @param dest Unit to be repaired.
**    @param flush      Flag flush all pending commands.
*/
global void SendCommandRepair(Unit* unit,int x,int y,Unit* dest,int flush)
{
    if( NetworkFildes==-1 ) {
      CommandLog("repair",unit,flush,x,y,dest,NULL,-1);
      CommandRepair(unit,x,y,dest,flush);
    } else {
      NetworkSendCommand(MessageCommandRepair,unit,x,y,dest,0,flush);
    }
}

/**
**    Send command: Unit attack unit or at position.
**
**    @param unit pointer to unit.
**    @param x    X map tile position to attack.
**    @param y    Y map tile position to attack.
**    @param attack     or !=NoUnitP unit to be attacked.
**    @param flush      Flag flush all pending commands.
*/
global void SendCommandAttack(Unit* unit,int x,int y,Unit* attack,int flush)
{
    if( NetworkFildes==-1 ) {
      CommandLog("attack",unit,flush,x,y,attack,NULL,-1);
      CommandAttack(unit,x,y,attack,flush);
    } else {
      NetworkSendCommand(MessageCommandAttack,unit,x,y,attack,0,flush);
    }
}

/**
**    Send command: Unit attack ground.
**
**    @param unit pointer to unit.
**    @param x    X map tile position to fire on.
**    @param y    Y map tile position to fire on.
**    @param flush      Flag flush all pending commands.
*/
global void SendCommandAttackGround(Unit* unit,int x,int y,int flush)
{
    if( NetworkFildes==-1 ) {
      CommandLog("attack-ground",unit,flush,x,y,NoUnitP,NULL,-1);
      CommandAttackGround(unit,x,y,flush);
    } else {
      NetworkSendCommand(MessageCommandGround,unit,x,y,NoUnitP,0,flush);
    }
}

/**
**    Send command: Unit patrol between current and position.
**
**    @param unit pointer to unit.
**    @param x    X map tile position to patrol between.
**    @param y    Y map tile position to patrol between.
**    @param flush      Flag flush all pending commands.
*/
global void SendCommandPatrol(Unit* unit,int x,int y,int flush)
{
    if( NetworkFildes==-1 ) {
      CommandLog("patrol",unit,flush,x,y,NoUnitP,NULL,-1);
      CommandPatrolUnit(unit,x,y,flush);
    } else {
      NetworkSendCommand(MessageCommandPatrol,unit,x,y,NoUnitP,0,flush);
    }
}

/**
**    Send command: Unit board unit.
**
**    @param unit pointer to unit.
**    @param x    X map tile position (unused).
**    @param y    Y map tile position (unused).
**    @param dest Destination to be boarded.
**    @param flush      Flag flush all pending commands.
*/
global void SendCommandBoard(Unit* unit,int x,int y,Unit* dest,int flush)
{
    if( NetworkFildes==-1 ) {
      CommandLog("board",unit,flush,x,y,dest,NULL,-1);
      CommandBoard(unit,dest,flush);
    } else {
      NetworkSendCommand(MessageCommandBoard,unit,x,y,dest,0,flush);
    }
}

/**
**    Send command: Unit unload unit.
**
**    @param unit pointer to unit.
**    @param x    X map tile position of unload.
**    @param y    Y map tile position of unload.
**    @param what Passagier to be unloaded.
**    @param flush      Flag flush all pending commands.
*/
global void SendCommandUnload(Unit* unit,int x,int y,Unit* what,int flush)
{
    if( NetworkFildes==-1 ) {
      CommandLog("unload",unit,flush,x,y,what,NULL,-1);
      CommandUnload(unit,x,y,what,flush);
    } else {
      NetworkSendCommand(MessageCommandUnload,unit,x,y,what,0,flush);
    }
}

/**
**    Send command: Unit builds building at position.
**
**    @param unit pointer to unit.
**    @param x    X map tile position of construction.
**    @param y    Y map tile position of construction.
**    @param what pointer to unit-type of the building.
**    @param flush      Flag flush all pending commands.
*/
global void SendCommandBuildBuilding(Unit* unit,int x,int y
      ,UnitType* what,int flush)
{
    if( NetworkFildes==-1 ) {
      CommandLog("build",unit,flush,x,y,NoUnitP,what->Ident,-1);
      CommandBuildBuilding(unit,x,y,what,flush);
    } else {
      NetworkSendCommand(MessageCommandBuild,unit,x,y,NoUnitP,what,flush);
    }
}

/**
**    Send command: Cancel this building construction.
**
**    @param unit pointer to unit.
**    @param worker     Worker which should stop.
*/
global void SendCommandCancelBuilding(Unit* unit,Unit* worker)
{
    // FIXME: currently unit and worker are same?
    if( NetworkFildes==-1 ) {
      CommandLog("cancel-build",unit,FlushCommands,-1,-1,worker,NULL,-1);
      CommandCancelBuilding(unit,worker);
    } else {
      NetworkSendCommand(MessageCommandCancelBuild,unit,0,0,worker,0
            ,FlushCommands);
    }
}

/**
**    Send command: Unit harvest wood.
**
**    @param unit pointer to unit.
**    @param x    X map tile position where to harvest.
**    @param y    Y map tile position where to harvest.
**    @param flush      Flag flush all pending commands.
*/
global void SendCommandHarvest(Unit* unit,int x,int y,int flush)
{
    if( NetworkFildes==-1 ) {
      CommandLog("harvest",unit,flush,x,y,NoUnitP,NULL,-1);
      CommandHarvest(unit,x,y,flush);
    } else {
      NetworkSendCommand(MessageCommandHarvest,unit,x,y,NoUnitP,0,flush);
    }
}

/**
**    Send command: Unit mine gold.
**
**    @param unit pointer to unit.
**    @param dest pointer to destination (gold-mine).
**    @param flush      Flag flush all pending commands.
*/
global void SendCommandMineGold(Unit* unit,Unit* dest,int flush)
{
    if( NetworkFildes==-1 ) {
      CommandLog("mine",unit,flush,-1,-1,dest,NULL,-1);
      CommandMineGold(unit,dest,flush);
    } else {
      NetworkSendCommand(MessageCommandMine,unit,0,0,dest,0,flush);
    }
}

/**
**    Send command: Unit haul oil.
**
**    @param unit pointer to unit.
**    @param dest pointer to destination (oil-platform).
**    @param flush      Flag flush all pending commands.
*/
global void SendCommandHaulOil(Unit* unit,Unit* dest,int flush)
{
    if( NetworkFildes==-1 ) {
      CommandLog("haul",unit,flush,-1,-1,dest,NULL,-1);
      CommandHaulOil(unit,dest,flush);
    } else {
      NetworkSendCommand(MessageCommandHaul,unit,0,0,dest,0,flush);
    }
}

/**
**    Send command: Unit return goods.
**
**    @param unit pointer to unit.
**    @param goal pointer to destination of the goods. (NULL=search best)
**    @param flush      Flag flush all pending commands.
*/
global void SendCommandReturnGoods(Unit* unit,Unit* goal,int flush)
{
    if( NetworkFildes==-1 ) {
      CommandLog("return",unit,flush,-1,-1,goal,NULL,-1);
      CommandReturnGoods(unit,goal,flush);
    } else {
      NetworkSendCommand(MessageCommandReturn,unit,0,0,goal,0,flush);
    }
}

/**
**    Send command: Building/unit train new unit.
**
**    @param unit pointer to unit.
**    @param what pointer to unit-type of the unit to be trained.
**    @param flush      Flag flush all pending commands.
*/
global void SendCommandTrainUnit(Unit* unit,UnitType* what,int flush)
{
    if( NetworkFildes==-1 ) {
      CommandLog("train",unit,flush,-1,-1,NoUnitP,what->Ident,-1);
      CommandTrainUnit(unit,what,flush);
    } else {
      NetworkSendCommand(MessageCommandTrain,unit,0,0,NoUnitP,what,flush);
    }
}

/**
**    Send command: Cancel training.
**
**    @param unit Pointer to unit.
**    @param slot Slot of training queue to cancel.
**    @param type Unit-type of unit to cancel.
*/
global void SendCommandCancelTraining(Unit* unit,int slot,const UnitType* type)
{
    if( NetworkFildes==-1 ) {
      CommandLog("cancel-train",unit,FlushCommands,-1,-1,NoUnitP,
            type ? type->Ident : NULL,slot);
      CommandCancelTraining(unit,slot,type);
    } else {
      NetworkSendCommand(MessageCommandCancelTrain,unit,slot,0,NoUnitP,type
            ,FlushCommands);
    }
}

/**
**    Send command: Building starts upgrading to.
**
**    @param unit pointer to unit.
**    @param what pointer to unit-type of the unit upgrade.
**    @param flush      Flag flush all pending commands.
*/
global void SendCommandUpgradeTo(Unit* unit,UnitType* what,int flush)
{
    if( NetworkFildes==-1 ) {
      CommandLog("upgrade-to",unit,flush,-1,-1,NoUnitP,what->Ident,-1);
      CommandUpgradeTo(unit,what,flush);
    } else {
      NetworkSendCommand(MessageCommandUpgrade,unit,0,0,NoUnitP,what,flush);
    }
}

/**
**    Send command: Cancel building upgrading to.
**
**    @param unit pointer to unit.
*/
global void SendCommandCancelUpgradeTo(Unit* unit)
{
    if( NetworkFildes==-1 ) {
      CommandLog("cancel-upgrade-to",unit,FlushCommands
            ,-1,-1,NoUnitP,NULL,-1);
      CommandCancelUpgradeTo(unit);
    } else {
      NetworkSendCommand(MessageCommandCancelUpgrade,unit
            ,0,0,NoUnitP,NULL,FlushCommands);
    }
}

/**
**    Send command: Building/unit research.
**
**    @param unit pointer to unit.
**    @param what research-type of the research.
**    @param flush      Flag flush all pending commands.
*/
global void SendCommandResearch(Unit* unit,Upgrade* what,int flush)
{
    if( NetworkFildes==-1 ) {
      CommandLog("research",unit,flush,-1,-1,NoUnitP,what->Ident,-1);
      CommandResearch(unit,what,flush);
    } else {
      NetworkSendCommand(MessageCommandResearch,unit
            ,what-Upgrades,0,NoUnitP,NULL,flush);
    }
}

/**
**    Send command: Cancel Building/unit research.
**
**    @param unit pointer to unit.
*/
global void SendCommandCancelResearch(Unit* unit)
{
    if( NetworkFildes==-1 ) {
      CommandLog("cancel-research",unit,FlushCommands,-1,-1,NoUnitP,NULL,-1);
      CommandCancelResearch(unit);
    } else {
      NetworkSendCommand(MessageCommandCancelResearch,unit
            ,0,0,NoUnitP,NULL,FlushCommands);
    }
}

/**
**    Send command: Unit demolish at position.
**
**    @param unit pointer to unit.
**    @param x    X map tile position where to demolish.
**    @param y    Y map tile position where to demolish.
**    @param attack     or !=NoUnitP unit to be demolished.
**    @param flush      Flag flush all pending commands.
*/
global void SendCommandDemolish(Unit* unit,int x,int y,Unit* attack,int flush)
{
    if( NetworkFildes==-1 ) {
      CommandLog("demolish",unit,flush,x,y,attack,NULL,-1);
      CommandDemolish(unit,x,y,attack,flush);
    } else {
      NetworkSendCommand(MessageCommandDemolish,unit,x,y,attack,NULL,flush);
    }
}

/**
**    Send command: Unit spell cast on position/unit.
**
**    @param unit pointer to unit.
**    @param x    X map tile position where to cast spell.
**    @param y    Y map tile position where to cast spell.
**    @param dest Cast spell on unit (if exist).
**    @param spellid  Spell type id.
**    @param flush      Flag flush all pending commands.
*/
global void SendCommandSpellCast(Unit* unit,int x,int y,Unit* dest,int spellid
      ,int flush)
{
    if( NetworkFildes==-1 ) {
      CommandLog("spell-cast",unit,flush,x,y,dest,NULL,spellid);
      CommandSpellCast(unit,x,y,dest,SpellTypeById(spellid),flush);
    } else {
      NetworkSendCommand(MessageCommandSpellCast+spellid
            ,unit,x,y,dest,NULL,flush);
    }
}

/**
**    Send command: Unit auto spell cast.
**
**    @param unit pointer to unit.
**    @param spellid  Spell type id.
**    @param on   1 for auto cast on, 0 for off.
*/
global void SendCommandAutoSpellCast(Unit* unit,int spellid,int on)
{
    if( NetworkFildes==-1 ) {
      CommandLog("auto-spell-cast",unit,FlushCommands,on,-1,NoUnitP
            ,NULL,spellid);
      CommandAutoSpellCast(unit,on?SpellTypeById(spellid):NULL);
    } else {
      NetworkSendCommand(MessageCommandSpellCast+spellid
            ,unit,on,-1,NoUnitP,NULL,FlushCommands);
    }
}

/**
**    Send command: Diplomacy changed.
**
**    @param player     Player which changes his state.
**    @param state      New diplomacy state.
**    @param opponent   Opponent.
*/
global void SendCommandDiplomacy(int player,int state,int opponent)
{
    if( NetworkFildes==-1 ) {
      switch( state ) {
          case DiplomacyNeutral:
            CommandLog("diplomacy",NoUnitP,0,player,opponent,
                  NoUnitP,"neutral",-1);
            break;
          case DiplomacyAllied:
            CommandLog("diplomacy",NoUnitP,0,player,opponent,
                  NoUnitP,"allied",-1);
            break;
          case DiplomacyEnemy:
            CommandLog("diplomacy",NoUnitP,0,player,opponent,
                  NoUnitP,"enemy",-1);
            break;
          case DiplomacyCrazy:
            CommandLog("diplomacy",NoUnitP,0,player,opponent,
                  NoUnitP,"crazy",-1);
            break;
      }
      CommandDiplomacy(player,state,opponent);
    } else {
      NetworkSendExtendedCommand(ExtendedMessageDiplomacy,
            -1,player,state,opponent,0);
    }
}

/**
**    Send command: Shared vision changed.
**
**    @param player     Player which changes his state.
**    @param state      New shared vision state.
**    @param opponent   Opponent.
*/
global void SendCommandSharedVision(int player,int state,int opponent)
{
    if( NetworkFildes==-1 ) {
      if( state==0 ) {
          CommandLog("shared-vision",NoUnitP,0,player,opponent,
                NoUnitP,"0",-1);
      } else {
          CommandLog("shared-vision",NoUnitP,0,player,opponent,
                NoUnitP,"1",-1);
      }
      CommandSharedVision(player,state,opponent);
    } else {
      NetworkSendExtendedCommand(ExtendedMessageSharedVision,
            -1,player,state,opponent,0);
    }
}

//@}

//----------------------------------------------------------------------------
//    Parse the message, from the network.
//----------------------------------------------------------------------------

/**@name parse */
//@{

/**
**    Parse a command (from network).
**
**    @param msgnr      Network message type
**    @param unum Unit number (slot) that receive the command.
**    @param x    optional X map position.
**    @param y    optional y map position.
**    @param dstnr      optional destination unit.
*/
global void ParseCommand(unsigned char msgnr,UnitRef unum,
      unsigned short x,unsigned short y,UnitRef dstnr)
{
    Unit* unit;
    Unit* dest;
    int id;
    int status;

    DebugLevel3Fn(" %d cycle %lu\n" _C_ msgnr _C_ GameCycle);

    unit=UnitSlots[unum];
    DebugCheck( !unit );
    //
    //      Check if unit is already killed?
    //
    if( unit->Destroyed ) {
      DebugLevel0Fn(" destroyed unit skipping %d\n" _C_ UnitNumber(unit));
      return;
    }

    DebugCheck( !unit->Type );

    status=(msgnr&0x80)>>7;

    // Note: destroyed destination unit is handled by the action routines.

    switch( msgnr&0x7F ) {
      case MessageSync:
          return;
      case MessageQuit:
          return;
      case MessageChat:
          return;

      case MessageCommandStop:
          CommandLog("stop",unit,FlushCommands,-1,-1,NoUnitP,NULL,-1);
          CommandStopUnit(unit);
          break;
      case MessageCommandStand:
          CommandLog("stand-ground",unit,status,-1,-1,NoUnitP,NULL,-1);
          CommandStandGround(unit,status);
          break;
      case MessageCommandFollow:
          dest=NoUnitP;
          if( dstnr!=(unsigned short)0xFFFF ) {
            dest=UnitSlots[dstnr];
            DebugCheck( !dest || !dest->Type );
          }
          CommandLog("follow",unit,status,-1,-1,dest,NULL,-1);
          CommandFollow(unit,dest,status);
          break;
      case MessageCommandMove:
          CommandLog("move",unit,status,x,y,NoUnitP,NULL,-1);
          CommandMove(unit,x,y,status);
          break;
      case MessageCommandRepair:
          dest=NoUnitP;
          if( dstnr!=(unsigned short)0xFFFF ) {
            dest=UnitSlots[dstnr];
            DebugCheck( !dest || !dest->Type );
          }
          CommandLog("repair",unit,status,x,y,dest,NULL,-1);
          CommandRepair(unit,x,y,dest,status);
          break;
      case MessageCommandAttack:
          dest=NoUnitP;
          if( dstnr!=(unsigned short)0xFFFF ) {
            dest=UnitSlots[dstnr];
            DebugCheck( !dest || !dest->Type );
          }
          CommandLog("attack",unit,status,x,y,dest,NULL,-1);
          CommandAttack(unit,x,y,dest,status);
          break;
      case MessageCommandGround:
          CommandLog("attack-ground",unit,status,x,y,NoUnitP,NULL,-1);
          CommandAttackGround(unit,x,y,status);
          break;
      case MessageCommandPatrol:
          CommandLog("patrol",unit,status,x,y,NoUnitP,NULL,-1);
          CommandPatrolUnit(unit,x,y,status);
          break;
      case MessageCommandBoard:
          dest=NoUnitP;
          if( dstnr!=(unsigned short)0xFFFF ) {
            dest=UnitSlots[dstnr];
            DebugCheck( !dest || !dest->Type );
          }
          CommandLog("board",unit,status,x,y,dest,NULL,-1);
          CommandBoard(unit,dest,status);
          break;
      case MessageCommandUnload:
          dest=NoUnitP;
          if( dstnr!=(unsigned short)0xFFFF ) {
            dest=UnitSlots[dstnr];
            DebugCheck( !dest || !dest->Type );
          }
          CommandLog("unload",unit,status,x,y,dest,NULL,-1);
          CommandUnload(unit,x,y,dest,status);
          break;
      case MessageCommandBuild:
          CommandLog("build",unit,status,x,y,NoUnitP,UnitTypes[dstnr].Ident,
                -1);
          CommandBuildBuilding(unit,x,y,UnitTypes+dstnr,status);
          break;
      case MessageCommandCancelBuild:
          // dest is the worker building the unit...
          dest=NoUnitP;
          if( dstnr!=(unsigned short)0xFFFF ) {
            dest=UnitSlots[dstnr];
            DebugCheck( !dest || !dest->Type );
          }
          CommandLog("cancel-build",unit,FlushCommands,-1,-1,dest,NULL,-1);
          CommandCancelBuilding(unit,dest);
          break;
      case MessageCommandHarvest:
          CommandLog("harvest",unit,status,x,y,NoUnitP,NULL,-1);
          CommandHarvest(unit,x,y,status);
          break;
      case MessageCommandMine:
          dest=NoUnitP;
          if( dstnr!=(unsigned short)0xFFFF ) {
            dest=UnitSlots[dstnr];
            DebugCheck( !dest || !dest->Type );
          }
          CommandLog("mine",unit,status,-1,-1,dest,NULL,-1);
          CommandMineGold(unit,dest,status);
          break;
      case MessageCommandHaul:
          dest=NoUnitP;
          if( dstnr!=(unsigned short)0xFFFF ) {
            dest=UnitSlots[dstnr];
            DebugCheck( !dest || !dest->Type );
          }
          CommandLog("haul",unit,status,-1,-1,dest,NULL,-1);
          CommandHaulOil(unit,dest,status);
          break;
      case MessageCommandReturn:
          dest=NoUnitP;
          if( dstnr!=(unsigned short)0xFFFF ) {
            dest=UnitSlots[dstnr];
            DebugCheck( !dest || !dest->Type );
          }
          CommandLog("return",unit,status,-1,-1,dest,NULL,-1);
          CommandReturnGoods(unit,dest,status);
          break;
      case MessageCommandTrain:
          CommandLog("train",unit,status,-1,-1,NoUnitP
                ,UnitTypes[dstnr].Ident,-1);
          CommandTrainUnit(unit,UnitTypes+dstnr,status);
          break;
      case MessageCommandCancelTrain:
          // We need (short)x for the last slot -1
          if( dstnr!=(unsigned short)0xFFFF ) {
            CommandLog("cancel-train",unit,FlushCommands,-1,-1,NoUnitP,
                  UnitTypes[dstnr].Ident,(short)x);
            CommandCancelTraining(unit,(short)x,UnitTypes+dstnr);
          } else {
            CommandLog("cancel-train",unit,FlushCommands,-1,-1,NoUnitP,
                  NULL,(short)x);
            CommandCancelTraining(unit,(short)x,NULL);
          }
          break;
      case MessageCommandUpgrade:
          CommandLog("upgrade-to",unit,status,-1,-1,NoUnitP
                ,UnitTypes[dstnr].Ident,-1);
          CommandUpgradeTo(unit,UnitTypes+dstnr,status);
          break;
      case MessageCommandCancelUpgrade:
          CommandLog("cancel-upgrade-to",unit,FlushCommands,-1,-1,NoUnitP
                ,NULL,-1);
          CommandCancelUpgradeTo(unit);
          break;
      case MessageCommandResearch:
          CommandLog("research",unit,status,-1,-1,NoUnitP
                ,Upgrades[x].Ident,-1);
          CommandResearch(unit,Upgrades+x,status);
          break;
      case MessageCommandCancelResearch:
          CommandLog("cancel-research",unit,FlushCommands,-1,-1,NoUnitP
                ,NULL,-1);
          CommandCancelResearch(unit);
          break;
      case MessageCommandDemolish:
          dest=NoUnitP;
          if( dstnr!=(unsigned short)0xFFFF ) {
            dest=UnitSlots[dstnr];
            DebugCheck( !dest || !dest->Type );
          }
          CommandLog("demolish",unit,status,x,y,dest,NULL,-1);
          CommandDemolish(unit,x,y,dest,status);
          break;
      default:
          id = (msgnr&0x7f) - MessageCommandSpellCast;
          if( y!=(unsigned short)0xFFFF ) {
            dest=NoUnitP;
            if( dstnr!=(unsigned short)0xFFFF ) {
                dest=UnitSlots[dstnr];
                DebugCheck( !dest || !dest->Type );
            }
            CommandLog("spell-cast",unit,status,x,y,dest,NULL,id);
            CommandSpellCast(unit,x,y,dest,SpellTypeById(id),status);
          } else {
            CommandLog("auto-spell-cast",unit,status,x,-1,NoUnitP,NULL,id);
            CommandAutoSpellCast(unit,x?SpellTypeById(id):NULL);
          }
          break;
    }
}

/**
**    Parse an extended command (from network).
**
**    @param type Network extended message type
**    @param status     Bit 7 of message type
**    @param arg1 Messe argument 1
**    @param arg2 Messe argument 2
**    @param arg3 Messe argument 3
**    @param arg4 Messe argument 4
*/
global void ParseExtendedCommand(unsigned char type,int status,
      unsigned char arg1, unsigned short arg2, unsigned short arg3,
      unsigned short arg4)
{
    DebugLevel3Fn(" %d cycle %lu\n" _C_ type _C_ GameCycle);

    // Note: destroyed units are handled by the action routines.

    switch( type ) {
      case ExtendedMessageDiplomacy:
          switch( arg3 ) {
            case DiplomacyNeutral:
                CommandLog("diplomacy",NoUnitP,0,arg2,arg4,
                      NoUnitP,"neutral",-1);
                break;
            case DiplomacyAllied:
                CommandLog("diplomacy",NoUnitP,0,arg2,arg4,
                      NoUnitP,"allied",-1);
                break;
            case DiplomacyEnemy:
                CommandLog("diplomacy",NoUnitP,0,arg2,arg4,
                      NoUnitP,"enemy",-1);
                break;
            case DiplomacyCrazy:
                CommandLog("diplomacy",NoUnitP,0,arg2,arg4,
                      NoUnitP,"crazy",-1);
                break;
          }
          CommandDiplomacy(arg2,arg3,arg4);
          break;
      case ExtendedMessageSharedVision:
          if( arg3==0 ) {
            CommandLog("shared-vision",NoUnitP,0,arg2,arg4,
                  NoUnitP,"0",-1);
          } else {
            CommandLog("shared-vision",NoUnitP,0,arg2,arg4,
                  NoUnitP,"1",-1);
          }
          CommandSharedVision(arg2,arg3,arg4);
          break;
      default:
          DebugLevel0Fn("Unknown extended message %u/%s %u %u %u %u\n" _C_
            type _C_ status ? "flush" : "-"
            _C_ arg1 _C_ arg2 _C_ arg3 _C_ arg4);
          break;
    }
}

//@}

//@}

Generated by  Doxygen 1.6.0   Back to index