/* Alliance Games - client-side bg functions.
 */

#include "cg_local.h"

int getGrapplePullSpeed(void) {
    return cg_grapple.pullSpeed;
}

qboolean hasEnoughAmmo(const entityState_t *ent, const playerState_t *ps) {
    // since we don't know the counts for this weap, if weapons stay is
    // on and the player has ANY ammo for this weap then return true
    // (it's not like the player will run out of ammo before the server
    // gives the player more)
    if (ps->ammo[bg_itemlist[ent->modelindex].giTag] > 0)
        return qtrue;
    return qfalse;
}

qboolean BG_weaponsStayEnabled(void) {
    return cg_serverConfig.weaponsStay;
}

void QDECL BG_Printf(const char *msg, ...) {
    va_list argptr;
    char text[1024];

    va_start(argptr, msg);
    vsprintf(text, msg, argptr);
    va_end(argptr);

    trap_Print(text);
}

qboolean BG_battleWeaponsEnabled(void) {
    return cg_serverConfig.battleWeapons;
}

int BG_gamemode(void) {
    return cg_serverConfig.gamemode;
}

// begin Joe triple rail
qboolean BG_tripleRailEnabled(void) {
    return cg_serverConfig.tripleRail;
}
// end Joe triple rail

// Myrkul: Movement options
int BG_rampJump(void) {
    return cg_serverConfig.rampJump;
}
int BG_strafeJump(void) {
    return cg_serverConfig.strafeJump;
}
int BG_airMove(void) {
    return cg_serverConfig.airMove;
}
int BG_airSpeed(void) {
    return cg_serverConfig.airSpeed;
}
int BG_grafting(void) {
    return cg_serverConfig.grafting;
}

/*
// Myrkul: trains you to use strafe jump
int BG_strafeJumpTrainer(void) {
    return cg_strafeJumpTrainer.integer;
}
*/
/*
qboolean BG_IamClient(void) {
    return qtrue;
}
 
qboolean BG_IamServer(void) {
	return qfalse;
}
*/

qboolean BG_IamClient(void) {
    if(!cgs.localServer)
        return qtrue;
    else
        return qfalse;
}

qboolean BG_IamServer(void) {
    if(cgs.localServer)
        return qtrue;
    else
        return qfalse;
}


qboolean BG_noClientPredictFire(void) {
    return cg_noPredictFire.integer;
}


// Joe
// warning: playerstates of server and client can be mixed together,
// pm->ps->commandTime and BUTTON_OFFHAND_GRAPPLE can go up and down within one hook
// move

void CG_Offhand_Grapple_Air(centity_t *cent);

#include "../game/bg_battlebots.h"

// Joe
void BG_check_Offhand_Grapple(pmove_t *pm) {
    trace_t tr;
    vec3_t origin, lastpos;
    centity_t *hook;

    static trajectory_t pos;

	if(cg_serverConfig.grapple_onhand)
		return;

    // safety clause
    //if(! cg_PredictHook.integer)
    //return;

    // not firing
    if(! (pm->cmd.buttons & BUTTON_GRAPPLE))
        return;

    // don't know about hook
    // happens maybe 1 time
    // hook entnum should be > MAX_CLIENTS - 1
    if(! pm->ps->stats[STAT_HOOK_ENTNUM]) {
        //        CG_Printf("CG: don't know about hook\n");
        return;
    }

    // don't need to
    if(pm->ps->pm_flags & PMF_GRAPPLE_PULL)
        return;

    hook = cg_entities + pm->ps->stats[STAT_HOOK_ENTNUM];

    // don't trace backwards
/*
    if(pm->ps->commandTime - 50 < hook->currentState.pos.trTime) {
        //        CG_Printf("CG: too early\n");
        return;
    }
*/

    // get running trajectory
    // this will always happen first?
    if(hook->currentState.pos.trType == TR_LINEAR) {
        //        CG_Printf("CG: TR_LINEAR\n");

        // this is very repetitious
        pos.trType = hook->currentState.pos.trType;
        pos.trTime = hook->currentState.pos.trTime;
        VectorCopy(hook->currentState.pos.trBase,  pos.trBase);
        VectorCopy(hook->currentState.pos.trDelta, pos.trDelta);

		// old position
        BG_EvaluateTrajectory(&hook->currentState.pos, pm->ps->commandTime,
                              origin);
        // current position
        BG_EvaluateTrajectory(&hook->currentState.pos, pm->ps->commandTime -
                              50, lastpos);
    }

    // EV_MISSILE_MISS has happened from a normal trace
    // g_missile.c's trace often happens first, used saved trajectory
    else {
        //        CG_Printf("CG: TR_STATIONARY\n");

        BG_EvaluateTrajectory(&pos, pm->ps->commandTime, origin);
        BG_EvaluateTrajectory(&pos, pm->ps->commandTime - 50, lastpos);

    }

    CG_Trace(&tr, lastpos, NULL, NULL,
             origin, pm->ps->clientNum, MASK_SHOT);

    if ( tr.fraction != 1 ) {
        // check if hooked a player
        centity_t *other = &cg_entities[tr.entityNum];
        if (other->currentState.eType == ET_PLAYER)
            return;

        // not sky hook and hit sky
        if (! BG_SkyHook() && (tr.surfaceFlags & SURF_NOIMPACT))
            return;

        //        CG_Printf("CG: pull turned on at pm->ps->commandTime %d\n",
        //                  pm->ps->commandTime);

        VectorCopy(tr.endpos, pm->ps->grapplePoint);
        pm->ps->pm_flags |= PMF_GRAPPLE_PULL;
    }

} // end BG_check_Offhand_Grapple()

/*
qboolean BG_predictHook(void) {
    return cg_serverConfig.predictHook;
}
*/

// Joe
qboolean BG_grappleEnabled(pmove_t *pm) {

    if (cg_serverConfig.grappleGlobal == 1)
        return qtrue;

    return pm->ps->stats[STAT_GRAPPLE];
}

qboolean BG_SkyHook(void) {
    return cg_serverConfig.SkyHook;
}

int BG_getGrappleHookSpeed(void) {
    return cg_grapple.hookSpeed;
}


qboolean BG_ammoRestore(void) {
    return cg_serverConfig.ammoRestore;
}

void BG_PrintTimes(pmove_t *pm) {
    CG_Printf("cg.time %d  pmove->cmd.serverTime %d pm->ps->commandTime %d\n",
              cg.time, pm->cmd.serverTime, pm->ps->commandTime);
}

qboolean BG_superShotgun(void) {
    if (cg_serverConfig.superShotgun)
        return qtrue;
    else
        return qfalse;
}
