// b_coopcam.c // blinky // Created: 2000/06 // Edited: 2000/07/17 // #include "g_local.h" #ifdef GAME_MOD void Blinky_BeginClientThink(edict_t *ent, usercmd_t *ucmd) { gclient_t * client = ent->client; BlinkyClient_t * bdata = &client->blinky_client; // the runrun code - continuous running if (bdata->runrun) { if (ucmd->forwardmove>0) bdata->runrun=1; else if (ucmd->forwardmove<0) bdata->runrun=2; else if (ucmd->sidemove>0) bdata->runrun=3; else if (ucmd->sidemove<0) bdata->runrun=4; switch(bdata->runrun) { case 1: ucmd->forwardmove = 400; break; case 2: ucmd->forwardmove = -400; break; case 3: ucmd->sidemove = 400; break; case 4: ucmd->sidemove = -400; break; } } } void Blinky_EndClientThink(edict_t *ent, usercmd_t *ucmd) { // gclient_t * client = ent->client; } static void Blinky_BeginServerFrameClient(edict_t * ent) { gclient_t * client = ent->client; edict_t * target = client->blinky_client.cam_target; edict_t * decoy = client->blinky_client.cam_decoy; if (target) { /* decoy->modelindex = ent->modelindex; decoy->modelindex2 = ent->modelindex2; decoy->modelindex3 = ent->modelindex3; decoy->modelindex4 = ent->modelindex4; decoy->frame = ent->frame; decoy->skinnum = ent->skinnum; */ decoy->s = ent->s; } // client->ps.viewangles[0] = client->ps.viewangles[1] = 0.0; } void Blinky_BeginRunFrame() { int i; edict_t *ent; for (i=0 ; ivalue ; i++) { ent = g_edicts + 1 + i; if (!ent->inuse || !ent->client) continue; Blinky_BeginServerFrameClient(ent); } } void Blinky_ClientEndServerFrame(edict_t * ent) { // gclient_t * client = ent->client; } static int IsSpectator(edict_t * ent) { return ent->client->pers.spectator; } #define SCANNER_UNIT 10 static void ShowStats(edict_t *ent, edict_t *player) { // float dist = 0.0; vec3_t v; int j; char stats[500]; BlinkyClient_t * bdata; char pname[11]; int health, armor, armorpow; int xd,yd,zd; vec3_t dp, normal={0,0,-1}; static int CellsIndex = -1; int index; j = 0; if (-1 == CellsIndex) CellsIndex = ITEM_INDEX(FindItem("cells")); bdata = &ent->client->blinky_client; VectorSubtract(ent->s.origin, player->s.origin, v); zd = -v[2]/SCANNER_UNIT; // save height differential v[2] = 0; // remove height component RotatePointAroundVector(dp, normal, v, ent->s.angles[1]); xd = -dp[0]/SCANNER_UNIT; yd = dp[1]/SCANNER_UNIT; if (player->client) strncpy(pname, player->client->pers.netname, sizeof(pname)-1); else strncpy(pname, player->classname, sizeof(pname)-1); pname[sizeof(pname)-1] = 0; health = player->health; armorpow = 0; if (PowerArmorType(ent)) armorpow = ent->client->pers.inventory[CellsIndex]; index = ArmorIndex (ent); if (index) armor = ent->client->pers.inventory[index]; if (armorpow) sprintf(stats+j, "%s: armor=%3d(%3d), health=%3d (f=%+5d,r=%+5d,u=%+5d)\n" , pname, armor,armorpow,health,xd, yd, zd); else sprintf(stats+j, "%s: armor=%3d, health=%3d (f=%+5d,r=%+5d,u=%+5d)\n" , pname, armor,health,xd, yd, zd); gi.cprintf(ent, PRINT_CHAT, "%s", stats); } void MoveToAngles(edict_t * ent, vec3_t pv1) { int i; for (i=0 ; i<3 ; i++) { ent->client->ps.pmove.delta_angles[i] = ANGLE2SHORT(pv1[i] - ent->client->resp.cmd_angles[i]); // ent->client->ps.viewangles[i] = pv1[i]; } } void StopCam(edict_t * ent) { BlinkyClient_t * bdata = &ent->client->blinky_client; if (!bdata->cam_target) return; bdata->cam_target = 0; ent->svflags &= ~SVF_NOCLIENT; ent->client->ps.pmove.pm_flags &= ~PMF_NO_PREDICTION; bdata->cam_decoy->svflags |= SVF_NOCLIENT; VectorCopy(bdata->cam_decoy->s.origin, ent->s.origin); MoveToAngles(ent, bdata->cam_decoy->s.angles); ent->client->ps.fov = bdata->save_fov; ent->client->pers.hand = bdata->save_hand; gi.linkentity(ent); gi.linkentity(bdata->cam_decoy); } void StartCam(edict_t * ent, edict_t * target) { BlinkyClient_t * bdata = &ent->client->blinky_client; edict_t * decoy = bdata->cam_decoy; bdata->cam_target = target; ent->svflags |= SVF_NOCLIENT; ent->client->ps.pmove.pm_flags |= PMF_NO_PREDICTION; if (!decoy) { bdata->cam_decoy = G_Spawn(); decoy = bdata->cam_decoy; decoy->client = ent->client; decoy->s = ent->s; // VectorCopy(ent->mins, decoy->mins); // VectorCopy(ent->maxs, decoy->maxs); // decoy->solid = ent->solid; // decoy->health = ent->health; } bdata->cam_decoy->svflags &= ~SVF_NOCLIENT; VectorCopy(ent->s.origin, bdata->cam_decoy->s.origin); MoveToAngles(ent, target->s.angles); VectorCopy(ent->s.angles, bdata->cam_decoy->s.angles); bdata->save_fov = ent->client->ps.fov; bdata->save_hand = ent->client->pers.hand; ent->client->pers.hand = CENTER_HANDED; if (target->client) ent->client->ps.fov = target->client->ps.fov; gi.linkentity(ent); gi.linkentity(bdata->cam_decoy); } void Cmd_Stats_f(edict_t *ent) { char * name = gi.args(); edict_t * player; for (player = &g_edicts[0]+1; player< &g_edicts[0]+(int)(maxclients->value)+1; player++) { if (!player->inuse || !player->client || player->client->pers.spectator) continue; // if (player == ent) // continue; // if a specific name requested & doesn't match, skip if (name[0]) { if (Q_stricmp(name, player->client->pers.netname)) continue; } ShowStats(ent, player); } } void Cmd_Cam_f(edict_t *ent) { char * name = gi.args(); // obj1 is how to tell when we've looped edict_t * obj1; edict_t * target; BlinkyClient_t * bdata; bdata = &ent->client->blinky_client; obj1 = bdata->cam_target; if (!coop->value || IsSpectator(ent)) return; if (!obj1) obj1 = ent; target = obj1; while(1) { // advance loop thru edicts // to do - this ought to cycle at maxclients instead of num_edicts if (target < &g_edicts[0]+(int)(maxclients->value)+1) target++; else target = g_edicts+1; if (target == obj1) break; // only look at (in use) players if (!target->inuse || !target->client || IsSpectator(target)) continue; // if a specific name requested & doesn't match, skip if (name[0] && Q_stricmp(name, target->client->pers.netname)) continue; // found cam target if (target == ent) { StopCam(ent); } else { StartCam(ent, target); ShowStats(ent, target); } break; } } static void Summon(edict_t *ent, edict_t *other) { vec3_t offset, forward, right, start; trace_t tr; if (other->client->blinky_client.nosummon) return; VectorSet(offset, 40, 0, ent->viewheight-8); AngleVectors (ent->client->v_angle, forward, right, NULL); P_ProjectSource (ent->client, ent->s.origin, offset, forward, right, start); // code mostly copied from KillBox // unlink to make sure it can't possibly interfere with KillBox gi.unlinkentity (other); tr = gi.trace (start, other->mins, other->maxs, start, NULL, MASK_PLAYERSOLID); if (tr.fraction < 1.0) { gi.linkentity (other); return; } VectorCopy (start, other->s.origin); VectorCopy (start, other->s.old_origin); other->s.origin[2] += 10; // clear the velocity and hold them in place briefly VectorClear (other->velocity); other->client->ps.pmove.pm_time = 160>>3; // hold time other->client->ps.pmove.pm_flags |= PMF_TIME_TELEPORT; // draw the teleport splash at source and on the player other->s.event = EV_PLAYER_TELEPORT; // set angles MoveToAngles(other, ent->s.angles); VectorClear (other->s.angles); VectorClear (other->client->ps.viewangles); VectorClear (other->client->v_angle); // kill anything at the destination KillBox (other); gi.linkentity (other); } void Cmd_NoSummon_f(edict_t *ent) { BlinkyClient_t * bdata = &ent->client->blinky_client; bdata->nosummon = !bdata->nosummon; } void Cmd_Runrun_f(edict_t *ent) { // char buffer[64]; int runrun = !ent->client->blinky_client.runrun; ent->client->blinky_client.runrun = runrun; // sprintf(buffer, "runrun is %s", runrun ? "on" : "off"); } void Cmd_Summon_f(edict_t *ent) { char * name = gi.args(); edict_t * target; int i; for (i = 1; i < (int)(maxclients->value)+1; i++) { target = &g_edicts[i]; if (!target->inuse || !target->client || IsSpectator(target)) continue; if (target == ent) continue; // if a specific name requested & doesn't match, skip if (name[0] && Q_stricmp(name, target->client->pers.netname)) continue; Summon(ent, target); return; } } void Blinky_OnClientTerminate(edict_t *self) { // disconnect any cams edict_t * player; BlinkyClient_t * bdata; for (player = &g_edicts[0]+1; player< &g_edicts[0]+(int)(maxclients->value)+1; player++) { if (!player->client || !player->inuse) continue; bdata = &player->client->blinky_client; if (bdata->cam_target == self) StopCam(player); } #if 0 StopCam(self); #endif } void Blinky_CalcViewOffsets(edict_t * ent, vec3_t v) { int i; BlinkyClient_t * bdata = &ent->client->blinky_client; vec3_t forward; edict_t * target = bdata->cam_target; int offset = camoffset->value; // ent->client->ps.gunindex = bdata->cam_target->client->ps.gunindex; VectorSet(v,0,0,0); for (i=0; i<3; i++) { ent->client->ps.pmove.origin[i] = target->s.origin[i]*8; } VectorCopy(target->s.angles, ent->client->ps.viewangles); // 2000/07/01 MoveToAngles doesn't work // MoveToAngles(ent, bdata->cam_target->s.angles); // 2000/07/01 changing from adding viewheight, to adding viewoffset // shift cam up // 2000/07/02 - adding viewoffset does not work // but adding viewheight to v[2] works // VectorAdd(v,ent->client->ps.viewoffset,v); v[2] += target->viewheight; // move cam forward if (offset) { AngleVectors (target->client->v_angle, forward, NULL, NULL); VectorMA (v, offset, forward, v); } } void Blinky_SpawnEntities() { gi.dprintf ("Blinky - CoopCam version of 3.20, 2000/08/23\n"); gi.dprintf ("\x02""Use cam to see through your buddy eyes, cam to turn back\n"); srand( (unsigned)time( NULL ) ); } #endif