Requirements: Intermediate knowledge of ASM and C++ and the stack, internal access to process

1)Find the address of the function you want to call

If you want to call the function that does damage to players, you would find your entity address, the enemy's entity address, do a "Find what Accesses This Address" on the enemy's health. Shoot the enemy once. Find the instruction that has only been executed once. This could be the function DoDamage() or it could be a function like DecreaseHealth() that gets called by the DoDamage() function. If it's DecreaseHealth() you will have to trace backwards to the function that calls it. If it's DoDamage() you will want to right click on this instruction in Cheat Engine and click "Select Function". Scroll to the top of the selected function, the top address is the address of your function.

2)Discover the calling convention of the function

You do this by viewing how the arguments are pushed onto the stack or placed in registers by the caller before the function is called and also how they are popped off the stack by either the caller or the callee.

When a function is called the callee creates a new stack frame using EBP and ESP, each function has it's own stack frame which is local storage that the function needs.

Read about stack frames here:

Example: For the DoDamge() function you would examine the PUSH instructions before the call and breakpoint the first instruction of the DoDamage() function and examine the registers. Find the address of your entity and of the enemy either on the stack or in the registers.

Read up on calling conventions:

3) Discover the arguments and the argument types

Using IDA is the easiest. If class objects are being passed in you will need to reverse those objects and recreate them in your code. Before your function gets called, you will see arguments get pushed onto the stack, usually in right to left order.

4)Recreate the function prototype in your code and create a typedef to it and then call it

Here are some examples:
//typedef the function prototype
typedef cvar_t*(__cdecl * _Cvar_Get)(const char *var_name, const char *var_value, int flags);

//Create an instance of the function and assign it to an address
_Cvar_Get Cvar_Get = (_Cvar_Get)0x043F688;

//Call it like this
Cvar_Get("cl_gamepath", "OpenArena", 0);

//typedef the function prototype
typedef clipHandle_t(__cdecl *_CM_InlineModel)(int index);

//Create an instance of the function and assign it to an address
_CM_InlineModel CM_InlineModel = (_CM_InlineModel)0x00426a5c;

//Call it like this
//multiline method:
typedef void(__cdecl * _contoutf)(const char* string, ...);
_contoutf contoutf = (_contoutf)0x46b060;
//one line method:
((void(__cdecl*)(const char* string))0x46b060)("do the shit");
Alternatively if the calling convention is giving you trouble you can just push the variables onto the stack and call the function using inline ASM

If you're using the wrong calling convention you will corrupt the stack and the game will crash.