From 6d4cacd5ad49d654e99c458f5002c70732c9e0a6 Mon Sep 17 00:00:00 2001 From: /dev/humancontroller Date: Sat, 15 Apr 2017 17:22:08 +0200 Subject: multi-protocol: largely port the (gamelogic part of the) multi-protocol code to the 1.1-ish code base also update .gitignore accordingly --- src/cgame/cg_local.h | 135 +++++++++++++++++++++++++++++++++++++++++++ src/cgame/cg_main.c | 56 ++++++++++++++++++ src/cgame/cg_public.h | 24 +++++++- src/cgame/cg_snapshot.c | 53 +++++++++++++++++ src/cgame/cg_syscalls.asm | 114 +++++++++++++++++++----------------- src/cgame/cg_syscalls.c | 4 ++ src/cgame/cg_syscalls_11.asm | 115 ++++++++++++++++++++++++++++++++++++ 7 files changed, 446 insertions(+), 55 deletions(-) create mode 100644 src/cgame/cg_syscalls_11.asm (limited to 'src/cgame') diff --git a/src/cgame/cg_local.h b/src/cgame/cg_local.h index 74b7a4d..ea1694b 100644 --- a/src/cgame/cg_local.h +++ b/src/cgame/cg_local.h @@ -2011,9 +2011,144 @@ void trap_GetGameState( gameState_t *gamestate ); // snapshot latency can be calculated. void trap_GetCurrentSnapshotNumber( int *snapshotNumber, int *serverTime ); +#ifdef MODULE_INTERFACE_11 +typedef struct { + int commandTime; // cmd->serverTime of last executed command + int pm_type; + int bobCycle; // for view bobbing and footstep generation + int pm_flags; // ducked, jump_held, etc + int pm_time; + + vec3_t origin; + vec3_t velocity; + int weaponTime; + int gravity; + int speed; + int delta_angles[3]; // add to command angles to get view direction + // changed by spawns, rotating objects, and teleporters + + int groundEntityNum;// ENTITYNUM_NONE = in air + + int legsTimer; // don't change low priority animations until this runs out + int legsAnim; // mask off ANIM_TOGGLEBIT + + int torsoTimer; // don't change low priority animations until this runs out + int torsoAnim; // mask off ANIM_TOGGLEBIT + + int movementDir; // a number 0 to 7 that represents the reletive angle + // of movement to the view angle (axial and diagonals) + // when at rest, the value will remain unchanged + // used to twist the legs during strafing + + vec3_t grapplePoint; // location of grapple to pull towards if PMF_GRAPPLE_PULL + + int eFlags; // copied to entityState_t->eFlags + + int eventSequence; // pmove generated events + int events[MAX_PS_EVENTS]; + int eventParms[MAX_PS_EVENTS]; + + int externalEvent; // events set on player from another source + int externalEventParm; + int externalEventTime; + + int clientNum; // ranges from 0 to MAX_CLIENTS-1 + int weapon; // copied to entityState_t->weapon + int weaponstate; + + vec3_t viewangles; // for fixed views + int viewheight; + + // damage feedback + int damageEvent; // when it changes, latch the other parms + int damageYaw; + int damagePitch; + int damageCount; + + int stats[MAX_STATS]; + int persistant[MAX_PERSISTANT]; // stats that aren't cleared on death + int misc[MAX_MISC]; // misc data + int ammo[16]; + + int generic1; + int loopSound; + int otherEntityNum; + + // not communicated over the net at all + int ping; // server to game info for scoreboard + int pmove_framecount; // FIXME: don't transmit over the network + int jumppad_frame; + int entityEventSequence; +} moduleAlternatePlayerState_t; + +typedef struct { + int number; // entity index + int eType; // entityType_t + int eFlags; + + trajectory_t pos; // for calculating position + trajectory_t apos; // for calculating angles + + int time; + int time2; + + vec3_t origin; + vec3_t origin2; + + vec3_t angles; + vec3_t angles2; + + int otherEntityNum; // shotgun sources, etc + int otherEntityNum2; + + int groundEntityNum; // ENTITYNUM_NONE = in air + + int constantLight; // r + (g<<8) + (b<<16) + (intensity<<24) + int loopSound; // constantly loop this sound + + int modelindex; + int modelindex2; + int clientNum; // 0 to (MAX_CLIENTS - 1), for players and corpses + int frame; + + int solid; // for client side prediction, trap_linkentity sets this properly + + int event; // impulse events -- muzzle flashes, footsteps, etc + int eventParm; + + // for players + int misc; // bit flags + int weapon; // determines weapon and flash model, etc + int legsAnim; // mask off ANIM_TOGGLEBIT + int torsoAnim; // mask off ANIM_TOGGLEBIT + + int generic1; +} moduleAlternateEntityState_t; + +typedef struct +{ + int snapFlags; // SNAPFLAG_RATE_DELAYED, etc + int ping; + + int serverTime; // server time the message is valid for (in msec) + + byte areamask[ MAX_MAP_AREA_BYTES ]; // portalarea visibility bits + + moduleAlternatePlayerState_t ps; // complete information about the current player at this time + + int numEntities; // all of the entities that need to be presented + moduleAlternateEntityState_t entities[ MAX_ENTITIES_IN_SNAPSHOT ]; // at the time of this snapshot + + int numServerCommands; // text based server commands to execute when this + int serverCommandSequence; // snapshot becomes current +} moduleAlternateSnapshot_t; + +qboolean trap_GetSnapshot( int snapshotNumber, moduleAlternateSnapshot_t *snapshot ); +#else // a snapshot get can fail if the snapshot (or the entties it holds) is so // old that it has fallen out of the client system queue qboolean trap_GetSnapshot( int snapshotNumber, snapshot_t *snapshot ); +#endif // retrieve a text command from the server stream // the current snapshot will hold the number of the most recent command diff --git a/src/cgame/cg_main.c b/src/cgame/cg_main.c index 17505d1..ef1a906 100644 --- a/src/cgame/cg_main.c +++ b/src/cgame/cg_main.c @@ -34,6 +34,7 @@ int forceModelModificationCount = -1; void CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum ); void CG_Shutdown( void ); +static char *CG_VoIPString( void ); /* ================ @@ -88,6 +89,11 @@ Q_EXPORT intptr_t vmMain( int command, int arg0, int arg1, int arg2, int arg3, CG_EventHandling( arg0 ); return 0; +#ifndef MODULE_INTERFACE_11 + case CG_VOIP_STRING: + return (intptr_t)CG_VoIPString( ); +#endif + default: CG_Error( "vmMain: unknown command %i", command ); break; @@ -1840,3 +1846,53 @@ void CG_Shutdown( void ) // some mods may need to do cleanup work here, // like closing files or archiving session data } + +/* +================ +CG_VoIPString +================ +*/ +static char *CG_VoIPString( void ) +{ + // a generous overestimate of the space needed for 0,1,2...61,62,63 + static char voipString[ MAX_CLIENTS * 4 ]; + char voipSendTarget[ MAX_CVAR_VALUE_STRING ]; + + trap_Cvar_VariableStringBuffer( "cl_voipSendTarget", voipSendTarget, + sizeof( voipSendTarget ) ); + + if( Q_stricmp( voipSendTarget, "team" ) == 0 ) + { + int i, slen; + for( slen = i = 0; i < cgs.maxclients; i++ ) + { + if( !cgs.clientinfo[ i ].infoValid || i == cg.clientNum ) + continue; + if( cgs.clientinfo[ i ].team != cgs.clientinfo[ cg.clientNum ].team ) + continue; + + Com_sprintf( &voipString[ slen ], sizeof( voipString ) - slen, + "%s%d", ( slen > 0 ) ? "," : "", i ); + slen = strlen( voipString ); + if( slen + 1 >= sizeof( voipString ) ) + { + CG_Printf( S_COLOR_YELLOW "WARNING: voipString overflowed\n" ); + break; + } + } + + // Notice that if the snprintf was truncated, slen was not updated + // so this will remove any trailing commas or partially-completed numbers + voipString[ slen ] = '\0'; + } + else if( Q_stricmp( voipSendTarget, "crosshair" ) == 0 ) + Com_sprintf( voipString, sizeof( voipString ), "%d", + CG_CrosshairPlayer( ) ); + else if( Q_stricmp( voipSendTarget, "attacker" ) == 0 ) + Com_sprintf( voipString, sizeof( voipString ), "%d", + CG_LastAttacker( ) ); + else + return NULL; + + return voipString; +} diff --git a/src/cgame/cg_public.h b/src/cgame/cg_public.h index 70cb052..543a222 100644 --- a/src/cgame/cg_public.h +++ b/src/cgame/cg_public.h @@ -120,6 +120,9 @@ typedef enum CG_R_ADDLIGHTTOSCENE, CG_R_RENDERSCENE, CG_R_SETCOLOR, +#ifndef MODULE_INTERFACE_11 + CG_R_SETCLIPREGION, +#endif CG_R_DRAWSTRETCHPIC, CG_R_MODELBOUNDS, CG_R_LERPTAG, @@ -138,11 +141,13 @@ typedef enum CG_KEY_GETCATCHER, CG_KEY_SETCATCHER, CG_KEY_GETKEY, +#ifdef MODULE_INTERFACE_11 CG_PARSE_ADD_GLOBAL_DEFINE, CG_PARSE_LOAD_SOURCE, CG_PARSE_FREE_SOURCE, CG_PARSE_READ_TOKEN, CG_PARSE_SOURCE_FILE_AND_LINE, +#endif CG_S_STOPBACKGROUNDTRACK, CG_REAL_TIME, CG_SNAPVECTOR, @@ -177,6 +182,19 @@ typedef enum CG_KEY_GETBINDINGBUF, CG_KEY_SETBINDING, +#ifndef MODULE_INTERFACE_11 + CG_PARSE_ADD_GLOBAL_DEFINE, + CG_PARSE_LOAD_SOURCE, + CG_PARSE_FREE_SOURCE, + CG_PARSE_READ_TOKEN, + CG_PARSE_SOURCE_FILE_AND_LINE, + + CG_KEY_SETOVERSTRIKEMODE, + CG_KEY_GETOVERSTRIKEMODE, + + CG_S_SOUNDDURATION, +#endif + CG_MEMSET = 200, CG_MEMCPY, CG_STRNCPY, @@ -242,10 +260,14 @@ typedef enum CG_EVENT_HANDLING, // void (*CG_EventHandling)(int type); - CG_CONSOLE_TEXT + CG_CONSOLE_TEXT, // void (*CG_ConsoleText)( void ); // pass text that has been printed to the console to cgame // use Cmd_Argc() / Cmd_Argv() to read it + + CG_VOIP_STRING + // char *(*CG_VoIPString)( void ); + // returns a string of comma-delimited clientnums based on cl_voipSendTarget } cgameExport_t; //---------------------------------------------- diff --git a/src/cgame/cg_snapshot.c b/src/cgame/cg_snapshot.c index f439a69..84b419f 100644 --- a/src/cgame/cg_snapshot.c +++ b/src/cgame/cg_snapshot.c @@ -245,6 +245,55 @@ static void CG_SetNextSnap( snapshot_t *snap ) } +#ifdef MODULE_INTERFACE_11 +static moduleAlternateSnapshot_t moduleAlternateSnapshot; + +static qboolean CG_GetModuleAlternateSnapshot( int snapshotNumber, snapshot_t *snap ) +{ + moduleAlternateSnapshot_t *alt = &moduleAlternateSnapshot; + int r = trap_GetSnapshot( snapshotNumber, alt ); + + if( r ) + { + int i; + + snap->snapFlags = alt->snapFlags; + snap->ping = alt->ping; + snap->serverTime = alt->serverTime; + snap->numEntities = alt->numEntities; + snap->numServerCommands = alt->numServerCommands; + snap->serverCommandSequence = alt->serverCommandSequence; + memcpy( &snap->areamask, &alt->areamask, sizeof( snap->areamask ) ); + +#define PSFO(x) ((size_t)&(((playerState_t*)0)->x)) + memcpy( &snap->ps.commandTime, &alt->ps.commandTime, PSFO(tauntTimer) - PSFO(commandTime) ); + memcpy( &snap->ps.movementDir, &alt->ps.movementDir, PSFO(ammo) - PSFO(movementDir) ); + memcpy( &snap->ps.generic1, &alt->ps.generic1, PSFO(entityEventSequence) - PSFO(generic1) ); + + snap->ps.weaponAnim = alt->ps.ammo[0] & 0xFF; + snap->ps.pm_flags |= ( alt->ps.ammo[0] & 0xFF00 ) << 8; + snap->ps.ammo = alt->ps.ammo[1] & 0xFFF; + snap->ps.clips = ( alt->ps.ammo[1] & 0xF000 ) >> 12; + snap->ps.tauntTimer = alt->ps.ammo[2] & 0xFFF; + snap->ps.generic1 |= ( alt->ps.ammo[2] & 0x3000 ) >> 4; + + for( i = 0; i < alt->numEntities; ++i ) + { + entityState_t *s = &snap->entities[ i ]; + const moduleAlternateEntityState_t *a = &alt->entities[ i ]; + +#define ESFO(x) ((size_t)&(((entityState_t*)0)->x)) + memcpy( &s->number, &a->number, ESFO(weaponAnim) - ESFO(number) ); + + s->weaponAnim = 0; + s->generic1 = a->generic1; + } + } + + return r; +} +#endif + /* ======================== CG_ReadNextSnapshot @@ -276,7 +325,11 @@ static snapshot_t *CG_ReadNextSnapshot( void ) // try to read the snapshot from the client system cgs.processedSnapshotNum++; +#ifdef MODULE_INTERFACE_11 + r = CG_GetModuleAlternateSnapshot( cgs.processedSnapshotNum, dest ); +#else r = trap_GetSnapshot( cgs.processedSnapshotNum, dest ); +#endif // FIXME: why would trap_GetSnapshot return a snapshot with the same server time if( cg.snap && r && dest->serverTime == cg.snap->serverTime ) diff --git a/src/cgame/cg_syscalls.asm b/src/cgame/cg_syscalls.asm index 0893ebc..2537c91 100644 --- a/src/cgame/cg_syscalls.asm +++ b/src/cgame/cg_syscalls.asm @@ -46,60 +46,66 @@ equ trap_R_AddPolyToScene -43 equ trap_R_AddLightToScene -44 equ trap_R_RenderScene -45 equ trap_R_SetColor -46 -equ trap_R_DrawStretchPic -47 -equ trap_R_ModelBounds -48 -equ trap_R_LerpTag -49 -equ trap_GetGlconfig -50 -equ trap_GetGameState -51 -equ trap_GetCurrentSnapshotNumber -52 -equ trap_GetSnapshot -53 -equ trap_GetServerCommand -54 -equ trap_GetCurrentCmdNumber -55 -equ trap_GetUserCmd -56 -equ trap_SetUserCmdValue -57 -equ trap_R_RegisterShaderNoMip -58 -equ trap_MemoryRemaining -59 -equ trap_R_RegisterFont -60 -equ trap_Key_IsDown -61 -equ trap_Key_GetCatcher -62 -equ trap_Key_SetCatcher -63 -equ trap_Key_GetKey -64 -equ trap_Parse_AddGlobalDefine -65 -equ trap_Parse_LoadSource -66 -equ trap_Parse_FreeSource -67 -equ trap_Parse_ReadToken -68 -equ trap_Parse_SourceFileAndLine -69 -equ trap_S_StopBackgroundTrack -70 -equ trap_RealTime -71 -equ trap_SnapVector -72 -equ trap_RemoveCommand -73 -equ trap_R_LightForPoint -74 -equ trap_CIN_PlayCinematic -75 -equ trap_CIN_StopCinematic -76 -equ trap_CIN_RunCinematic -77 -equ trap_CIN_DrawCinematic -78 -equ trap_CIN_SetExtents -79 -equ trap_R_RemapShader -80 -equ trap_S_AddRealLoopingSound -81 -equ trap_S_StopLoopingSound -82 -equ trap_CM_TempCapsuleModel -83 -equ trap_CM_CapsuleTrace -84 -equ trap_CM_TransformedCapsuleTrace -85 -equ trap_R_AddAdditiveLightToScene -86 -equ trap_GetEntityToken -87 -equ trap_R_AddPolysToScene -88 -equ trap_R_inPVS -89 -equ trap_FS_Seek -90 -equ trap_FS_GetFileList -91 -equ trap_LiteralArgs -92 -equ trap_CM_BiSphereTrace -93 -equ trap_CM_TransformedBiSphereTrace -94 -equ trap_GetDemoState -95 -equ trap_GetDemoPos -96 -equ trap_GetDemoName -97 -equ trap_Key_KeynumToStringBuf -98 -equ trap_Key_GetBindingBuf -99 -equ trap_Key_SetBinding -100 +equ trap_R_SetClipRegion -47 +equ trap_R_DrawStretchPic -48 +equ trap_R_ModelBounds -49 +equ trap_R_LerpTag -50 +equ trap_GetGlconfig -51 +equ trap_GetGameState -52 +equ trap_GetCurrentSnapshotNumber -53 +equ trap_GetSnapshot -54 +equ trap_GetServerCommand -55 +equ trap_GetCurrentCmdNumber -56 +equ trap_GetUserCmd -57 +equ trap_SetUserCmdValue -58 +equ trap_R_RegisterShaderNoMip -59 +equ trap_MemoryRemaining -60 +equ trap_R_RegisterFont -61 +equ trap_Key_IsDown -62 +equ trap_Key_GetCatcher -63 +equ trap_Key_SetCatcher -64 +equ trap_Key_GetKey -65 +equ trap_S_StopBackgroundTrack -66 +equ trap_RealTime -67 +equ trap_SnapVector -68 +equ trap_RemoveCommand -69 +equ trap_R_LightForPoint -70 +equ trap_CIN_PlayCinematic -71 +equ trap_CIN_StopCinematic -72 +equ trap_CIN_RunCinematic -73 +equ trap_CIN_DrawCinematic -74 +equ trap_CIN_SetExtents -75 +equ trap_R_RemapShader -76 +equ trap_S_AddRealLoopingSound -77 +equ trap_S_StopLoopingSound -78 +equ trap_CM_TempCapsuleModel -79 +equ trap_CM_CapsuleTrace -80 +equ trap_CM_TransformedCapsuleTrace -81 +equ trap_R_AddAdditiveLightToScene -82 +equ trap_GetEntityToken -83 +equ trap_R_AddPolysToScene -84 +equ trap_R_inPVS -85 +equ trap_FS_Seek -86 +equ trap_FS_GetFileList -87 +equ trap_LiteralArgs -88 +equ trap_CM_BiSphereTrace -89 +equ trap_CM_TransformedBiSphereTrace -90 +equ trap_GetDemoState -91 +equ trap_GetDemoPos -92 +equ trap_GetDemoName -93 +equ trap_Key_KeynumToStringBuf -94 +equ trap_Key_GetBindingBuf -95 +equ trap_Key_SetBinding -96 + +equ trap_Parse_AddGlobalDefine -97 +equ trap_Parse_LoadSource -98 +equ trap_Parse_FreeSource -99 +equ trap_Parse_ReadToken -100 +equ trap_Parse_SourceFileAndLine -101 +equ trap_Key_SetOverstrikeMode -102 +equ trap_Key_GetOverstrikeMode -103 + +equ trap_S_SoundDuration -104 equ memset -201 equ memcpy -202 diff --git a/src/cgame/cg_syscalls.c b/src/cgame/cg_syscalls.c index 1239165..aa42019 100644 --- a/src/cgame/cg_syscalls.c +++ b/src/cgame/cg_syscalls.c @@ -407,7 +407,11 @@ void trap_GetCurrentSnapshotNumber( int *snapshotNumber, int *serverTime ) syscall( CG_GETCURRENTSNAPSHOTNUMBER, snapshotNumber, serverTime ); } +#ifdef MODULE_INTERFACE_11 +qboolean trap_GetSnapshot( int snapshotNumber, moduleAlternateSnapshot_t *snapshot ) +#else qboolean trap_GetSnapshot( int snapshotNumber, snapshot_t *snapshot ) +#endif { return syscall( CG_GETSNAPSHOT, snapshotNumber, snapshot ); } diff --git a/src/cgame/cg_syscalls_11.asm b/src/cgame/cg_syscalls_11.asm new file mode 100644 index 0000000..0893ebc --- /dev/null +++ b/src/cgame/cg_syscalls_11.asm @@ -0,0 +1,115 @@ +code + +equ trap_Print -1 +equ trap_Error -2 +equ trap_Milliseconds -3 +equ trap_Cvar_Register -4 +equ trap_Cvar_Update -5 +equ trap_Cvar_Set -6 +equ trap_Cvar_VariableStringBuffer -7 +equ trap_Argc -8 +equ trap_Argv -9 +equ trap_Args -10 +equ trap_FS_FOpenFile -11 +equ trap_FS_Read -12 +equ trap_FS_Write -13 +equ trap_FS_FCloseFile -14 +equ trap_SendConsoleCommand -15 +equ trap_AddCommand -16 +equ trap_SendClientCommand -17 +equ trap_UpdateScreen -18 +equ trap_CM_LoadMap -19 +equ trap_CM_NumInlineModels -20 +equ trap_CM_InlineModel -21 +equ trap_CM_LoadModel -22 +equ trap_CM_TempBoxModel -23 +equ trap_CM_PointContents -24 +equ trap_CM_TransformedPointContents -25 +equ trap_CM_BoxTrace -26 +equ trap_CM_TransformedBoxTrace -27 +equ trap_CM_MarkFragments -28 +equ trap_S_StartSound -29 +equ trap_S_StartLocalSound -30 +equ trap_S_ClearLoopingSounds -31 +equ trap_S_AddLoopingSound -32 +equ trap_S_UpdateEntityPosition -33 +equ trap_S_Respatialize -34 +equ trap_S_RegisterSound -35 +equ trap_S_StartBackgroundTrack -36 +equ trap_R_LoadWorldMap -37 +equ trap_R_RegisterModel -38 +equ trap_R_RegisterSkin -39 +equ trap_R_RegisterShader -40 +equ trap_R_ClearScene -41 +equ trap_R_AddRefEntityToScene -42 +equ trap_R_AddPolyToScene -43 +equ trap_R_AddLightToScene -44 +equ trap_R_RenderScene -45 +equ trap_R_SetColor -46 +equ trap_R_DrawStretchPic -47 +equ trap_R_ModelBounds -48 +equ trap_R_LerpTag -49 +equ trap_GetGlconfig -50 +equ trap_GetGameState -51 +equ trap_GetCurrentSnapshotNumber -52 +equ trap_GetSnapshot -53 +equ trap_GetServerCommand -54 +equ trap_GetCurrentCmdNumber -55 +equ trap_GetUserCmd -56 +equ trap_SetUserCmdValue -57 +equ trap_R_RegisterShaderNoMip -58 +equ trap_MemoryRemaining -59 +equ trap_R_RegisterFont -60 +equ trap_Key_IsDown -61 +equ trap_Key_GetCatcher -62 +equ trap_Key_SetCatcher -63 +equ trap_Key_GetKey -64 +equ trap_Parse_AddGlobalDefine -65 +equ trap_Parse_LoadSource -66 +equ trap_Parse_FreeSource -67 +equ trap_Parse_ReadToken -68 +equ trap_Parse_SourceFileAndLine -69 +equ trap_S_StopBackgroundTrack -70 +equ trap_RealTime -71 +equ trap_SnapVector -72 +equ trap_RemoveCommand -73 +equ trap_R_LightForPoint -74 +equ trap_CIN_PlayCinematic -75 +equ trap_CIN_StopCinematic -76 +equ trap_CIN_RunCinematic -77 +equ trap_CIN_DrawCinematic -78 +equ trap_CIN_SetExtents -79 +equ trap_R_RemapShader -80 +equ trap_S_AddRealLoopingSound -81 +equ trap_S_StopLoopingSound -82 +equ trap_CM_TempCapsuleModel -83 +equ trap_CM_CapsuleTrace -84 +equ trap_CM_TransformedCapsuleTrace -85 +equ trap_R_AddAdditiveLightToScene -86 +equ trap_GetEntityToken -87 +equ trap_R_AddPolysToScene -88 +equ trap_R_inPVS -89 +equ trap_FS_Seek -90 +equ trap_FS_GetFileList -91 +equ trap_LiteralArgs -92 +equ trap_CM_BiSphereTrace -93 +equ trap_CM_TransformedBiSphereTrace -94 +equ trap_GetDemoState -95 +equ trap_GetDemoPos -96 +equ trap_GetDemoName -97 +equ trap_Key_KeynumToStringBuf -98 +equ trap_Key_GetBindingBuf -99 +equ trap_Key_SetBinding -100 + +equ memset -201 +equ memcpy -202 +equ strncpy -203 +equ sin -204 +equ cos -205 +equ atan2 -206 +equ sqrt -207 +equ floor -208 +equ ceil -209 +equ testPrintInt -210 +equ testPrintFloat -211 + -- cgit