/**************************************************************************************************************************** ** TA4 COBalt BOS Library ** ** ** ** This file allows easy interfacing with TA's COBalt functions. This is not the most efficient way of doing things but ** ** it is readable and easy to maintain. An optimized library may soon be available, though even that would not be as ** ** efficient as customizing the code for each individual unit by hand. ** ** ** ** Chat about TA on IRC: irc.gnug.org OR www.tauniverse.com (note the www. NOT irc. for tauniverse) ** ** Channel: #cc ** ** ** ** Author: Mafia (a.k.a. Prognosis) (itsuneek@postmaster.co.uk) ** ** Public Domain ** ****************************************************************************************************************************/ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //Operations: //Each call to COBalt must specify an operation ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #define Opcode__Get 0 #define Opcode__Set 1 #define Opcode__PeekMemory 2 #define Opcode__PokeMemory 3 #define Opcode__CreateNewStruct 4 #define Opcode__DeleteStruct 5 #define Opcode__CopyStruct 6 #define Opcode__PrintMessage 7 #define Opcode__CallDLLProc 8 #define Opcode__ToggleDLL 9 //can cause memory leaks if custom created structs aren't destroyed ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //Struct Type Values (create/delete/copystruct can only be used on UnitDefStruct__): //These are used for the memberof argument and the structtype argument for create/delete/copystruct //Note that Constant__ and Generic__ are not structures, but certain values fall into those two categories //Only UnitDefStruct__ may be specified for the create/copy/deletestruct functions. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #define Constant__ 0 //can only get values of this type, not set #define Generic__ 1 //can only get values of this type, not set #define IsUnitStruct__ 2 //get or set members of #define UnitDefStruct__ 3 //can create new structs of this & get or set members #define UnitOrdersStruct__ 4 //can only get members of, not set #define UnitStruct__ 5 //get or set members of #define WeaponStruct__ 6 //can only get members of, not set ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //Constant Values (none yet): //This section will eventually have things like max starting metal, max units, etc. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //Generic Values: //Misc. Values //Please note that Generic__HitUnit should always be the same as Generic__CurrentUnit. If not, something is wrong -- see //below for details. //These values may only be specified for 'cobaltGet'; they cannot be cobaltSet. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #define Generic__AttackerUnit 0 //the unit who shot at us (if any) #define Generic__HitUnit 1 //the unit that was hit by the shot. If this does not match //Generic__CurrentUnit, something is wrong. This provides an easy way //to make sure that the GetAttacker feature is working but checking for //the concurrence of the two values is probably not necessary. If the //two values do not match, however, this means that GetAttacker is not //being run in sync with the current script. In such an event, the only //way to retrieve the attacker is by means of UnitStruct__Attacker, but //this method is probably not as safe as Generic__AttackerUnit. If you //don't understand any of this, just ignore it :) #define Generic__CurrentUnit 2 //this unit #define Generic__CurrentFunction 3 //the index # of the current function #define Generic__ScriptProgramCounter 4 //how far we are into the script ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //IsUnit Values: //Only contains the current speed at the moment (can get or set) ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #define IsUnitStruct__CurrentRawSpeed 0 //to get FBI file speed, multiply this by (1 / 65536) //result * 12 = speed in m/s ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //UnitDefStruct Values: //UnitDefStruct is the unit template -- it contains values common to each instance of a unit. These values can be used by //cobaltGet or cobaltSet, but if used by set, a new struct should be created and used, as setting a template value will //affect all units of the type, otherwise. For example, changing a value in the CORE Slasher's template will affect all //CORE Slashers. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #define UnitDefStruct__pszName 0 #define UnitDefStruct__pszUnitName 1 #define UnitDefStruct__pszDescription 2 #define UnitDefStruct__pszObjectName 3 #define UnitDefStruct__pszSide 4 #define UnitDefStruct__RawSpeed 5 //to get the FBI speed, multiply this number by (1 / 65536) #define UnitDefStruct__MaxHP 6 #define UnitDefStruct__WorkerTime 7 #define UnitDefStruct__HealTime 8 #define UnitDefStruct__SightDistance 9 #define UnitDefStruct__RadarDistance 10 #define UnitDefStruct__SonarDistance 11 #define UnitDefStruct__BuildDistance 12 #define UnitDefStruct__ManeuverLeashLength 13 #define UnitDefStruct__CruiseAlt 14 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //UnitOrdersStruct Values: //Right now it is only possible to get these values and only for the unit's first waypoint ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #define UnitOrdersStruct__PosX 1 #define UnitOrdersStruct__PosZ 2 #define UnitOrdersStruct__PosY 3 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //UnitStruct Values: //These values may be used for either cobaltGet or cobaltSet ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #define UnitStruct__UnitState 0 //don't know what this is #define UnitStruct__ZTurn 1 //I think these are multiplied by TA's angular constant (182.044444) #define UnitStruct__XTurn 2 #define UnitStruct__YTurn 3 #define UnitStruct__XPos 4 //pos values are in TA linear units (multipled by 163840) #define UnitStruct__ZPos 5 #define UnitStruct__YPos 6 #define UnitStruct__UnitDef 7 //pointer to the unit template -- used with create/copy/deletestruct #define UnitStruct__Kills 8 #define UnitStruct__Attacker 9 //this might only work for buildings... Generic__AttackerUnit is safer #define UnitStruct__Height 10 //not sure of the details of this one #define UnitStruct__Health 11 #define UnitStruct__IsCloaked 12 //1 for no, 5 for yes. changing this might not do anything, though... #define UnitStruct__UnitSelected 13 //0x71 (113) for selected, 0x21 (33) for not selected #define UnitStruct__Status 14 //looks to contain status bits? //for cloaked, set this to 0xB (11), for visible, set to 3 -- I think this //is a better way of cloaking than via UnitStruct__IsCloaked (which seems //to be set to 5 *after* the unit decides to cloak) //set this to 0x43 (67 decimal) to kill the unit -- but no explosion is //triggered, the unit just vanishes ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //WeaponStruct Values: //These values are templated and may only be used with cobaltGet //The weapon to operate on must also be specified ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #define WeaponStruct__pszWeaponName 0 #define WeaponStruct__pszWeaponDescription 1 #define WeaponStruct__DefaultDamage 2 //this is the default damage -- the custom damage values are different #define WeaponStruct__AOE 3 //area of effect #define WeaponStruct__EdgeEffectiveness 4 #define WeaponStruct__Range 5 #define WeaponStruct__ShakeMagnitude 6 #define WeaponStruct__ID 7 #define WeaponStruct__FireStarter 8 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //Weapon Specifiers: //Used by cobaltGet if a weapon value is being retrieved ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #define Weapon1Const 0 //the unit's first weapon #define Weapon2Const 1 #define Weapon3Const 2 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //Values for Peek/PokeMemory //These are used to specify the size (in bytes) of the data being worked with //Note that floating point values should be placed in the COB in long form... use a base converter to do this... i.e. //0.75 = 3F400000, which is 1061158912 as a long. Thus, 1061158912 should be specified, NOT 0.75. A workaround for this //might be in order... perhaps a BCD (binary coded decimal) solution. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #define WIDTH_BYTE 0 #define WIDTH_WORD 1 #define WIDTH_DWORD 2 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //Static-Var: //The library functions construct 'opcode' automatically and the value returned by the DLL is placed in 'retval' ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static-var opcode, retval; ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //Functions: //Most of these should be pretty self-explanatory. The cobaltGet and cobaltSet functions both take a unit to operate on -- //to use the current unit, specify 0 or pass the value returned by a Get Generic__CurrentUnit operation. To specify the //attacker of the current unit, pass the value returned by a Get Generic__AttackerUnit operation (if necessary, check to make //sure that the unit has been attacked by confirming that the returned value is not zero). // //If a weapon item is going to be fetched by cobaltGet, provide a valid weapon type. Otherwise, optwhichweapon is not used //by the DLL. // //cobaltPrintMessage() and cobaltCallDLLProc() both take string arguments. The arguments cannot be passed in the BOS //function call, i.e., cobaltPrintMessage("message");. The arguments must be pushed (using the pushstring BASM instruction) //prior to the function call. These arguments are commented in the function body as well to show the order in which they //should be pushed. Note that the strings are pushed from right to left. Make sure to wrap the push operation(s) in a //'__basm' block. // //Example for cobaltPrintMessage() //msg // //__basm // { // pushstring "my message"; // } // //cobaltPrintMessage(); // // //Example for cobaltCallDLLProc() //dllname, procname, parmstr // //__basm // { // pushstring "parmstring_argument1, parmstring_argument2, parmstring_argumentN"; // pushstring "procname"; // pushstring "DLLname"; // } // //cobaltCallDLLProc(); ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// cobaltGet(unit, memberof, whichvalue, optwhichweapon) { opcode = Opcode__Get & (memberof << 8) | (whichvalue << 16) | (optwhichweapon << 24); __basm { pushl unit; pushs opcode; _cobalt; pops retval; } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //Setting a member of UnitDefStruct__ will affect all units of the same type unless a new struct is created. //To create a new struct, first get 'UnitStruct__UnitDef'. Then call cobaltCreateNewStruct, specifying UnitDefStruct__ as //'struct type'. Then call cobaltCopyStruct, using the value returned by 'UnitStruct__UnitDef' as the src value and //specifying the value returned by CreateNewStruct (the new value of UnitStruct__UnitDef) as 'dest'. When the unit dies or //you are otherwise done with the new struct, you need to get UnitStruct__UnitDef, pass this value to cobaltDeleteStruct, //and then cobaltSet UnitStruct__UnitDef as the old value of this variable, before the new struct was created. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// cobaltSet(unit, memberof, whichvalue, newvalue) { opcode = Opcode__Set | (memberof << 8) | (whichvalue << 16); __basm { pushl newvalue; pushl unit; pushs opcode; _cobalt; pops retval; } } cobaltPeekMemory(addr, width) { opcode = Opcode__PeekMemory | (width << 8); __basm { pushl addr; pushc opcode; _cobalt; pops retval; } } cobaltPokeMemory(addr, width, newval) { opcode = Opcode__PokeMemory | (width << 8); __basm { pushl newval; pushl addr; pushc opcode; _cobalt; pops retval; } } cobaltCreateNewStruct(structtype) { opcode = Opcode__CreateNewStruct | (structtype << 8) __basm { pushl opcode; _cobalt; pops retval; } } cobaltDeleteStruct(structtype, structptr) { opcode = Opcode__DeleteStruct | (structtype << 8) __basm { pushl structptr; pushl opcode; _cobalt; pops retval; } } cobaltCopyStruct(structtype, dest, src) { opcode = Opcode__CopyStruct | (structtype << 8) __basm { pushl src; pushl dest; pushl opcode; _cobalt; pops retval; } } cobaltPrintMessage()//msg { __basm { //push this string *before* calling this function //pushstring "msg"; pushl Opcode__PrintMessage; _cobalt; pops retval; } } cobaltCallDLLProc()//dllname, procname, parmstr { __basm { //push these three strings *before* calling this function, and push them in the order shown here //pushstring "parmstr"; //pushstring "procname"; //pushstring "dllname"; pushl Opcode__CallDLLProc; _cobalt; pops retval; } } cobaltToggleDLL(onoff) { __basm { pushl onoff; pushl Opcode__ToggleDLL; _cobalt; pops retval; } }