diff --git a/src/network/commands.cpp b/src/network/commands.cpp new file mode 100644 index 000000000..cf3912125 --- /dev/null +++ b/src/network/commands.cpp @@ -0,0 +1,682 @@ +// ___________ _________ _____ __ +// \_ _____/______ ____ ____ \_ ___ \____________ _/ ____\/ |_ +// | __) \_ __ \_/ __ \_/ __ \/ \ \/\_ __ \__ \\ __\\ __\ +// | \ | | \/\ ___/\ ___/\ \____| | \// __ \| | | | +// \___ / |__| \___ >\___ >\______ /|__| (____ /__| |__| +// \/ \/ \/ \/ \/ +// ______________________ ______________________ +// 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 by Lutz Sammer +// +// $Id$ + +//@{ + +//---------------------------------------------------------------------------- +// Includes +//---------------------------------------------------------------------------- + +#include <stdio.h> +#include <time.h> + +#include "freecraft.h" +#include "unit.h" +#include "map.h" +#include "actions.h" +#include "player.h" +#include "network.h" + +//---------------------------------------------------------------------------- +// Declaration +//---------------------------------------------------------------------------- + +//---------------------------------------------------------------------------- +// Variables +//---------------------------------------------------------------------------- + +global int CommandLogEnabled; /// True if command log is on + +//---------------------------------------------------------------------------- +// 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 position Flag X,Y contains position or value or nothing. +** @param x optional X map position. +** @param y optional y map position. +** @param dest optional destination unit. +** @param type optional command argument (unit-type,...). +*/ +local void CommandLog(const char* name,const Unit* unit,int flag, + int position,unsigned x,unsigned y,const Unit* dest,const char* value) +{ + static FILE* logf; + + if( !CommandLogEnabled ) { + return; + } + + if( !logf ) { + time_t now; + + logf=fopen("command.log","wb"); + if( !logf ) { + return; + } + fprintf(logf,";;; Log file generated by FreeCraft Version " + VERSION "\n"); + time(&now); + fprintf(logf,";;;\tDate: %s",ctime(&now)); + fprintf(logf,";;;\tMap: %s\n\n",TheMap.Description); + } + fprintf(logf,"(log %d 'U%Zd '%s '%s", + FrameCounter,UnitNumber(unit),name, + flag ? "flush" : "append"); + switch( position ) { + case 1: + fprintf(logf," (%d %d)",x,y); + break; + case 2: + fprintf(logf," %d",x); + } + if( dest ) { + fprintf(logf," 'U%Zd",UnitNumber(unit)); + } + if( value ) { + fprintf(logf," '%s",value); + } + fprintf(logf,")\n"); + fflush(logf); +} + +//@} + +//---------------------------------------------------------------------------- +// Send game commands, maybe over the network. +//---------------------------------------------------------------------------- + +/**@name send */ +//@{ + +/** +** Send command: Unit stop. +** +** @param unit pointer to unit. +*/ +global void SendCommandStopUnit(Unit* unit) +{ + CommandLog("stop",unit,1,0,0,0,NoUnitP,NULL); + if( NetworkFildes==-1 ) { + CommandStopUnit(unit); + } else { + NetworkSendCommand(MessageCommandStop,unit,0,0,NoUnitP,0,1); + } +} + +/** +** Send command: Unit stand ground. +** +** @param unit pointer to unit. +** @param flush Flag flush all pending commands. +*/ +global void SendCommandStandGround(Unit* unit,int flush) +{ + CommandLog("stand-ground",unit,flush,0,0,0,NoUnitP,NULL); + if( NetworkFildes==-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 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 SendCommandFollow(Unit* unit,Unit* dest,int flush) +{ + CommandLog("move",unit,flush,0,0,0,dest,NULL); + if( NetworkFildes==-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) +{ + CommandLog("move",unit,flush,1,x,y,NoUnitP,NULL); + if( NetworkFildes==-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 flush Flag flush all pending commands. +*/ +global void SendCommandRepair(Unit* unit,int x,int y,Unit* dest,int flush) +{ + CommandLog("repair",unit,flush,1,x,y,dest,NULL); + if( NetworkFildes==-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) +{ + CommandLog("attack",unit,flush,1,x,y,attack,NULL); + if( NetworkFildes==-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) +{ + CommandLog("attack-ground",unit,flush,1,x,y,NoUnitP,NULL); + if( NetworkFildes==-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) +{ + CommandLog("patrol",unit,flush,1,x,y,NoUnitP,NULL); + if( NetworkFildes==-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 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) +{ + CommandLog("board",unit,flush,1,x,y,dest,NULL); + if( NetworkFildes==-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) +{ + CommandLog("unload",unit,flush,1,x,y,what,NULL); + if( NetworkFildes==-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) +{ + CommandLog("build",unit,flush,1,x,y,NULL,what->Ident); + if( NetworkFildes==-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. +*/ +global void SendCommandCancelBuilding(Unit* unit,Unit* worker) +{ + // FIXME: currently unit and worker are same? + CommandLog("cancel-build",unit,1,0,0,0,worker,NULL); + if( NetworkFildes==-1 ) { + CommandCancelBuilding(unit,worker); + } else { + NetworkSendCommand(MessageCommandCancelBuild,unit,0,0,worker,0,1); + } +} + +/** +** 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) +{ + CommandLog("harvest",unit,flush,1,x,y,NoUnitP,NULL); + if( NetworkFildes==-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) +{ + CommandLog("mine",unit,flush,0,0,0,dest,NULL); + if( NetworkFildes==-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) +{ + CommandLog("haul",unit,flush,0,0,0,dest,NULL); + if( NetworkFildes==-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 flush Flag flush all pending commands. +*/ +global void SendCommandReturnGoods(Unit* unit,int flush) +{ + CommandLog("return",unit,flush,0,0,0,NoUnitP,NULL); + if( NetworkFildes==-1 ) { + CommandReturnGoods(unit,flush); + } else { + NetworkSendCommand(MessageCommandReturn,unit,0,0,NoUnitP,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) +{ + CommandLog("train",unit,flush,0,0,0,NULL,what->Ident); + if( NetworkFildes==-1 ) { + CommandTrainUnit(unit,what,flush); + } else { + NetworkSendCommand(MessageCommandTrain,unit,0,0,NoUnitP,what,flush); + } +} + +/** +** Send command: Cancel training. +** +** @param unit pointer to unit. +*/ +global void SendCommandCancelTraining(Unit* unit,int slot) +{ + CommandLog("cancel-train",unit,1,2,slot,0,NoUnitP,NULL); + if( NetworkFildes==-1 ) { + CommandCancelTraining(unit,slot); + } else { + NetworkSendCommand(MessageCommandCancelTrain,unit,slot,0,NoUnitP,0,1); + } +} + +/** +** 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) +{ + CommandLog("upgrade-to",unit,flush,0,0,0,NULL,what->Ident); + if( NetworkFildes==-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) +{ + CommandLog("cancel-upgrade-to",unit,1,0,0,0,NoUnitP,NULL); + if( NetworkFildes==-1 ) { + CommandCancelUpgradeTo(unit); + } else { + NetworkSendCommand(MessageCommandCancelUpgrade,unit + ,0,0,NoUnitP,NULL,1); + } +} + +/** +** 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) +{ + CommandLog("research",unit,flush,0,0,0,NULL,what->Ident); + if( NetworkFildes==-1 ) { + CommandResearch(unit,what,flush); + } else { + NetworkSendCommand(MessageCommandResearch,unit + ,what-Upgrades,0,NoUnitP,0,flush); + } +} + +/** +** Send command: Cancel Building/unit research. +** +** @param unit pointer to unit. +*/ +global void SendCommandCancelResearch(Unit* unit) +{ + CommandLog("cancel-research",unit,1,0,0,0,NoUnitP,NULL); + if( NetworkFildes==-1 ) { + CommandCancelResearch(unit); + } else { + NetworkSendCommand(MessageCommandCancelResearch,unit + ,0,0,NoUnitP,0,1); + } +} + +/** +** 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) +{ + CommandLog("demolish",unit,flush,1,x,y,attack,NULL); + if( NetworkFildes==-1 ) { + CommandDemolish(unit,x,y,attack,flush); + } else { + NetworkSendCommand(MessageCommandDemolish,unit,x,y,attack,0,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 attack 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) +{ + CommandLog("spell-cast",unit,flush,1,x,y,dest,NULL); //FIXME: vladi: spellid? + if( NetworkFildes==-1 ) { + CommandSpellCast(unit,x,y,dest,spellid,flush); + } else { + NetworkSendCommand(MessageCommandSpellCast+spellid,unit,x,y,dest,0,flush); + } +} + +//@} + + +/**@name parse */ +//@{ + +/** +** Parse a command (from network). +** +** @param Type 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 Dest optional destination unit. +*/ +global void ParseCommand(unsigned short Type,UnitRef Unum,unsigned short x,unsigned short y,UnitRef Dest) +{ + Unit *unit, *dest; + int id, status; + + DebugLevel3Fn(" %d frame %d\n", Type, FrameCounter); + + unit=UnitSlots[Unum]; + DebugCheck( !unit ); + if( unit->Destroyed ) { + DebugLevel0Fn(" destroyed unit skipping %Zd\n" + ,UnitNumber(unit)); + return; + } + + status=(Type&0x80)>>7; + + // Note: destroyed destination unit is handled by the action routines. + + switch( Type&0x7F ) { + case MessageSync: + return; + case MessageQuit: + return; + case MessageCommandStop: + CommandStopUnit(unit); + break; + case MessageCommandStand: + CommandStandGround(unit,status); + break; + case MessageCommandMove: + CommandMove(unit,x,y,status); + break; + case MessageCommandAttack: + dest=NoUnitP; + DebugLevel3Fn(" %x\n",Dest); + if( Dest!=(unsigned short)0xFFFF ) { + dest=UnitSlots[Dest]; + DebugCheck( !dest ); + } + CommandAttack(unit,x,y,dest,status); + break; + case MessageCommandGround: + CommandAttackGround(unit,x,y,status); + break; + case MessageCommandPatrol: + CommandPatrolUnit(unit,x,y,status); + break; + case MessageCommandBoard: + dest=NoUnitP; + if( Dest!=(unsigned short)0xFFFF ) { + dest=UnitSlots[Dest]; + DebugCheck( !dest ); + } + CommandBoard(unit,dest,status); + break; + case MessageCommandUnload: + dest=NoUnitP; + if( Dest!=(unsigned short)0xFFFF ) { + dest=UnitSlots[Dest]; + DebugCheck( !dest ); + } + CommandUnload(unit,x,y,dest,status); + break; + case MessageCommandBuild: + CommandBuildBuilding(unit,x,y + ,UnitTypes+Dest,status); + break; + case MessageCommandCancelBuild: + // dest is the worker building the unit... + dest=NoUnitP; + if( Dest!=(unsigned short)0xFFFF ) { + dest=UnitSlots[Dest]; + DebugCheck( !dest ); + } + CommandCancelBuilding(unit,dest); + break; + case MessageCommandHarvest: + CommandHarvest(unit,x,y,status); + break; + case MessageCommandMine: + dest=NoUnitP; + if( Dest!=(unsigned short)0xFFFF ) { + dest=UnitSlots[Dest]; + DebugCheck( !dest ); + } + CommandMineGold(unit,dest,status); + break; + case MessageCommandHaul: + dest=NoUnitP; + if( Dest!=(unsigned short)0xFFFF ) { + dest=UnitSlots[Dest]; + DebugCheck( !dest ); + } + CommandHaulOil(unit,dest,status); + break; + case MessageCommandReturn: + CommandReturnGoods(unit,status); + break; + case MessageCommandTrain: + CommandTrainUnit(unit,UnitTypes+Dest,status); + break; + case MessageCommandCancelTrain: + // FIXME: cancel slot? + CommandCancelTraining(unit,0); + break; + case MessageCommandUpgrade: + CommandUpgradeTo(unit,UnitTypes+Dest,status); + break; + case MessageCommandResearch: + CommandResearch(unit,Upgrades+x,status); + break; + case MessageCommandDemolish: + dest=NoUnitP; + if( Dest!=(unsigned short)0xFFFF ) { + dest=UnitSlots[Dest]; + DebugCheck( !dest ); + } + CommandDemolish(unit,x,y,dest,status); + break; + default: + id = (Type&0x7f) - MessageCommandSpellCast; + dest=NoUnitP; + if( Dest!=(unsigned short)0xFFFF ) { + dest=UnitSlots[Dest]; + DebugCheck( !dest ); + } + CommandSpellCast(unit,x,y,dest,id,status); + break; + } +} + +//@} + +//@}