Since the only thing it gets used for is swapping out PlayerPawns it can safely skip all global variables that never point to a live player, which allowed to remove quite a bit of code here that stood in the way of scriptifying more content
Null pointers must be allowed and non-object pointers which are not null must be explicitly checked for because the code could crash on them when performing a static_cast on an incorrect type.
For the varargs functions that used the Type field to validate their parameters, now a hidden additional argument is passed which contains a byte array with the type info for the current call's arguments. Since this is static per call location it can be better prepared once when the code is being compiled instead of being put in a runtime created array for each invocation. Everything else uses the per-function instance of the same data.
The only thing that still needed the type field with a VMValue is the defaults array, so this uses a different struct type now to store its data.
Currently used for loading parameters into registers.
For checking parameters of native functions some more work is needed to get the info to the function. Currently it doesn't receive the function descriptor.
The amount of support code for this minor optimization was quite large and this stood in the way of streamlining the VM's calling convention, so it was preferable to remove it before moving on.
This removes the last non-vararg cases where a native VM function checks 'numparam'. As of this commit all function calls will pass the complete list of arguments.
There were some issues here:
* a check for mismatching count is too strict because it is legal to omit return values
* it failed to detect returning multiple values in a single expression.
The instruction one free instruction byte so it's now using that to extend its argument's register range to 65535.
For param this is needed because it passes strings by reference and creating an implicit temporary copy for string constants does not work here.
This setup has been a constant source of problems so now I reviewed all uses of FName to make sure that everything that needs to be initialized is done manually.
This also merges the player_t constructor into the class definition as default values.
Due to how function calls get resolved by the code generator there were some incorrect flags on the self pointer which triggered an assert and caused incorrect code generation.
Fortunately this was a mostly contained special case for which a workaround was possible.