FTE MULTIPROGS

From FTE
Revision as of 22:07, 14 June 2006 by TimeServ (talk | contribs)

Jump to: navigation, search

Description

This is a huge extension. The engine can load multiple progs.dat which can redirect function calls to create mutators, aka Unreal Tournament.

This can also be used for arrays by using externset and externvalue on named globals when used on the current progs.

If you have any questions, post on quakesrc.org's forums, and Spike'll try to answer them (and probably anotate this more).

Background: All fields are shared. An entities model in one progs is the same in annother. This isn't true with globals however, except for self, other and time (which are considered special enough).

As far as the engine is concerned, the progs all act as one unit. It'll search for spawn functions and the like starting with the first loaded (the progs.dat). So a simple addon could be used to add things like hipnotic style forcefields.

Calling across the progs is a little more awkward than a native call (QCC requires that all progs have all function bodies). You can use forms of externcall to call a function in a different progs, though you are required to have an index to the progs you wish to call to.

Hooking functions is possible by following this double damage sample:

void(entity targ, entity inflictor, entity attacker, float damage) origionaldamage = {}; void(entity targ, entity inflictor, entity attacker, float damage) T_Damage = {

   damage = damage * 2; 
   origionaldamage(targ, inflictor, attacker, damage);

};
void() attachDamageHook = {

   origionalfunc = externvalue_func(mainprogs, "T_Damage"); 
   externset_func(progs, "T_Damage");

};

You would then call attachDamageHook when you want to apply (possibly in a spawn func). Make sure you don't call it multiple times for the same progs of course. It can be cumulative on the condition that you store the old function in a different place (different global/progs). Be aware that hooks could conflict. The engine will only load addons with the same progs crc as the first progs it loads. If you want an addon for either qwprogs.dat or progs.dat, you'll need two addons. The recommended place to call it is in a function known as 'initents'. This QC function is called by the engine just after all the progs were loaded, and just before worldspawn, so is a natural place to redirect spawn functions or create your own entities with specified thinks. An alternate place is the 'FTE_init' function, which is called just after the progs was loaded (but don't make use of any entity types/builtins, not even world). FTE_init is the only suitable place to call the addprogs builtin. You can call addprogs at any point, but if it defines too many fields which have not yet been encountered (after the initents event) then you'll get an error.

About progs indexes: FTE currently has them as integers. This is fine for FTEQCC's 'integer' type (which is a true integer), but can cause problems with other QC compilers and doesn't allow the progs to be run by other engines (which isn't an issue if it's only used in the mutator itself).

FTEQCC was origionally created to support this extension. It supports an alternate output, -TFTE on FTEQCC's commandline. This target allows additional keywords: extern and shared. Extern is applied to functions. It prevents the need for a function body, and links the function to a function exported in a previous progs (which must be found). The shared keyword works on globals. It causes globals to be copied around in the same mannor that the self, other and time globals are. Be aware that it does not work properly when the globals are defined in a different order. Only use this when you are using a common defs.qc file (anything before end_sys_fields is safe). As mentioned above, the FTE target supports an 'integer' type also. This is not the same as FrikQCC's 'int' type (which is actually that of a float). Be aware that using FrikQCC and using the 'eliminate constant defs/names' optimisation on an addon will prevent loading. FTEQCC has a similar extension, but it's split into two to allow this optimisation on addons to the furthest extent possible.

Globals

float mainprogs;
float thisprogs;
float nextaddon;

Builtins

float(float progs, string funcname, ...) externcall = #201;
float(string s) addprogs = #202;
string(float prnum, string name) externvalue_s = #203;
float(float prnum, string name) externvalue_f = #203;
integer(float prnum, string name,...) externvalue_func = #203;
integer(float prnum, string name) externvalue_i = #203;
entity(float prnum, string name) externvalue_e = #203;
void(float prnum, string value, string name) externset_s = #204;
void(float prnum, float value, string name) externset_f = #204;
void(float prnum, integer value, string name,...) externset_func = #204;
void(float prnum, integer value, string name) externset_i = #204;
void(float prnum, entity value, string name) externset_e = #204;