/* =============== UI_DrawPlayer =============== */ void UI_DrawPlayer( float x, float y, float w, float h, playerInfo_t *pi, int time ) { refdef_t refdef; refEntity_t legs; refEntity_t torso; refEntity_t head; refEntity_t gun; refEntity_t barrel; refEntity_t flash; vec3_t origin; int renderfx; vec3_t mins = {-16, -16, -24}; vec3_t maxs = {16, 16, 32}; float len; float xx; float xscale; float yscale; if ( !pi->legsModel || !pi->torsoModel || !pi->headModel || !pi->animations[0].numFrames ) { return; } dp_realtime = time; if ( pi->pendingWeapon != WP_NUM_WEAPONS && dp_realtime > pi->weaponTimer ) { pi->weapon = pi->pendingWeapon; pi->lastWeapon = pi->pendingWeapon; pi->pendingWeapon = WP_NUM_WEAPONS; pi->weaponTimer = 0; if( pi->currentWeapon != pi->weapon ) { trap_S_StartLocalSound( weaponChangeSound, CHAN_LOCAL ); } } CG_AdjustFrom640( &x, &y, &w, &h ); y -= jumpHeight; memset( &refdef, 0, sizeof( refdef ) ); memset( &legs, 0, sizeof(legs) ); memset( &torso, 0, sizeof(torso) ); memset( &head, 0, sizeof(head) ); refdef.rdflags = RDF_NOWORLDMODEL; AxisClear( refdef.viewaxis ); refdef.x = x; refdef.y = y; refdef.width = w; refdef.height = h; if ( ui_stretch.integer ) { xscale = cgs.screenXScaleStretch; yscale = cgs.screenYScaleStretch; } else { xscale = cgs.screenXScale; yscale = cgs.screenYScale; } refdef.fov_x = (int)((float)refdef.width / xscale / 640.0f * 90.0f); xx = refdef.width / xscale / tan( refdef.fov_x / 360 * M_PI ); refdef.fov_y = atan2( refdef.height / yscale, xx ); refdef.fov_y *= ( 360 / M_PI ); // calculate distance so the player nearly fills the box len = 0.7 * ( maxs[2] - mins[2] ); origin[0] = len / tan( DEG2RAD(refdef.fov_x) * 0.5 ); origin[1] = 0.5 * ( mins[1] + maxs[1] ); origin[2] = -0.5 * ( mins[2] + maxs[2] ); refdef.time = dp_realtime; trap_R_ClearScene(); // get the rotation information UI_PlayerAngles( pi, legs.axis, torso.axis, head.axis ); // get the animation state (after rotation, to allow feet shuffle) UI_PlayerAnimation( pi, &legs.oldframe, &legs.frame, &legs.backlerp, &torso.oldframe, &torso.frame, &torso.backlerp ); renderfx = RF_LIGHTING_ORIGIN | RF_NOSHADOW; // // add the legs // legs.hModel = pi->legsModel; legs.customSkin = CG_AddSkinToFrame( &pi->modelSkin ); VectorCopy( origin, legs.origin ); VectorCopy( origin, legs.lightingOrigin ); legs.renderfx = renderfx; VectorCopy (legs.origin, legs.oldorigin); CG_AddRefEntityWithMinLight( &legs ); if (!legs.hModel) { return; } // // add the torso // torso.hModel = pi->torsoModel; if (!torso.hModel) { return; } torso.customSkin = legs.customSkin; VectorCopy( origin, torso.lightingOrigin ); UI_PositionRotatedEntityOnTag( &torso, &legs, pi->legsModel, "tag_torso"); torso.renderfx = renderfx; CG_AddRefEntityWithMinLight( &torso ); // // add the head // head.hModel = pi->headModel; if (!head.hModel) { return; } head.customSkin = legs.customSkin; VectorCopy( origin, head.lightingOrigin ); UI_PositionRotatedEntityOnTag( &head, &torso, pi->torsoModel, "tag_head"); head.renderfx = renderfx; CG_AddRefEntityWithMinLight( &head ); // // add the gun // if ( pi->currentWeapon != WP_NONE ) { memset( &gun, 0, sizeof(gun) ); gun.hModel = pi->weaponModel; if( pi->currentWeapon == WP_RAILGUN ) { Byte4Copy( pi->c1RGBA, gun.shaderRGBA ); } else { Byte4Copy( colorWhite, gun.shaderRGBA ); } VectorCopy( origin, gun.lightingOrigin ); UI_PositionEntityOnTag( &gun, &torso, pi->torsoModel, "tag_weapon"); gun.renderfx = renderfx; CG_AddRefEntityWithMinLight( &gun ); } // // add the spinning barrel // if ( pi->realWeapon == WP_MACHINEGUN || pi->realWeapon == WP_GAUNTLET || pi->realWeapon == WP_BFG #ifdef MISSIONPACK || pi->realWeapon == WP_CHAINGUN #endif ) { vec3_t angles; memset( &barrel, 0, sizeof(barrel) ); VectorCopy( origin, barrel.lightingOrigin ); barrel.renderfx = renderfx; barrel.hModel = pi->barrelModel; angles[YAW] = 0; angles[PITCH] = 0; angles[ROLL] = UI_MachinegunSpinAngle( pi ); if( pi->realWeapon == WP_GAUNTLET || pi->realWeapon == WP_BFG ) { angles[PITCH] = angles[ROLL]; angles[ROLL] = 0; } AnglesToAxis( angles, barrel.axis ); UI_PositionRotatedEntityOnTag( &barrel, &gun, pi->weaponModel, "tag_barrel"); CG_AddRefEntityWithMinLight( &barrel ); } // // add muzzle flash // if ( dp_realtime <= pi->muzzleFlashTime ) { if ( pi->flashModel ) { memset( &flash, 0, sizeof(flash) ); flash.hModel = pi->flashModel; if( pi->currentWeapon == WP_RAILGUN ) { Byte4Copy( pi->c1RGBA, flash.shaderRGBA ); } else { Byte4Copy( colorWhite, flash.shaderRGBA ); } VectorCopy( origin, flash.lightingOrigin ); UI_PositionEntityOnTag( &flash, &gun, pi->weaponModel, "tag_flash"); flash.renderfx = renderfx; CG_AddRefEntityWithMinLight( &flash ); } // make a dlight for the flash if ( pi->flashDlightColor[0] || pi->flashDlightColor[1] || pi->flashDlightColor[2] ) { trap_R_AddLightToScene( flash.origin, 200 + (rand()&31), 1.0f, pi->flashDlightColor[0], pi->flashDlightColor[1], pi->flashDlightColor[2] ); } } // // add the chat icon // if ( pi->chat ) { UI_PlayerFloatSprite( pi, origin, trap_R_RegisterShaderNoMip( "sprites/balloon3" ) ); } // // add an accent light // origin[0] -= 100; // + = behind, - = in front origin[1] += 100; // + = left, - = right origin[2] += 100; // + = above, - = below trap_R_AddLightToScene( origin, 500, 1.0, 1.0, 1.0, 1.0 ); origin[0] -= 100; origin[1] -= 100; origin[2] -= 100; trap_R_AddLightToScene( origin, 500, 1.0, 1.0, 0.0, 0.0 ); trap_R_RenderScene( &refdef ); }
void target_laser_think (edict_t *self) { edict_t *ignore; vec3_t start; vec3_t end; trace_t tr; vec3_t point; vec3_t last_movedir; int count; if (self->spawnflags & 0x80000000) count = 8; else count = 4; if (self->enemy) { VectorCopy (self->movedir, last_movedir); VectorMA (self->enemy->absmin, 0.5, self->enemy->size, point); VectorSubtract (point, self->s.origin, self->movedir); VectorNormalize (self->movedir); if (!VectorCompare(self->movedir, last_movedir)) self->spawnflags |= 0x80000000; } ignore = self; VectorCopy (self->s.origin, start); VectorMA (start, 2048, self->movedir, end); while(1) { tr = gi.trace (start, NULL, NULL, end, ignore, CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_DEADMONSTER); VectorCopy (tr.endpos,self->moveinfo.end_origin); if (!tr.ent) break; // hurt it if we can if ((tr.ent->takedamage) && !(tr.ent->flags & FL_IMMUNE_LASER)) T_Damage (tr.ent, self, self->activator, self->movedir, tr.endpos, vec3_origin, self->dmg, 1, DAMAGE_ENERGY, MOD_TARGET_LASER); // if we hit something that's not a monster or player or is immune to lasers, we're done if (!(tr.ent->svflags & SVF_MONSTER) && (!tr.ent->client)) { if (self->spawnflags & 0x80000000) { self->spawnflags &= ~0x80000000; gi.WriteByte (svc_temp_entity); gi.WriteByte (TE_LASER_SPARKS); gi.WriteByte (count); gi.WritePosition (tr.endpos); gi.WriteDir (tr.plane.normal); gi.WriteByte (self->s.skinnum); gi.multicast (tr.endpos, MULTICAST_PVS); } break; } ignore = tr.ent; VectorCopy (tr.endpos, start); } VectorCopy (tr.endpos, self->s.old_origin); self->nextthink = level.time + FRAMETIME; }
void ClientThink_real( gentity_t *ent, usercmd_t *ucmd ) { gclient_t *client; pmove_t pm; vec3_t oldOrigin; int oldEventSequence; int msec; //Don't let the player do anything if in a camera if ( ent->s.number == 0 ) { extern cvar_t *g_skippingcin; if ( in_camera ) { // watch the code here, you MUST "return" within this IF(), *unless* you're stopping the cinematic skip. // if ( ClientCinematicThink(ent->client) ) { if (g_skippingcin->integer) // already doing cinematic skip? { // yes... so stop skipping... gi.cvar_set("skippingCinematic", "0"); gi.cvar_set("timescale", "1"); } else { // no... so start skipping... gi.cvar_set("skippingCinematic", "1"); gi.cvar_set("timescale", "100"); return; } } else { return; } } else { if ( g_skippingcin->integer ) {//We're skipping the cinematic and it's over now gi.cvar_set("timescale", "1"); gi.cvar_set("skippingCinematic", "0"); } if ( ent->client->ps.pm_type == PM_DEAD && cg.missionStatusDeadTime < level.time ) {//mission status screen is up because player is dead, stop all scripts if (Q_stricmpn(level.mapname,"_holo",5)) { stop_icarus = qtrue; } } } // Don't allow the player to adjust the pitch when they are in third person overhead cam. extern vmCvar_t cg_thirdPerson; if ( cg_thirdPerson.integer == 2 ) { ucmd->angles[PITCH] = 0; } if ( player_locked && ent->client->ps.pm_type < PM_DEAD ) {//lock out player control unless dead VectorClear(ucmd->angles) ; ucmd->forwardmove = 0; ucmd->rightmove = 0; ucmd->buttons = 0; ucmd->upmove = 0; } } else { G_NPCMunroMatchPlayerWeapon( ent ); } client = ent->client; // mark the time, so the connection sprite can be removed client->lastCmdTime = level.time; client->pers.lastCommand = *ucmd; // sanity check the command time to prevent speedup cheating if ( ucmd->serverTime > level.time + 200 ) { ucmd->serverTime = level.time + 200; } if ( ucmd->serverTime < level.time - 1000 ) { ucmd->serverTime = level.time - 1000; } msec = ucmd->serverTime - client->ps.commandTime; if ( msec < 1 ) { msec = 1; } if ( msec > 200 ) { msec = 200; } // check for inactivity timer, but never drop the local client of a non-dedicated server if ( !ClientInactivityTimer( client ) ) return; if ( client->noclip ) { client->ps.pm_type = PM_NOCLIP; } else if ( client->ps.stats[STAT_HEALTH] <= 0 ) { client->ps.pm_type = PM_DEAD; } else { client->ps.pm_type = PM_NORMAL; } //FIXME: if global gravity changes this should update everyone's personal gravity... if ( !(ent->svFlags & SVF_CUSTOM_GRAVITY) ) { client->ps.gravity = g_gravity->value; } // set speed if ( ent->NPC != NULL ) {//we don't actually scale the ucmd, we use actual speeds if ( ent->NPC->combatMove == qfalse ) { if ( !(ucmd->buttons & BUTTON_USE) ) {//Not leaning qboolean Flying = (ucmd->upmove && ent->NPC->stats.moveType == MT_FLYSWIM); qboolean Climbing = (ucmd->upmove && ent->watertype&CONTENTS_LADDER ); client->ps.friction = 6; if ( ucmd->forwardmove || ucmd->rightmove || Flying ) { if ( ent->NPC->behaviorState != BS_FORMATION ) {//In - Formation NPCs set thier desiredSpeed themselves if ( ucmd->buttons & BUTTON_WALKING ) { ent->NPC->desiredSpeed = NPC_GetWalkSpeed( ent );//ent->NPC->stats.walkSpeed; } else//running { ent->NPC->desiredSpeed = NPC_GetRunSpeed( ent );//ent->NPC->stats.runSpeed; } if ( ent->NPC->currentSpeed >= 80 ) {//At higher speeds, need to slow down close to stuff //Slow down as you approach your goal if ( ent->NPC->distToGoal < SLOWDOWN_DIST && client->race != RACE_BORG && !(ent->NPC->aiFlags&NPCAI_NO_SLOWDOWN) )//128 { if ( ent->NPC->desiredSpeed > MIN_NPC_SPEED ) { float slowdownSpeed = ((float)ent->NPC->desiredSpeed) * ent->NPC->distToGoal / SLOWDOWN_DIST; ent->NPC->desiredSpeed = ceil(slowdownSpeed); if ( ent->NPC->desiredSpeed < MIN_NPC_SPEED ) {//don't slow down too much ent->NPC->desiredSpeed = MIN_NPC_SPEED; } } } } } } else if ( Climbing ) { ent->NPC->desiredSpeed = ent->NPC->stats.walkSpeed; } else {//We want to stop ent->NPC->desiredSpeed = 0; } NPC_Accelerate( ent, (ent->NPC->behaviorState==BS_FORMATION), (ent->NPC->behaviorState==BS_FORMATION) ); if ( ent->NPC->currentSpeed <= 24 && ent->NPC->desiredSpeed < ent->NPC->currentSpeed ) {//No-one walks this slow client->ps.speed = ent->NPC->currentSpeed = 0;//Full stop ucmd->forwardmove = 0; ucmd->rightmove = 0; } else { if ( ent->NPC->currentSpeed <= ent->NPC->stats.walkSpeed ) {//Play the walkanim ucmd->buttons |= BUTTON_WALKING; } else { ucmd->buttons &= ~BUTTON_WALKING; } if ( ent->NPC->currentSpeed > 0 ) {//We should be moving if ( Climbing || Flying ) { if ( !ucmd->upmove ) {//We need to force them to take a couple more steps until stopped ucmd->upmove = ent->NPC->last_ucmd.upmove;//was last_upmove; } } else if ( !ucmd->forwardmove && !ucmd->rightmove ) {//We need to force them to take a couple more steps until stopped ucmd->forwardmove = ent->NPC->last_ucmd.forwardmove;//was last_forwardmove; ucmd->rightmove = ent->NPC->last_ucmd.rightmove;//was last_rightmove; } } client->ps.speed = ent->NPC->currentSpeed; //Slow down on turns - don't orbit!!! float turndelta = (180 - fabs( AngleDelta( ent->currentAngles[YAW], ent->NPC->desiredYaw ) ))/180; if ( turndelta < 0.75f ) { client->ps.speed = 0; } else if ( ent->NPC->distToGoal < 100 && turndelta < 1.0 ) {//Turn is greater than 45 degrees or closer than 100 to goal client->ps.speed = floor(((float)(client->ps.speed))*turndelta); } } } } else { ent->NPC->desiredSpeed = ( ucmd->buttons & BUTTON_WALKING ) ? NPC_GetWalkSpeed( ent ) : NPC_GetRunSpeed( ent ); client->ps.speed = ent->NPC->desiredSpeed; } } else {//Client sets ucmds and such for speed alterations client->ps.speed = g_speed->value;//default is 320 } //Apply forced movement if ( client->forced_forwardmove ) { ucmd->forwardmove = client->forced_forwardmove; if ( !client->ps.speed ) { if ( ent->NPC != NULL ) { client->ps.speed = ent->NPC->stats.runSpeed; } else { client->ps.speed = g_speed->value;//default is 320 } } } if ( client->forced_rightmove ) { ucmd->rightmove = client->forced_rightmove; if ( !client->ps.speed ) { if ( ent->NPC != NULL ) { client->ps.speed = ent->NPC->stats.runSpeed; } else { client->ps.speed = g_speed->value;//default is 320 } } } //FIXME: need to do this before check to avoid walls and cliffs (or just cliffs?) BG_AddPushVecToUcmd( ent, ucmd ); BG_CalculateOffsetAngles( ent, ucmd ); // set up for pmove oldEventSequence = client->ps.eventSequence; memset( &pm, 0, sizeof(pm) ); pm.gent = ent; pm.ps = &client->ps; pm.cmd = *ucmd; // pm.tracemask = MASK_PLAYERSOLID; // used differently for navgen pm.tracemask = ent->clipmask; pm.trace = gi.trace; pm.pointcontents = gi.pointcontents; pm.debugLevel = g_debugMove->integer; pm.noFootsteps = 0;//( g_dmflags->integer & DF_NO_FOOTSTEPS ) > 0; VectorCopy( client->ps.origin, oldOrigin ); // perform a pmove Pmove( &pm ); // save results of pmove if ( ent->client->ps.eventSequence != oldEventSequence ) { ent->eventTime = level.time; { int seq; seq = (ent->client->ps.eventSequence-1) & (MAX_PS_EVENTS-1); ent->s.event = ent->client->ps.events[ seq ] | ( ( ent->client->ps.eventSequence & 3 ) << 8 ); ent->s.eventParm = ent->client->ps.eventParms[ seq ]; } } PlayerStateToEntityState( &ent->client->ps, &ent->s ); VectorCopy ( ent->currentOrigin, ent->lastOrigin ); #if 1 // use the precise origin for linking VectorCopy( ent->client->ps.origin, ent->currentOrigin ); #else //We don't use prediction anymore, so screw this // use the snapped origin for linking so it matches client predicted versions VectorCopy( ent->s.pos.trBase, ent->currentOrigin ); #endif VectorCopy (pm.mins, ent->mins); VectorCopy (pm.maxs, ent->maxs); ent->waterlevel = pm.waterlevel; ent->watertype = pm.watertype; VectorCopy( ucmd->angles, client->pers.cmd_angles ); // execute client events ClientEvents( ent, oldEventSequence ); if ( pm.useEvent ) { //TODO: Use TryUse( ent ); } // link entity now, after any personal teleporters have been used gi.linkentity( ent ); ent->client->hiddenDist = 0; if ( !ent->client->noclip ) { G_TouchTriggersLerped( ent ); } // touch other objects ClientImpacts( ent, &pm ); // swap and latch button actions client->oldbuttons = client->buttons; client->buttons = ucmd->buttons; client->latched_buttons |= client->buttons & ~client->oldbuttons; // check for respawning if ( client->ps.stats[STAT_HEALTH] <= 0 ) { // wait for the attack button to be pressed if ( ent->NPC == NULL && level.time > client->respawnTime ) { // don't allow respawn if they are still flying through the // air, unless 10 extra seconds have passed, meaning something // strange is going on, like the corpse is caught in a wind tunnel if ( level.time < client->respawnTime + 10000 ) { if ( client->ps.groundEntityNum == ENTITYNUM_NONE ) { return; } } // pressing attack or use is the normal respawn method if ( ucmd->buttons & ( BUTTON_ATTACK | BUTTON_USE_HOLDABLE ) ) { respawn( ent ); } } return; } if ((cg.missionStatusShow) && ((cg.missionStatusDeadTime + 1) < level.time)) { if ( ucmd->buttons & ( BUTTON_ATTACK | BUTTON_USE_HOLDABLE ) ) { cg.missionStatusShow = 0; ScoreBoardReset(); // Q3_TaskIDComplete( ent, TID_MISSIONSTATUS ); } } // perform once-a-second actions //ClientTimerActions( ent, msec ); //DEBUG INFO /* if ( client->ps.clientNum < 1 ) {//Only a player if ( ucmd->buttons & BUTTON_USE ) { NAV_PrintLocalWpDebugInfo( ent ); } } */ }
void BotUpdateEntityItems() { int ent, i, modelindex; vec3_t dir; levelitem_t* li, * nextli; aas_entityinfo_t entinfo; itemconfig_t* ic; //timeout current entity items if necessary for ( li = levelitems; li; li = nextli ) { nextli = li->next; //if it is a item that will time out if ( li->timeout ) { //timeout the item if ( li->timeout < AAS_Time() ) { RemoveLevelItemFromList( li ); FreeLevelItem( li ); } //end if } //end if } //end for //find new entity items ic = itemconfig; if ( !itemconfig ) { return; } // for ( ent = AAS_NextEntity( 0 ); ent; ent = AAS_NextEntity( ent ) ) { if ( AAS_EntityType( ent ) != Q3ET_ITEM ) { continue; } //get the model index of the entity modelindex = AAS_EntityModelindex( ent ); // if ( !modelindex ) { continue; } //get info about the entity AAS_EntityInfo( ent, &entinfo ); //FIXME: don't do this //skip all floating items for now if ( !( GGameType & GAME_Quake3 ) && entinfo.groundent != Q3ENTITYNUM_WORLD ) { continue; } //if the entity is still moving if ( entinfo.origin[ 0 ] != entinfo.lastvisorigin[ 0 ] || entinfo.origin[ 1 ] != entinfo.lastvisorigin[ 1 ] || entinfo.origin[ 2 ] != entinfo.lastvisorigin[ 2 ] ) { continue; } //check if the entity is already stored as a level item for ( li = levelitems; li; li = li->next ) { if ( GGameType & GAME_Quake3 ) { //if the level item is linked to an entity if ( li->entitynum && li->entitynum == ent ) { //the entity is re-used if the models are different if ( ic->iteminfo[ li->iteminfo ].modelindex != modelindex ) { //remove this level item RemoveLevelItemFromList( li ); FreeLevelItem( li ); li = NULL; break; } else { if ( entinfo.origin[ 0 ] != li->origin[ 0 ] || entinfo.origin[ 1 ] != li->origin[ 1 ] || entinfo.origin[ 2 ] != li->origin[ 2 ] ) { VectorCopy( entinfo.origin, li->origin ); //also update the goal area number li->goalareanum = AAS_BestReachableArea( li->origin, ic->iteminfo[ li->iteminfo ].mins, ic->iteminfo[ li->iteminfo ].maxs, li->goalorigin ); } break; } } } else { //if the model of the level item and the entity are different if ( ic->iteminfo[ li->iteminfo ].modelindex != modelindex ) { continue; } //if the level item is linked to an entity if ( li->entitynum ) { if ( li->entitynum == ent ) { VectorCopy( entinfo.origin, li->origin ); break; } //end if } //end if else { //check if the entity is very close VectorSubtract( li->origin, entinfo.origin, dir ); if ( VectorLength( dir ) < 30 ) { //found an entity for this level item li->entitynum = ent; //keep updating the entity origin VectorCopy( entinfo.origin, li->origin ); //also update the goal area number li->goalareanum = AAS_BestReachableArea( li->origin, ic->iteminfo[ li->iteminfo ].mins, ic->iteminfo[ li->iteminfo ].maxs, li->goalorigin ); //Log_Write("found item %s entity", ic->iteminfo[li->iteminfo].classname); break; } //end if //else BotImport_Print(PRT_MESSAGE, "item %s has no attached entity\n", // ic->iteminfo[li->iteminfo].name); } //end else } } //end for if ( li ) { continue; } if ( GGameType & GAME_Quake3 ) { //try to link the entity to a level item for ( li = levelitems; li; li = li->next ) { //if this level item is already linked if ( li->entitynum ) { continue; } if ( g_gametype == Q3GT_SINGLE_PLAYER ) { if ( li->flags & IFL_NOTSINGLE ) { continue; } } else if ( g_gametype >= Q3GT_TEAM ) { if ( li->flags & IFL_NOTTEAM ) { continue; } } else { if ( li->flags & IFL_NOTFREE ) { continue; } } //if the model of the level item and the entity are the same if ( ic->iteminfo[ li->iteminfo ].modelindex == modelindex ) { //check if the entity is very close VectorSubtract( li->origin, entinfo.origin, dir ); if ( VectorLength( dir ) < 30 ) { //found an entity for this level item li->entitynum = ent; //if the origin is different if ( entinfo.origin[ 0 ] != li->origin[ 0 ] || entinfo.origin[ 1 ] != li->origin[ 1 ] || entinfo.origin[ 2 ] != li->origin[ 2 ] ) { //update the level item origin VectorCopy( entinfo.origin, li->origin ); //also update the goal area number li->goalareanum = AAS_BestReachableArea( li->origin, ic->iteminfo[ li->iteminfo ].mins, ic->iteminfo[ li->iteminfo ].maxs, li->goalorigin ); } #ifdef DEBUG Log_Write( "linked item %s to an entity", ic->iteminfo[ li->iteminfo ].classname ); #endif break; } } } if ( li ) { continue; } } //check if the model is from a known item for ( i = 0; i < ic->numiteminfo; i++ ) { if ( ic->iteminfo[ i ].modelindex == modelindex ) { break; } //end if } //end for //if the model is not from a known item if ( i >= ic->numiteminfo ) { continue; } //allocate a new level item li = AllocLevelItem(); // if ( !li ) { continue; } //entity number of the level item li->entitynum = ent; //number for the level item li->number = numlevelitems + ent; //set the item info index for the level item li->iteminfo = i; //origin of the item VectorCopy( entinfo.origin, li->origin ); //get the item goal area and goal origin li->goalareanum = AAS_BestReachableArea( li->origin, ic->iteminfo[ i ].mins, ic->iteminfo[ i ].maxs, li->goalorigin ); //never go for items dropped into jumppads if ( AAS_AreaJumpPad( li->goalareanum ) ) { FreeLevelItem( li ); continue; } //end if //time this item out after 30 seconds //dropped items disappear after 30 seconds li->timeout = AAS_Time() + 30; //add the level item to the list AddLevelItemToList( li ); } }
int BotGetLevelItemGoalQ3( int index, const char* name, bot_goal_q3_t* goal ) { if ( !itemconfig ) { return -1; } levelitem_t* li = levelitems; if ( index >= 0 ) { for (; li; li = li->next ) { if ( li->number == index ) { li = li->next; break; } } } for (; li; li = li->next ) { if ( GGameType & GAME_WolfSP ) { if ( g_gametype == Q3GT_SINGLE_PLAYER ) { if ( li->flags & IFL_NOTSINGLE ) { continue; } } else if ( g_gametype >= Q3GT_TEAM ) { if ( li->flags & IFL_NOTTEAM ) { continue; } } else { if ( li->flags & IFL_NOTFREE ) { continue; } } } else if ( GGameType & GAME_WolfMP ) { if ( g_gametype == Q3GT_SINGLE_PLAYER ) { if ( li->flags & IFL_NOTSINGLE ) { continue; } } else if ( g_gametype >= Q3GT_TEAM ) { if ( li->flags & IFL_NOTTEAM ) { continue; } } else { if ( li->flags & IFL_NOTFREE ) { continue; } } } else { if ( g_gametype == Q3GT_SINGLE_PLAYER ) { if ( li->flags & IFL_NOTSINGLE ) { continue; } } else if ( g_gametype >= Q3GT_TEAM ) { if ( li->flags & IFL_NOTTEAM ) { continue; } } else { if ( li->flags & IFL_NOTFREE ) { continue; } } if ( li->flags & IFL_NOTBOT ) { continue; } } if ( !String::ICmp( name, itemconfig->iteminfo[ li->iteminfo ].name ) ) { goal->areanum = li->goalareanum; VectorCopy( li->goalorigin, goal->origin ); goal->entitynum = li->entitynum; VectorCopy( itemconfig->iteminfo[ li->iteminfo ].mins, goal->mins ); VectorCopy( itemconfig->iteminfo[ li->iteminfo ].maxs, goal->maxs ); goal->number = li->number; if ( GGameType & GAME_Quake3 ) { goal->flags = GFL_ITEM; if ( li->timeout ) { goal->flags |= GFL_DROPPED; } } return li->number; } } return -1; }
/* ================== BotAIStartFrame ================== */ int BotAIStartFrame(int time) { int i; gentity_t *ent; bot_entitystate_t state; int elapsed_time, thinktime; static int local_time; static int botlib_residual; static int lastbotthink_time; G_CheckBotSpawn(); trap_Cvar_Update(&bot_rocketjump); trap_Cvar_Update(&bot_grapple); trap_Cvar_Update(&bot_fastchat); trap_Cvar_Update(&bot_nochat); trap_Cvar_Update(&bot_testrchat); trap_Cvar_Update(&bot_thinktime); trap_Cvar_Update(&bot_memorydump); trap_Cvar_Update(&bot_saveroutingcache); trap_Cvar_Update(&bot_pause); trap_Cvar_Update(&bot_report); if (bot_report.integer) { // BotTeamplayReport(); // trap_Cvar_Set("bot_report", "0"); BotUpdateInfoConfigStrings(); } if (bot_pause.integer) { // execute bot user commands every frame for( i = 0; i < MAX_CLIENTS; i++ ) { if( !botstates[i] || !botstates[i]->inuse ) { continue; } if( g_entities[i].client->pers.connected != CON_CONNECTED ) { continue; } botstates[i]->lastucmd.forwardmove = 0; botstates[i]->lastucmd.rightmove = 0; botstates[i]->lastucmd.upmove = 0; botstates[i]->lastucmd.buttons = 0; botstates[i]->lastucmd.serverTime = time; trap_BotUserCommand(botstates[i]->client, &botstates[i]->lastucmd); } return qtrue; } if (bot_memorydump.integer) { trap_BotLibVarSet("memorydump", "1"); trap_Cvar_Set("bot_memorydump", "0"); } if (bot_saveroutingcache.integer) { trap_BotLibVarSet("saveroutingcache", "1"); trap_Cvar_Set("bot_saveroutingcache", "0"); } //check if bot interbreeding is activated BotInterbreeding(); //cap the bot think time if (bot_thinktime.integer > 200) { trap_Cvar_Set("bot_thinktime", "200"); } //if the bot think time changed we should reschedule the bots if (bot_thinktime.integer != lastbotthink_time) { lastbotthink_time = bot_thinktime.integer; BotScheduleBotThink(); } elapsed_time = time - local_time; local_time = time; botlib_residual += elapsed_time; if (elapsed_time > bot_thinktime.integer) thinktime = elapsed_time; else thinktime = bot_thinktime.integer; // update the bot library if ( botlib_residual >= thinktime ) { botlib_residual -= thinktime; trap_BotLibStartFrame((float) time / 1000); if (!trap_AAS_Initialized()) return qfalse; //update entities in the botlib for (i = 0; i < MAX_GENTITIES; i++) { ent = &g_entities[i]; if (!ent->inuse) { trap_BotLibUpdateEntity(i, NULL); continue; } if (!ent->r.linked) { trap_BotLibUpdateEntity(i, NULL); continue; } if (ent->r.svFlags & SVF_NOCLIENT) { trap_BotLibUpdateEntity(i, NULL); continue; } // do not update missiles if (ent->s.eType == ET_MISSILE && ent->s.weapon != WP_GRAPPLING_HOOK) { trap_BotLibUpdateEntity(i, NULL); continue; } // do not update event only entities if (ent->s.eType > ET_EVENTS) { trap_BotLibUpdateEntity(i, NULL); continue; } #ifdef MISSIONPACK // never link prox mine triggers if (ent->r.contents == CONTENTS_TRIGGER) { if (ent->touch == ProximityMine_Trigger) { trap_BotLibUpdateEntity(i, NULL); continue; } } #endif // memset(&state, 0, sizeof(bot_entitystate_t)); // VectorCopy(ent->r.currentOrigin, state.origin); if (i < MAX_CLIENTS) { VectorCopy(ent->s.apos.trBase, state.angles); } else { VectorCopy(ent->r.currentAngles, state.angles); } VectorCopy(ent->s.origin2, state.old_origin); VectorCopy(ent->r.mins, state.mins); VectorCopy(ent->r.maxs, state.maxs); state.type = ent->s.eType; state.flags = ent->s.eFlags; if (ent->r.bmodel) state.solid = SOLID_BSP; else state.solid = SOLID_BBOX; state.groundent = ent->s.groundEntityNum; state.modelindex = ent->s.modelindex; state.modelindex2 = ent->s.modelindex2; state.frame = ent->s.frame; state.event = ent->s.event; state.eventParm = ent->s.eventParm; state.powerups = ent->s.powerups; state.legsAnim = ent->s.legsAnim; state.torsoAnim = ent->s.torsoAnim; state.weapon = ent->s.weapon; // trap_BotLibUpdateEntity(i, &state); } BotAIRegularUpdate(); } floattime = trap_AAS_Time(); // execute scheduled bot AI for( i = 0; i < MAX_CLIENTS; i++ ) { if( !botstates[i] || !botstates[i]->inuse ) { continue; } // botstates[i]->botthink_residual += elapsed_time; // if ( botstates[i]->botthink_residual >= thinktime ) { botstates[i]->botthink_residual -= thinktime; if (!trap_AAS_Initialized()) return qfalse; if (g_entities[i].client->pers.connected == CON_CONNECTED) { BotAI(i, (float) thinktime / 1000); } } } // execute bot user commands every frame for( i = 0; i < MAX_CLIENTS; i++ ) { if( !botstates[i] || !botstates[i]->inuse ) { continue; } if( g_entities[i].client->pers.connected != CON_CONNECTED ) { continue; } BotUpdateInput(botstates[i], time, elapsed_time); trap_BotUserCommand(botstates[i]->client, &botstates[i]->lastucmd); } return qtrue; }
/* ==================== CL_GetMessage Handles recording and playback of demos, on top of NET_ code ==================== */ int CL_GetMessage (void) { int r, i; float f; if (cls.demoplayback) { // decide if it is time to grab the next message if (cls.signon == SIGNONS) // allways grab until fully connected { if (cls.timedemo) { if (host_framecount == cls.td_lastframe) return 0; // allready read this frame's message cls.td_lastframe = host_framecount; // if this is the second frame, grab the real td_starttime // so the bogus time on the first frame doesn't count if (host_framecount == cls.td_startframe + 1) cls.td_starttime = realtime; } else if ( /* cl.time > 0 && */ cl.time <= cl.mtime[0]) { return 0; // don't need another message yet } } // get the next message fread (&net_message.cursize, 4, 1, cls.demofile); VectorCopy (cl.mviewangles[0], cl.mviewangles[1]); for (i=0 ; i<3 ; i++) { r = fread (&f, 4, 1, cls.demofile); cl.mviewangles[0][i] = LittleFloat (f); } net_message.cursize = LittleLong (net_message.cursize); if (net_message.cursize > MAX_MSGLEN) Sys_Error ("Demo message > MAX_MSGLEN"); r = fread (net_message.data, net_message.cursize, 1, cls.demofile); if (r != 1) { CL_StopPlayback (); return 0; } return 1; } while (1) { r = NET_GetMessage (cls.netcon); if (r != 1 && r != 2) return r; // discard nop keepalive message if (net_message.cursize == 1 && net_message.data[0] == svc_nop) Con_Printf ("<-- server to client keepalive\n"); else break; } if (cls.demorecording) CL_WriteDemoMessage (); return r; }
/* =========== Drag_Begin =========== */ void Drag_Begin (int x, int y, int buttons, vec3_t xaxis, vec3_t yaxis, vec3_t origin, vec3_t dir) { trace_t t; drag_ok = false; VectorCopy (vec3_origin, pressdelta); VectorCopy (vec3_origin, vPressStart); drag_first = true; peLink = NULL; // shift LBUTTON = select entire brush if (buttons == (MK_LBUTTON | MK_SHIFT) && g_qeglobals.d_select_mode != sel_curvepoint) { int nFlag = (static_cast<bool>(::GetAsyncKeyState(VK_MENU))) ? SF_CYCLE : 0; if (dir[0] == 0 || dir[1] == 0 || dir[2] == 0) // extremely low chance of this happening from camera Select_Ray (origin, dir, nFlag | SF_ENTITIES_FIRST); // hack for XY else Select_Ray (origin, dir, nFlag); return; } // ctrl-shift LBUTTON = select single face if (buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT) && g_qeglobals.d_select_mode != sel_curvepoint) { Select_Deselect (); Select_Ray (origin, dir, SF_SINGLEFACE); return; } // LBUTTON + all other modifiers = manipulate selection if (buttons & MK_LBUTTON) { Drag_Setup (x, y, buttons, xaxis, yaxis, origin, dir); return; } int nMouseButton = g_PrefsDlg.m_nMouseButtons == 2 ? MK_RBUTTON : MK_MBUTTON; // middle button = grab texture if (buttons == nMouseButton) { t = Test_Ray (origin, dir, false); if (t.face) { g_qeglobals.d_new_brush_bottom_z = t.brush->mins[2]; g_qeglobals.d_new_brush_top_z = t.brush->maxs[2]; Texture_SetTexture (&t.face->texdef); UpdateSurfaceDialog(); UpdatePatchInspector(); } else Sys_Printf ("Did not select a texture\n"); return; } // ctrl-middle button = set entire brush to texture if (buttons == (nMouseButton|MK_CONTROL) ) { t = Test_Ray (origin, dir, false); if (t.brush) { if (t.brush->brush_faces->texdef.name[0] == '(') Sys_Printf ("Can't change an entity texture\n"); else { Brush_SetTexture (t.brush, &g_qeglobals.d_texturewin.texdef, false, false); Sys_UpdateWindows (W_ALL); } } else Sys_Printf ("Didn't hit a btrush\n"); return; } // ctrl-shift-middle button = set single face to texture if (buttons == (nMouseButton|MK_SHIFT|MK_CONTROL) ) { t = Test_Ray (origin, dir, false); if (t.brush) { if (t.brush->brush_faces->texdef.name[0] == '(') Sys_Printf ("Can't change an entity texture\n"); else { SetFaceTexdef (t.brush, t.face, &g_qeglobals.d_texturewin.texdef, false, false); Brush_Build( t.brush ); Sys_UpdateWindows (W_ALL); } } else Sys_Printf ("Didn't hit a btrush\n"); return; } // shift-middle = (if light) // set face texture info (err...whatever), // else // set brush to texture but preserve any system faces // if (buttons == (nMouseButton | MK_SHIFT)) { Sys_Printf("Set brush face texture info\n"); t = Test_Ray (origin, dir, false); if (t.brush) { if (t.brush->brush_faces->texdef.name[0] == '(') { if (strcmpi(t.brush->owner->eclass->name, "light") == 0) { CString strBuff; qtexture_t* pTex = Texture_ForName(g_qeglobals.d_texturewin.texdef.name); if (pTex) { vec3_t vColor; VectorCopy(pTex->color, vColor); float fLargest = 0.0f; for (int i = 0; i < 3; i++) { if (vColor[i] > fLargest) fLargest = vColor[i]; } if (fLargest == 0.0f) { vColor[0] = vColor[1] = vColor[2] = 1.0f; } else { float fScale = 1.0f / fLargest; for (int i = 0; i < 3; i++) { vColor[i] *= fScale; } } strBuff.Format("%f %f %f",pTex->color[0], pTex->color[1], pTex->color[2]); SetKeyValue(t.brush->owner, "_color", strBuff.GetBuffer(0)); Sys_UpdateWindows (W_ALL); } } else { Sys_Printf ("Can't select an entity brush face\n"); } } else { Brush_SetTexture (t.brush, &g_qeglobals.d_texturewin.texdef, false, true); Sys_UpdateWindows (W_ALL); } } else Sys_Printf ("Didn't hit a brush\n"); return; } }
// //=========== //MoveSelection //=========== // void MoveSelection (vec3_t move) { int i; brush_t *b; CString strStatus; vec3_t vTemp, vTemp2; if (!move[0] && !move[1] && !move[2]) return; if (g_pParentWnd->ActiveXY()->RotateMode() || g_bPatchBendMode) { float fDeg = -move[2]; float fAdj = move[2]; int nAxis = 0; if (g_pParentWnd->ActiveXY()->GetViewType() == XY) { fDeg = -move[1]; fAdj = move[1]; nAxis = 2; } else if (g_pParentWnd->ActiveXY()->GetViewType() == XZ) { fDeg = move[2]; fAdj = move[2]; nAxis = 1; } else nAxis = 0; g_pParentWnd->ActiveXY()->Rotation()[nAxis] += fAdj; strStatus.Format("%s x:: %.1f y:: %.1f z:: %.1f", (g_bPatchBendMode) ? "Bend angle" : "Rotation", g_pParentWnd->ActiveXY()->Rotation()[0], g_pParentWnd->ActiveXY()->Rotation()[1], g_pParentWnd->ActiveXY()->Rotation()[2]); g_pParentWnd->SetStatusText(2, strStatus); if (g_bPatchBendMode) { Patch_SelectBendNormal(); Select_RotateAxis(nAxis, fDeg*2, false, true); Patch_SelectBendAxis(); Select_RotateAxis(nAxis, fDeg, false, true); } else { Select_RotateAxis(nAxis, fDeg, false, true); } return; } if (g_pParentWnd->ActiveXY()->ScaleMode()) { vec3_t v; v[0] = v[1] = v[2] = 1.0; if (move[1] > 0) { v[0] = 1.1; v[1] = 1.1; v[2] = 1.1; } else if (move[1] < 0) { v[0] = 0.9; v[1] = 0.9; v[2] = 0.9; } Select_Scale((g_nScaleHow & SCALE_X) ? v[0] : 1.0, (g_nScaleHow & SCALE_Y) ? v[1] : 1.0, (g_nScaleHow & SCALE_Z) ? v[2] : 1.0); Sys_UpdateWindows (W_ALL); return; } vec3_t vDistance; VectorSubtract(pressdelta, vPressStart, vDistance); strStatus.Format("Distance x: %.1f y: %.1f z: %.1f", vDistance[0], vDistance[1], vDistance[2]); g_pParentWnd->SetStatusText(3, strStatus); // // dragging only a part of the selection // // this is fairly crappy way to deal with curvepoint and area selection // but it touches the smallest amount of code this way // if (g_qeglobals.d_num_move_points || g_qeglobals.d_select_mode == sel_area) { if (g_qeglobals.d_select_mode == sel_area) { VectorAdd(g_qeglobals.d_vAreaBR, move, g_qeglobals.d_vAreaBR); return; } if (g_qeglobals.d_select_mode == sel_curvepoint) { Patch_UpdateSelected(move); return; } else { for (i=0 ; i<g_qeglobals.d_num_move_points ; i++) VectorAdd (g_qeglobals.d_move_points[i], move, g_qeglobals.d_move_points[i]); } //VectorScale(move, .5, move); //for (i=0 ; i<g_qeglobals.d_num_move_points2 ; i++) // VectorAdd (g_qeglobals.d_move_points2[i], move, g_qeglobals.d_move_points2[i]); for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) { VectorCopy(b->maxs, vTemp); VectorSubtract(vTemp, b->mins, vTemp); Brush_Build( b ); for (i=0 ; i<3 ; i++) if (b->mins[i] > b->maxs[i] || b->maxs[i] - b->mins[i] > WORLD_SIZE) break; // dragged backwards or f****d up if (i != 3) break; if (b->patchBrush) { VectorCopy(b->maxs, vTemp2); VectorSubtract(vTemp2, b->mins, vTemp2); VectorSubtract(vTemp2, vTemp, vTemp2); if (!Patch_DragScale(b->nPatchID, vTemp2, move)) { b = NULL; break; } } } // if any of the brushes were crushed out of existance // calcel the entire move if (b != &selected_brushes) { Sys_Printf ("Brush dragged backwards, move canceled\n"); for (i=0 ; i<g_qeglobals.d_num_move_points ; i++) VectorSubtract (g_qeglobals.d_move_points[i], move, g_qeglobals.d_move_points[i]); for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) Brush_Build( b ); } } else { // // if there are lots of brushes selected, just translate instead // of rebuilding the brushes // if (drag_yvec[2] == 0 && selected_brushes.next->next != &selected_brushes) { Select_Move (move); //VectorAdd (g_qeglobals.d_select_translate, move, g_qeglobals.d_select_translate); } else { Select_Move (move); } } }
//----------------------------------------------------------------------------- // Method to sample the windspeed at a particular time //----------------------------------------------------------------------------- void GetWindspeedAtTime( float flTime, Vector &vecVelocity ) { // For now, ignore history and time.. fix later when we use wind to affect // client-side prediction VectorCopy( s_vecWindVelocity, vecVelocity ); }
void CLH2_UpdateStreams() { h2stream_t* stream = clh2_Streams; for ( int streamIndex = 0; streamIndex < MAX_STREAMS_H2; streamIndex++, stream++ ) { if ( !stream->models[ 0 ] ) { // Inactive continue; } if ( stream->endTime < cl.serverTime ) { // Inactive if ( stream->type != H2TE_STREAM_LIGHTNING && stream->type != H2TE_STREAM_LIGHTNING_SMALL ) { continue; } else if ( stream->endTime + 250 < cl.serverTime ) { continue; } } if ( stream->flags & H2STREAM_ATTACHED && stream->endTime >= cl.serverTime ) { // Attach the start position to owner h2entity_state_t* state = CLH2_FindState( stream->entity ); if ( state ) { VectorAdd( state->origin, stream->offset, stream->source ); } } vec3_t dist; VectorSubtract( stream->dest, stream->source, dist ); vec3_t angles; VecToAnglesBuggy( dist, angles ); vec3_t org; VectorCopy( stream->source, org ); float d = VectorNormalize( dist ); vec3_t right, up; float cosTime, sinTime, lifeTime, cos2Time, sin2Time; if ( ( GGameType & GAME_HexenWorld ) && stream->type == H2TE_STREAM_SUNSTAFF2 ) { vec3_t discard; AngleVectors( angles, discard, right, up ); lifeTime = ( stream->endTime - cl.serverTime ) / 800.0f; cosTime = cos( cl.serverTime * 0.001 * 5 ); sinTime = sin( cl.serverTime * 0.001 * 5 ); cos2Time = cos( cl.serverTime * 0.001 * 5 + 3.14 ); sin2Time = sin( cl.serverTime * 0.001 * 5 + 3.14 ); } int segmentCount = 0; if ( stream->type == H2TE_STREAM_ICECHUNKS ) { int offset = ( cl.serverTime / 25 ) % 30; for ( int i = 0; i < 3; i++ ) { org[ i ] += dist[ i ] * offset; } } while ( d > 0 ) { refEntity_t ent; Com_Memset( &ent, 0, sizeof ( ent ) ); ent.reType = RT_MODEL; VectorCopy( org, ent.origin ); ent.hModel = stream->models[ 0 ]; switch ( stream->type ) { case H2TE_STREAM_CHAIN: angles[ 2 ] = 0; CLH2_SetRefEntAxis( &ent, angles, oldvec3_origin, 0, 128, H2MLS_ABSLIGHT ); R_AddRefEntityToScene( &ent ); break; case H2TE_STREAM_SUNSTAFF1: angles[ 2 ] = ( cl.serverTime / 100 ) % 360; if ( GGameType & GAME_HexenWorld ) { CLH2_SetRefEntAxis( &ent, angles, oldvec3_origin, 50 + ( stream->endTime - cl.serverTime ) / 3, 128, H2MLS_ABSLIGHT ); } else { CLH2_SetRefEntAxis( &ent, angles, oldvec3_origin, 0, 128, H2MLS_ABSLIGHT ); } R_AddRefEntityToScene( &ent ); Com_Memset( &ent, 0, sizeof ( ent ) ); ent.reType = RT_MODEL; VectorCopy( org, ent.origin ); ent.hModel = stream->models[ 1 ]; angles[ 2 ] = ( cl.serverTime / 20 ) % 360; if ( GGameType & GAME_HexenWorld ) { CLH2_SetRefEntAxis( &ent, angles, oldvec3_origin, 50 + ( stream->endTime - cl.serverTime ) * 0.2f, 128, H2MLS_ABSLIGHT | H2DRF_TRANSLUCENT ); } else { CLH2_SetRefEntAxis( &ent, angles, oldvec3_origin, 0, 128, H2MLS_ABSLIGHT | H2DRF_TRANSLUCENT ); } R_AddRefEntityToScene( &ent ); break; case H2TE_STREAM_SUNSTAFF2: if ( !( GGameType & GAME_HexenWorld ) ) { angles[ 2 ] = ( cl.serverTime / 100 ) % 360; ent.frame = ( cl.serverTime / 100 ) % 8; CLH2_SetRefEntAxis( &ent, angles, oldvec3_origin, 0, 128, H2MLS_ABSLIGHT ); R_AddRefEntityToScene( &ent ); } else { angles[ 2 ] = ( int )( cl.serverTime * 0.001 * 100 ) % 360; VectorMA( ent.origin, cosTime * ( 40 * lifeTime ), right, ent.origin ); VectorMA( ent.origin, sinTime * ( 40 * lifeTime ), up, ent.origin ); CLH2_SetRefEntAxis( &ent, angles, oldvec3_origin, 100 + 150 * lifeTime, 128, H2MLS_ABSLIGHT | H2DRF_TRANSLUCENT ); R_AddRefEntityToScene( &ent ); Com_Memset( &ent, 0, sizeof ( ent ) ); ent.reType = RT_MODEL; VectorCopy( org, ent.origin ); ent.hModel = stream->models[ 0 ]; angles[ 2 ] = ( int )( cl.serverTime * 0.001 * 100 ) % 360; VectorMA( ent.origin, cos2Time * ( 40 * lifeTime ), right, ent.origin ); VectorMA( ent.origin, sin2Time * ( 40 * lifeTime ), up, ent.origin ); CLH2_SetRefEntAxis( &ent, angles, oldvec3_origin, 100 + 150 * lifeTime, 128, H2MLS_ABSLIGHT | H2DRF_TRANSLUCENT ); R_AddRefEntityToScene( &ent ); for ( int ix = 0; ix < 2; ix++ ) { Com_Memset( &ent, 0, sizeof ( ent ) ); ent.reType = RT_MODEL; VectorCopy( org, ent.origin ); if ( ix ) { VectorMA( ent.origin, cos2Time * ( 40 * lifeTime ), right, ent.origin ); VectorMA( ent.origin, sin2Time * ( 40 * lifeTime ), up, ent.origin ); } else { VectorMA( ent.origin, cosTime * ( 40 * lifeTime ), right, ent.origin ); VectorMA( ent.origin, sinTime * ( 40 * lifeTime ), up, ent.origin ); } ent.hModel = stream->models[ 1 ]; angles[ 2 ] = ( int )( cl.serverTime * 0.001 * 20 ) % 360; CLH2_SetRefEntAxis( &ent, angles, oldvec3_origin, 100 + 150 * lifeTime, 128, H2MLS_ABSLIGHT ); R_AddRefEntityToScene( &ent ); } } break; case H2TE_STREAM_LIGHTNING: if ( stream->endTime < cl.serverTime ) {//fixme: keep last non-translucent frame and angle angles[ 2 ] = 0; CLH2_SetRefEntAxis( &ent, angles, oldvec3_origin, 0, 128 + ( stream->endTime - cl.serverTime ) * 192 / 1000.0, H2MLS_ABSLIGHT | H2DRF_TRANSLUCENT ); } else { angles[ 2 ] = rand() % 360; ent.frame = rand() % 6; CLH2_SetRefEntAxis( &ent, angles, oldvec3_origin, 0, 128, H2MLS_ABSLIGHT ); } R_AddRefEntityToScene( &ent ); break; case H2TE_STREAM_LIGHTNING_SMALL: case HWTE_STREAM_LIGHTNING_SMALL: if ( stream->endTime < cl.serverTime ) { angles[ 2 ] = 0; CLH2_SetRefEntAxis( &ent, angles, oldvec3_origin, 0, 128 + ( stream->endTime - cl.serverTime ) * 192 / 1000.0, H2MLS_ABSLIGHT | H2DRF_TRANSLUCENT ); } else { angles[ 2 ] = rand() % 360; ent.frame = rand() % 6; CLH2_SetRefEntAxis( &ent, angles, oldvec3_origin, 0, 128, H2MLS_ABSLIGHT ); } R_AddRefEntityToScene( &ent ); break; case H2TE_STREAM_FAMINE: angles[ 2 ] = rand() % 360; ent.frame = 0; CLH2_SetRefEntAxis( &ent, angles, oldvec3_origin, 0, 128, H2MLS_ABSLIGHT ); R_AddRefEntityToScene( &ent ); break; case H2TE_STREAM_COLORBEAM: angles[ 2 ] = 0; ent.skinNum = stream->skin; CLH2_SetRefEntAxis( &ent, angles, oldvec3_origin, 0, 128, H2MLS_ABSLIGHT ); CLH2_HandleCustomSkin( &ent ); R_AddRefEntityToScene( &ent ); break; case H2TE_STREAM_GAZE: angles[ 2 ] = 0; ent.frame = ( cl.serverTime / 25 ) % 36; CLH2_SetRefEntAxis( &ent, angles, oldvec3_origin, 0, 128, H2MLS_ABSLIGHT ); R_AddRefEntityToScene( &ent ); break; case H2TE_STREAM_ICECHUNKS: angles[ 2 ] = rand() % 360; ent.frame = rand() % 5; CLH2_SetRefEntAxis( &ent, angles, oldvec3_origin, 0, 128, H2MLS_ABSLIGHT ); R_AddRefEntityToScene( &ent ); break; default: angles[ 2 ] = 0; CLH2_SetRefEntAxis( &ent, angles, oldvec3_origin, 0, 0, 0 ); R_AddRefEntityToScene( &ent ); } for ( int i = 0; i < 3; i++ ) { org[ i ] += dist[ i ] * 30; } d -= 30; segmentCount++; } if ( stream->type == H2TE_STREAM_SUNSTAFF1 || ( !( GGameType & GAME_HexenWorld ) && stream->type == H2TE_STREAM_SUNSTAFF2 ) ) { if ( stream->lastTrailTime + 200 < cl.serverTime ) { stream->lastTrailTime = cl.serverTime; CLH2_SunStaffTrail( stream->source, stream->dest ); } refEntity_t ent; Com_Memset( &ent, 0, sizeof ( ent ) ); ent.reType = RT_MODEL; VectorCopy( stream->dest, ent.origin ); ent.hModel = stream->models[ 2 ]; CLH2_SetRefEntAxis( &ent, oldvec3_origin, oldvec3_origin, 80 + ( rand() & 15 ), 128, H2MLS_ABSLIGHT ); R_AddRefEntityToScene( &ent ); Com_Memset( &ent, 0, sizeof ( ent ) ); ent.reType = RT_MODEL; VectorCopy( stream->dest, ent.origin ); ent.hModel = stream->models[ 3 ]; CLH2_SetRefEntAxis( &ent, oldvec3_origin, oldvec3_origin, 150 + ( rand() & 15 ), 128, H2MLS_ABSLIGHT | H2DRF_TRANSLUCENT ); R_AddRefEntityToScene( &ent ); } } }
void LoadJTRAIL(edict_t *ent,char filename[MAX_STR_LEN],qboolean pdm,int clean,int colorp,int sizep) { FILE *jtrail_file; char *token="\0"; char buf2[1000]; char message[256]; int lbuf2,color,mass; edict_t *laser = NULL; vec3_t start; int lasttrailnum=0; char JTRAILFile[MAX_STR_LEN]; int delcount=0; char tok[2]=""; int clean_count=0; int total_good_lines=0; if (TrailsBanned()) return; if (pdm) { if (!Q_stricmp(filename,"lastdemo")) sprintf(JTRAILFile, GAMEVERSION "/puppetdemo/%i.pdm",ent->client->resp.id); else sprintf(JTRAILFile, GAMEVERSION "/puppetdemo/%s-%s.pdm",level.mapname,filename); } else sprintf(JTRAILFile, GAMEVERSION "/jtrail/%s-%s.jtrail",level.mapname,filename); jtrail_file = fopen(JTRAILFile, "r"); if (jtrail_file == NULL) { if (pdm) { if (!Q_stricmp(filename,"lastdemo")) gi.cprintf(ent,PRINT_HIGH,"\"%i.pdm\" was not found!\n",ent->client->resp.id); else gi.cprintf(ent,PRINT_HIGH,"\"%s-%s.pdm\" was not found!\n",level.mapname,filename); } else gi.cprintf(ent,PRINT_HIGH,"\"%s-%s.jtrail\" was not found!\n",level.mapname,filename); return; } if (pdm) tok[0] = ','; //puppet demos parsed with ',' else tok[0] = ' '; //trail files parsed with ' ' tok[1] = '\0'; //grab the total good lines, for new clean-on-load usage while (fgets(buf2, 900, jtrail_file) != NULL) { if (!(((buf2[0] > '0') && (buf2[0] < '9')) || (buf2[0] == '-'))) continue; total_good_lines++; } fclose(jtrail_file); //reopen the file to start reading again... we know it exists so no check on that jtrail_file = fopen(JTRAILFile, "r"); jtrail_num_lines = 0; ltrails++; while (fgets(buf2, 900, jtrail_file) != NULL) { double time; if (!(((buf2[0] > '0') && (buf2[0] < '9')) || (buf2[0] == '-'))) continue; if (clean_count != clean) { if ((jtrail_num_lines != 0) && (jtrail_num_lines != total_good_lines)) { clean_count++; continue; } clean_count++; } else clean_count = 0; message[0]='\0'; lbuf2 = strlen(buf2); while (buf2[lbuf2-1] == '\r' || buf2[lbuf2-1] == '\n') { buf2[lbuf2-1] = 0; lbuf2--; } start[0] = start[1] = start[2] = color = mass = 0; if (ltnodes <= traillimit->value) { laser = G_Spawn(); // laser->owner = ent; ltnodes++; laser->classnum = jtrail_num_lines+1;//ltnodes; laser->classname = "LaserTrailLink"; laser->s.frame = 4; VectorSet (laser->mins, -8, -8, -8); VectorSet (laser->maxs, 8, 8, 8); //Load Coords token = strtok( buf2, tok ); start[0] = atoi(token); token = strtok( NULL, tok ); if ((token == NULL) && pdm) break; start[1] = atoi(token); token = strtok( NULL, tok ); start[2] = atoi(token); VectorCopy(start,laser->s.origin); if (pdm) { if (colorp == -1) laser->s.skinnum = NUMtoCOLOR(1); //color (green) else laser->s.skinnum = NUMtoCOLOR(colorp); if (sizep == -1) laser->s.frame = 4; //size else laser->s.frame = sizep; laser->mass = ltrails; //num (never gonna be multiple paths to load this way) } else { //Load Color token = strtok( NULL, tok ); color = atoi(token); laser->s.skinnum = color; //Load Size token = strtok( NULL, tok ); color = atoi(token); laser->s.frame = color; //Load Gravity token = strtok( NULL, tok ); color = atoi(token); if (lasttrailnum != color) { ltrails++; lasttrailnum = color; } laser->mass = color+ltrails; } time = level.time + (jtrail_num_lines/10); laser->think = DelayLaserLinkOn;//MODIFY ME!!!WHY?!!//DelayMarkerLoad_Think; laser->nextthink = time; gi.linkentity(laser); } else { delcount++; } jtrail_num_lines++; } fclose(jtrail_file); if (delcount !=0) { if (delcount == jtrail_num_lines) gi.bprintf(PRINT_HIGH,"%s: \"%s\" could not be loaded due to traillimit hit!\n",ent->client->pers.netname,JTRAILFile); else { gi.bprintf(PRINT_HIGH,"%s: \"%s\" was partially loaded due to traillimit hit! (%i/%i link",ent->client->pers.netname,JTRAILFile,jtrail_num_lines-delcount,jtrail_num_lines); if (jtrail_num_lines != 1) gi.bprintf(PRINT_HIGH,"s"); if (jtrail_num_lines-delcount > 10) gi.bprintf(PRINT_HIGH," (%i in queue))\n",jtrail_num_lines-delcount-10); else gi.bprintf(PRINT_HIGH,")\n"); } } else { gi.bprintf(PRINT_HIGH,"%s: \"%s\" was loaded successfully! (%i link",ent->client->pers.netname,JTRAILFile,jtrail_num_lines); if (jtrail_num_lines != 1) gi.bprintf(PRINT_HIGH,"s"); if (jtrail_num_lines > 10) gi.bprintf(PRINT_HIGH," (%i in queue))\n",jtrail_num_lines-10); else gi.bprintf(PRINT_HIGH,")\n"); } }
/* ============== ClientThink This will be called once for each client frame, which will usually be a couple times for each server frame. ============== */ void ClientThink (edict_t *ent, usercmd_t *ucmd) { gclient_t *client; edict_t *other; int i, j; pmove_t pm; level.current_entity = ent; client = ent->client; if (level.intermissiontime) { client->ps.pmove.pm_type = PM_FREEZE; // can exit intermission after five seconds if (level.time > level.intermissiontime + 5.0 && (ucmd->buttons & BUTTON_ANY) ) level.exitintermission = true; return; } pm_passent = ent; if (ent->client->chase_target) { client->resp.cmd_angles[0] = SHORT2ANGLE(ucmd->angles[0]); client->resp.cmd_angles[1] = SHORT2ANGLE(ucmd->angles[1]); client->resp.cmd_angles[2] = SHORT2ANGLE(ucmd->angles[2]); } else { // set up for pmove memset (&pm, 0, sizeof(pm)); if (ent->movetype == MOVETYPE_NOCLIP) client->ps.pmove.pm_type = PM_SPECTATOR; else if (ent->s.modelindex != 255) client->ps.pmove.pm_type = PM_GIB; else if (ent->deadflag) client->ps.pmove.pm_type = PM_DEAD; else client->ps.pmove.pm_type = PM_NORMAL; client->ps.pmove.gravity = sv_gravity->value; pm.s = client->ps.pmove; for (i=0 ; i<3 ; i++) { pm.s.origin[i] = ent->s.origin[i]*8; pm.s.velocity[i] = ent->velocity[i]*8; } if (memcmp(&client->old_pmove, &pm.s, sizeof(pm.s))) { pm.snapinitial = true; // gi.dprintf ("pmove changed!\n"); } pm.cmd = *ucmd; pm.trace = PM_trace; // adds default parms pm.pointcontents = gi.pointcontents; // perform a pmove gi.Pmove (&pm); // save results of pmove client->ps.pmove = pm.s; client->old_pmove = pm.s; for (i=0 ; i<3 ; i++) { ent->s.origin[i] = pm.s.origin[i]*0.125; ent->velocity[i] = pm.s.velocity[i]*0.125; } VectorCopy (pm.mins, ent->mins); VectorCopy (pm.maxs, ent->maxs); client->resp.cmd_angles[0] = SHORT2ANGLE(ucmd->angles[0]); client->resp.cmd_angles[1] = SHORT2ANGLE(ucmd->angles[1]); client->resp.cmd_angles[2] = SHORT2ANGLE(ucmd->angles[2]); if (ent->groundentity && !pm.groundentity && (pm.cmd.upmove >= 10) && (pm.waterlevel == 0)) { gi.sound(ent, CHAN_VOICE, gi.soundindex("*jump1.wav"), 1, ATTN_NORM, 0); PlayerNoise(ent, ent->s.origin, PNOISE_SELF); } ent->viewheight = pm.viewheight; ent->waterlevel = pm.waterlevel; ent->watertype = pm.watertype; ent->groundentity = pm.groundentity; if (pm.groundentity) ent->groundentity_linkcount = pm.groundentity->linkcount; if (ent->deadflag) { client->ps.viewangles[ROLL] = 40; client->ps.viewangles[PITCH] = -15; client->ps.viewangles[YAW] = client->killer_yaw; } else { VectorCopy (pm.viewangles, client->v_angle); VectorCopy (pm.viewangles, client->ps.viewangles); } gi.linkentity (ent); if (ent->movetype != MOVETYPE_NOCLIP) G_TouchTriggers (ent); // touch other objects for (i=0 ; i<pm.numtouch ; i++) { other = pm.touchents[i]; for (j=0 ; j<i ; j++) if (pm.touchents[j] == other) break; if (j != i) continue; // duplicated if (!other->touch) continue; other->touch (other, ent, NULL, NULL); } } client->oldbuttons = client->buttons; client->buttons = ucmd->buttons; client->latched_buttons |= client->buttons & ~client->oldbuttons; // save light level the player is standing on for // monster sighting AI ent->light_level = ucmd->lightlevel; // fire weapon from final position if needed if (client->latched_buttons & BUTTON_ATTACK) { if (client->resp.spectator) { client->latched_buttons = 0; if (client->chase_target) { client->chase_target = NULL; client->ps.pmove.pm_flags &= ~PMF_NO_PREDICTION; } else GetChaseTarget(ent); } else if (!client->weapon_thunk) { client->weapon_thunk = true; Think_Weapon (ent); } } if (client->resp.spectator) { if (ucmd->upmove >= 10) { if (!(client->ps.pmove.pm_flags & PMF_JUMP_HELD)) { client->ps.pmove.pm_flags |= PMF_JUMP_HELD; if (client->chase_target) ChaseNext(ent); else GetChaseTarget(ent); } } else client->ps.pmove.pm_flags &= ~PMF_JUMP_HELD; } // update chase cam if being followed for (i = 1; i <= maxclients->value; i++) { other = g_edicts + i; if (other->inuse && other->client->chase_target == ent) UpdateChaseCam(other); } }
/* =========== PutClientInServer Called when a player connects to a server or respawns in a deathmatch. ============ */ void PutClientInServer (edict_t *ent) { vec3_t mins = {-16, -16, -24}; vec3_t maxs = {16, 16, 32}; int index; vec3_t spawn_origin, spawn_angles; gclient_t *client; int i; client_persistant_t saved; client_respawn_t resp; // find a spawn point // do it before setting health back up, so farthest // ranging doesn't count this client SelectSpawnPoint (ent, spawn_origin, spawn_angles); index = ent-g_edicts-1; client = ent->client; // deathmatch wipes most client data every spawn if (deathmatch->value) { char userinfo[MAX_INFO_STRING]; resp = client->resp; memcpy (userinfo, client->pers.userinfo, sizeof(userinfo)); InitClientPersistant (client); ClientUserinfoChanged (ent, userinfo); } else if (coop->value) { // int n; char userinfo[MAX_INFO_STRING]; resp = client->resp; memcpy (userinfo, client->pers.userinfo, sizeof(userinfo)); // this is kind of ugly, but it's how we want to handle keys in coop // for (n = 0; n < game.num_items; n++) // { // if (itemlist[n].flags & IT_KEY) // resp.coop_respawn.inventory[n] = client->pers.inventory[n]; // } resp.coop_respawn.game_helpchanged = client->pers.game_helpchanged; resp.coop_respawn.helpchanged = client->pers.helpchanged; client->pers = resp.coop_respawn; ClientUserinfoChanged (ent, userinfo); if (resp.score > client->pers.score) client->pers.score = resp.score; } else { memset (&resp, 0, sizeof(resp)); } // clear everything but the persistant data saved = client->pers; memset (client, 0, sizeof(*client)); client->pers = saved; if (client->pers.health <= 0) InitClientPersistant(client); client->resp = resp; // copy some data from the client to the entity FetchClientEntData (ent); // clear entity values ent->groundentity = NULL; ent->client = &game.clients[index]; ent->takedamage = DAMAGE_AIM; ent->movetype = MOVETYPE_WALK; ent->viewheight = 22; ent->inuse = true; ent->classname = "player"; ent->mass = 200; ent->solid = SOLID_BBOX; ent->deadflag = DEAD_NO; ent->air_finished = level.time + 12; ent->clipmask = MASK_PLAYERSOLID; ent->model = "players/male/tris.md2"; ent->pain = player_pain; ent->die = player_die; ent->waterlevel = 0; ent->watertype = 0; ent->flags &= ~FL_NO_KNOCKBACK; ent->svflags &= ~SVF_DEADMONSTER; VectorCopy (mins, ent->mins); VectorCopy (maxs, ent->maxs); VectorClear (ent->velocity); // clear playerstate values memset (&ent->client->ps, 0, sizeof(client->ps)); client->ps.pmove.origin[0] = spawn_origin[0]*8; client->ps.pmove.origin[1] = spawn_origin[1]*8; client->ps.pmove.origin[2] = spawn_origin[2]*8; if (deathmatch->value && ((int)dmflags->value & DF_FIXED_FOV)) { client->ps.fov = 90; } else { client->ps.fov = atoi(Info_ValueForKey(client->pers.userinfo, "fov")); if (client->ps.fov < 1) client->ps.fov = 90; else if (client->ps.fov > 160) client->ps.fov = 160; } client->ps.gunindex = gi.modelindex(client->pers.weapon->view_model); // clear entity state values ent->s.effects = 0; ent->s.modelindex = 255; // will use the skin specified model ent->s.modelindex2 = 255; // custom gun model // sknum is player num and weapon number // weapon number will be added in changeweapon ent->s.skinnum = ent - g_edicts - 1; ent->s.frame = 0; VectorCopy (spawn_origin, ent->s.origin); ent->s.origin[2] += 1; // make sure off ground VectorCopy (ent->s.origin, ent->s.old_origin); // set the delta angle for (i=0 ; i<3 ; i++) { client->ps.pmove.delta_angles[i] = ANGLE2SHORT(spawn_angles[i] - client->resp.cmd_angles[i]); } ent->s.angles[PITCH] = 0; ent->s.angles[YAW] = spawn_angles[YAW]; ent->s.angles[ROLL] = 0; VectorCopy (ent->s.angles, client->ps.viewangles); VectorCopy (ent->s.angles, client->v_angle); // spawn a spectator if (client->pers.spectator) { client->chase_target = NULL; client->resp.spectator = true; ent->movetype = MOVETYPE_NOCLIP; ent->solid = SOLID_NOT; ent->svflags |= SVF_NOCLIENT; ent->client->ps.gunindex = 0; gi.linkentity (ent); return; } else client->resp.spectator = false; if (!KillBox (ent)) { // could't spawn in? } gi.linkentity (ent); // force the current weapon up client->newweapon = client->pers.weapon; ChangeWeapon (ent); }
void CGCam_Update( void ) { int i; qboolean checkFollow = qfalse; qboolean checkTrack = qfalse; // Apply new roff data to the camera as needed if ( client_camera.info_state & CAMERA_ROFFING ) { CGCam_Roff(); } //Check for a zoom if ( client_camera.info_state & CAMERA_ZOOMING ) { float actualFOV_X; if ( client_camera.FOV_time + client_camera.FOV_duration < cg.time ) { actualFOV_X = client_camera.FOV = client_camera.FOV2; client_camera.info_state &= ~CAMERA_ZOOMING; } else { actualFOV_X = client_camera.FOV + (( ( client_camera.FOV2 - client_camera.FOV ) ) / client_camera.FOV_duration ) * ( cg.time - client_camera.FOV_time ); } CG_CalcFOVFromX( actualFOV_X ); } else { CG_CalcFOVFromX( client_camera.FOV ); } //Check for pan if ( client_camera.info_state & CAMERA_PANNING ) { //Note: does not actually change the camera's angles until the pan time is done! if ( client_camera.pan_time + client_camera.pan_duration < cg.time ) {//finished panning for ( i = 0; i < 3; i++ ) { client_camera.angles[i] = AngleNormalize360( ( client_camera.angles[i] + client_camera.angles2[i] ) ); } client_camera.info_state &= ~CAMERA_PANNING; VectorCopy(client_camera.angles, cg.refdefViewAngles ); } else {//still panning for ( i = 0; i < 3; i++ ) { //NOTE: does not store the resultant angle in client_camera.angles until pan is done cg.refdefViewAngles[i] = client_camera.angles[i] + ( client_camera.angles2[i] / client_camera.pan_duration ) * ( cg.time - client_camera.pan_time ); } } } else { checkFollow = qtrue; } AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis ); //Check for movement if ( client_camera.info_state & CAMERA_MOVING ) { //NOTE: does not actually move the camera until the movement time is done! if ( client_camera.move_time + client_camera.move_duration < cg.time ) { VectorCopy( client_camera.origin2, client_camera.origin ); client_camera.info_state &= ~CAMERA_MOVING; VectorCopy( client_camera.origin, cg.refdef.vieworg ); } else { for ( i = 0; i < 3; i++ ) cg.refdef.vieworg[i] = client_camera.origin[i] + (( ( client_camera.origin2[i] - client_camera.origin[i] ) ) / client_camera.move_duration ) * ( cg.time - client_camera.move_time ); } } else { checkTrack = qtrue; } if ( checkFollow ) { if ( client_camera.info_state & CAMERA_FOLLOWING ) {//This needs to be done after camera movement CGCam_FollowUpdate(); } VectorCopy(client_camera.angles, cg.refdefViewAngles ); } if ( checkTrack ) { if ( client_camera.info_state & CAMERA_TRACKING ) {//This has to run AFTER Follow if the camera is following a cameraGroup CGCam_TrackUpdate(); } VectorCopy( client_camera.origin, cg.refdef.vieworg ); } //Bar fading if ( client_camera.info_state & CAMERA_BAR_FADING ) { CGCam_UpdateBarFade(); } //Normal fading - separate call because can finish after camera is disabled CGCam_UpdateFade(); //Update shaking if there's any CGCam_UpdateShake( cg.refdef.vieworg, cg.refdefViewAngles ); }
/* =========== Drag_Setup =========== */ void Drag_Setup (int x, int y, int buttons, vec3_t xaxis, vec3_t yaxis, vec3_t origin, vec3_t dir) { trace_t t; face_t *f; drag_first = true; VectorCopy (vec3_origin, pressdelta); pressx = x; pressy = y; VectorCopy (xaxis, drag_xvec); AxializeVector (drag_xvec); VectorCopy (yaxis, drag_yvec); AxializeVector (drag_yvec); extern void SelectCurvePointByRay (vec3_t org, vec3_t dir, int buttons); if (g_qeglobals.d_select_mode == sel_curvepoint) { //if ((buttons == MK_LBUTTON)) // g_qeglobals.d_num_move_points = 0; SelectCurvePointByRay (origin, dir, buttons); if (g_qeglobals.d_num_move_points || g_qeglobals.d_select_mode == sel_area) { drag_ok = true; } Sys_UpdateWindows(W_ALL); return; } else { g_qeglobals.d_num_move_points = 0; } if (selected_brushes.next == &selected_brushes) { Sys_Status("No selection to drag\n", 0); return; } if (g_qeglobals.d_select_mode == sel_vertex) { SelectVertexByRay (origin, dir); if (g_qeglobals.d_num_move_points) { drag_ok = true; return; } } if (g_qeglobals.d_select_mode == sel_edge) { SelectEdgeByRay (origin, dir); if (g_qeglobals.d_num_move_points) { drag_ok = true; return; } } // // check for direct hit first // t = Test_Ray (origin, dir, true); if (t.selected) { drag_ok = true; if (buttons == (MK_LBUTTON|MK_CONTROL) ) { Sys_Printf ("Shear dragging face\n"); Brush_SelectFaceForDragging (t.brush, t.face, true); } else if (buttons == (MK_LBUTTON|MK_CONTROL|MK_SHIFT) ) { Sys_Printf ("Sticky dragging brush\n"); for (f=t.brush->brush_faces ; f ; f=f->next) Brush_SelectFaceForDragging (t.brush, f, false); } else Sys_Printf ("Dragging entire selection\n"); return; } if (g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_edge) return; // // check for side hit // // multiple brushes selected? if (selected_brushes.next->next != &selected_brushes) { // yes, special handling bool bOK = (g_PrefsDlg.m_bALTEdge) ? (static_cast<bool>(::GetAsyncKeyState(VK_MENU))) : true; if (bOK) { for (brush_t* pBrush = selected_brushes.next ; pBrush != &selected_brushes ; pBrush = pBrush->next) { if (buttons & MK_CONTROL) Brush_SideSelect (pBrush, origin, dir, true); else Brush_SideSelect (pBrush, origin, dir, false); } } else { Sys_Printf ("press ALT to drag multiple edges\n"); return; } } else { // single select.. trying to drag fixed entities handle themselves and just move if (buttons & MK_CONTROL) Brush_SideSelect (selected_brushes.next, origin, dir, true); else Brush_SideSelect (selected_brushes.next, origin, dir, false); } Sys_Printf ("Side stretch\n"); drag_ok = true; }
/** * @brief Kills an actor (all that is needed is the local entity state set to STATE_DEAD). * @note Also changes the animation to a random death sequence and appends the dead animation * @param[in] msg The netchannel message * @param[in] self Pointer to the event structure that is currently executed */ void CL_ActorRevitalised (const eventRegister_t *self, struct dbuffer *msg) { le_t *le, *floor; int entnum, state; NET_ReadFormat(msg, self->formatString, &entnum, &state); /* get les */ le = LE_Get(entnum); if (!le) LE_NotFoundError(entnum); if (!LE_IsStunned(le) && !LE_IsLivingActor(le)) Com_Error(ERR_DROP, "CL_ActorRevitalised: Can't revitalise, LE is not a dead or stunned actor"); LE_Lock(le); /* link any floor container into the actor temp floor container */ floor = LE_Find(ET_ITEM, le->pos); if (floor) FLOOR(le) = FLOOR(floor); le->state = state; /* play animation */ LE_SetThink(le, LET_StartIdle); /* Print some info about the death or stun. */ if (le->team == cls.team) { const character_t *chr = CL_ActorGetChr(le); if (chr) { char tmpbuf[128]; Com_sprintf(tmpbuf, lengthof(tmpbuf), _("%s was revitalised\n"), chr->name); HUD_DisplayMessage(tmpbuf); } } else { switch (le->team) { case (TEAM_CIVILIAN): HUD_DisplayMessage(_("A civilian was revitalised.\n")); break; case (TEAM_ALIEN): HUD_DisplayMessage(_("An alien was revitalised.\n")); break; case (TEAM_PHALANX): HUD_DisplayMessage(_("A soldier was revitalised.\n")); break; default: HUD_DisplayMessage(va(_("A member of team %i was revitalised.\n"), le->team)); break; } } VectorCopy(player_maxs, le->maxs); /* add team members to the actor list */ CL_ActorAddToTeamList(le); /* update pathing as we maybe not can walk onto this actor anymore */ CL_ActorConditionalMoveCalc(selActor); LE_Unlock(le); }
void CGCam_SetPosition( vec3_t org ) { VectorCopy( org, client_camera.origin ); VectorCopy( client_camera.origin, cg.refdef.vieworg ); }
/* ============== BotAI ============== */ int BotAI(int client, float thinktime) { bot_state_t *bs; char buf[1024], *args; int j; trap_EA_ResetInput(client); // bs = botstates[client]; if (!bs || !bs->inuse) { BotAI_Print(PRT_FATAL, "BotAI: client %d is not setup\n", client); return qfalse; } //retrieve the current client state BotAI_GetClientState( client, &bs->cur_ps ); //retrieve any waiting server commands while( trap_BotGetServerCommand(client, buf, sizeof(buf)) ) { //have buf point to the command and args to the command arguments args = strchr( buf, ' '); if (!args) continue; *args++ = '\0'; //remove color espace sequences from the arguments RemoveColorEscapeSequences( args ); if (!Q_stricmp(buf, "cp ")) { /*CenterPrintf*/ } else if (!Q_stricmp(buf, "cs")) { /*ConfigStringModified*/ } else if (!Q_stricmp(buf, "print")) { //remove first and last quote from the chat message memmove(args, args+1, strlen(args)); args[strlen(args)-1] = '\0'; trap_BotQueueConsoleMessage(bs->cs, CMS_NORMAL, args); } else if (!Q_stricmp(buf, "chat")) { //remove first and last quote from the chat message memmove(args, args+1, strlen(args)); args[strlen(args)-1] = '\0'; trap_BotQueueConsoleMessage(bs->cs, CMS_CHAT, args); } else if (!Q_stricmp(buf, "tchat")) { //remove first and last quote from the chat message memmove(args, args+1, strlen(args)); args[strlen(args)-1] = '\0'; trap_BotQueueConsoleMessage(bs->cs, CMS_CHAT, args); } #ifdef MISSIONPACK else if (!Q_stricmp(buf, "vchat")) { BotVoiceChatCommand(bs, SAY_ALL, args); } else if (!Q_stricmp(buf, "vtchat")) { BotVoiceChatCommand(bs, SAY_TEAM, args); } else if (!Q_stricmp(buf, "vtell")) { BotVoiceChatCommand(bs, SAY_TELL, args); } #endif else if (!Q_stricmp(buf, "scores")) { /*FIXME: parse scores?*/ } else if (!Q_stricmp(buf, "clientLevelShot")) { /*ignore*/ } } //add the delta angles to the bot's current view angles for (j = 0; j < 3; j++) { bs->viewangles[j] = AngleMod(bs->viewangles[j] + SHORT2ANGLE(bs->cur_ps.delta_angles[j])); } //increase the local time of the bot bs->ltime += thinktime; // bs->thinktime = thinktime; //origin of the bot VectorCopy(bs->cur_ps.origin, bs->origin); //eye coordinates of the bot VectorCopy(bs->cur_ps.origin, bs->eye); bs->eye[2] += bs->cur_ps.viewheight; //get the area the bot is in bs->areanum = BotPointAreaNum(bs->origin); //the real AI BotDeathmatchAI(bs, thinktime); //set the weapon selection every AI frame trap_EA_SelectWeapon(bs->client, bs->weaponnum); //subtract the delta angles for (j = 0; j < 3; j++) { bs->viewangles[j] = AngleMod(bs->viewangles[j] - SHORT2ANGLE(bs->cur_ps.delta_angles[j])); } //everything was ok return qtrue; }
void CGCam_SetAngles( vec3_t ang ) { VectorCopy( ang, client_camera.angles ); VectorCopy(client_camera.angles, cg.refdefViewAngles ); }
void CL_ParseUpdate ( int bits ) { model_t *model; qboolean forcelink; entity_t *ent; int modnum, num, i; if (cls.signon == SIGNONS - 1) { // first update is the final signon stage cls.signon = SIGNONS; CL_SignonReply (); } if (bits & U_MOREBITS) { i = MSG_ReadByte (); bits |= (i<<8); } if (bits & U_LONGENTITY) num = MSG_ReadShort (); else num = MSG_ReadByte (); ent = CL_EntityNum (num); for (i=0 ; i<16 ; i++) if (bits&(1<<i)) bitcounts[i]++; if (ent->msgtime != cl.mtime[1]) forcelink = true; // no previous frame to lerp from else forcelink = false; ent->msgtime = cl.mtime[0]; if (bits & U_MODEL) { modnum = MSG_ReadByte (); if (modnum >= MAX_MODELS) Host_Error ("CL_ParseModel: bad modnum"); } else modnum = ent->baseline.modelindex; model = cl.model_precache[modnum]; if (model != ent->model) { ent->model = model; // automatic animation (torches, etc) can be either all together // or randomized if (model) { if (model->synctype == ST_RAND) ent->syncbase = (float)(rand()&0x7fff) / 0x7fff; else ent->syncbase = 0.0; } else forcelink = true; // hack to make null model players work if (num > 0 && num <= cl.maxclients) R_TranslatePlayerSkin (num - 1); } if (bits & U_FRAME) ent->frame = MSG_ReadByte (); else ent->frame = ent->baseline.frame; if (bits & U_COLORMAP) i = MSG_ReadByte(); else i = ent->baseline.colormap; if (!i) ent->colormap = vid.colormap; else { if (i > cl.maxclients) Sys_Error ("i >= cl.maxclients"); ent->colormap = cl.scores[i-1].translations; } { int skin; if (bits & U_SKIN) skin = MSG_ReadByte(); else skin = ent->baseline.skinnum; if (skin != ent->skinnum) { ent->skinnum = skin; if (num > 0 && num <= cl.maxclients) R_TranslatePlayerSkin (num - 1); } } if (bits & U_EFFECTS) ent->effects = MSG_ReadByte(); else ent->effects = ent->baseline.effects; // shift the known values for interpolation VectorCopy (ent->msg_origins[0], ent->msg_origins[1]); VectorCopy (ent->msg_angles[0], ent->msg_angles[1]); if (bits & U_ORIGIN1) ent->msg_origins[0][0] = MSG_ReadCoord (); else ent->msg_origins[0][0] = ent->baseline.origin[0]; if (bits & U_ANGLE1) ent->msg_angles[0][0] = MSG_ReadAngle(); else ent->msg_angles[0][0] = ent->baseline.angles[0]; if (bits & U_ORIGIN2) ent->msg_origins[0][1] = MSG_ReadCoord (); else ent->msg_origins[0][1] = ent->baseline.origin[1]; if (bits & U_ANGLE2) ent->msg_angles[0][1] = MSG_ReadAngle(); else ent->msg_angles[0][1] = ent->baseline.angles[1]; if (bits & U_ORIGIN3) ent->msg_origins[0][2] = MSG_ReadCoord (); else ent->msg_origins[0][2] = ent->baseline.origin[2]; if (bits & U_ANGLE3) ent->msg_angles[0][2] = MSG_ReadAngle(); else ent->msg_angles[0][2] = ent->baseline.angles[2]; if ( bits & U_NOLERP ) ent->forcelink = true; if ( forcelink ) { // didn't have an update last message VectorCopy (ent->msg_origins[0], ent->msg_origins[1]); VectorCopy (ent->msg_origins[0], ent->origin); VectorCopy (ent->msg_angles[0], ent->msg_angles[1]); VectorCopy (ent->msg_angles[0], ent->angles); ent->forcelink = true; } }
//void CGCam_Track( char *trackName, float speed, float duration ) void CGCam_Track( const char *trackName, float speed, float initLerp ) { gentity_t *trackEnt = NULL; CGCam_TrackDisable(); if(Q_stricmp("none", (char *)trackName) == 0) {//turn off tracking return; } //NOTE: if this interrupts a move before it's done, need to copy the cg.refdef.vieworg to the camera.origin! //This will find a path_corner now, not a misc_camera_track trackEnt = G_Find(NULL, FOFS(targetname), (char *)trackName); if ( !trackEnt ) { gi.Printf(S_COLOR_RED"ERROR: %s camera track target not found\n", trackName); return; } client_camera.info_state |= CAMERA_TRACKING; client_camera.info_state &= ~CAMERA_MOVING; client_camera.trackEntNum = trackEnt->s.number; client_camera.initSpeed = speed/10.0f; client_camera.speed = speed; client_camera.nextTrackEntUpdateTime = cg.time; if ( initLerp ) { client_camera.trackInitLerp = qtrue; } else { client_camera.trackInitLerp = qfalse; } /* if ( client_camera.info_state & CAMERA_FOLLOWING ) {//Used to snap angles? Do what...? } */ //Set a moveDir VectorSubtract( trackEnt->currentOrigin, client_camera.origin, client_camera.moveDir ); if ( !client_camera.trackInitLerp ) {//want to snap to first position //Snap to trackEnt's origin VectorCopy( trackEnt->currentOrigin, client_camera.origin ); //Set new moveDir if trackEnt has a next path_corner //Possible that track has no next point, in which case we won't be moving anyway if ( trackEnt->target && trackEnt->target[0] ) { gentity_t *newTrackEnt = G_Find( NULL, FOFS(targetname), trackEnt->target ); if ( newTrackEnt ) { VectorSubtract( newTrackEnt->currentOrigin, client_camera.origin, client_camera.moveDir ); } } } VectorNormalize( client_camera.moveDir ); }
static bool BotChooseNBGItem( int goalstate, const vec3_t origin, const int* inventory, int travelflags, const bot_goal_t* ltg, float maxtime ) { bot_goalstate_t* gs = BotGoalStateFromHandle( goalstate ); if ( !gs ) { return false; } if ( !gs->itemweightconfig ) { return false; } //get the area the bot is in int areanum = BotReachabilityArea( origin, gs->client ); //if the bot is in solid or if the area the bot is in has no reachability links if ( !areanum || !AAS_AreaReachability( areanum ) ) { //use the last valid area the bot was in areanum = gs->lastreachabilityarea; } //remember the last area with reachabilities the bot was in gs->lastreachabilityarea = areanum; //if still in solid if ( !areanum ) { return false; } int ltg_time; if ( ltg ) { ltg_time = AAS_AreaTravelTimeToGoalArea( areanum, origin, ltg->areanum, travelflags ); } else { ltg_time = 99999; } //the item configuration itemconfig_t* ic = itemconfig; if ( !itemconfig ) { return false; } //best weight and item so far float bestweight = 0; levelitem_t* bestitem = NULL; //go through the items in the level for ( levelitem_t* li = levelitems; li; li = li->next ) { if ( GGameType & GAME_ET ) { if ( g_singleplayer ) { if ( li->flags & IFL_NOTSINGLE ) { continue; } } } else { if ( g_gametype == Q3GT_SINGLE_PLAYER ) { if ( li->flags & IFL_NOTSINGLE ) { continue; } } else if ( g_gametype >= Q3GT_TEAM ) { if ( li->flags & IFL_NOTTEAM ) { continue; } } else { if ( li->flags & IFL_NOTFREE ) { continue; } } } if ( GGameType & GAME_Quake3 && li->flags & IFL_NOTBOT ) { continue; } //if the item is in a possible goal area if ( !li->goalareanum ) { continue; } //FIXME: is this a good thing? added this for items that never spawned into the game (f.i. CTF flags in obelisk) if ( GGameType & GAME_Quake3 && !li->entitynum && !( li->flags & IFL_ROAM ) ) { continue; } //get the fuzzy weight function for this item iteminfo_t* iteminfo = &ic->iteminfo[ li->iteminfo ]; int weightnum = gs->itemweightindex[ iteminfo->number ]; if ( weightnum < 0 ) { continue; } //if this goal is in the avoid goals if ( !( GGameType & GAME_Quake3 ) && BotAvoidGoalTime( goalstate, li->number ) > 0 ) { continue; } float weight = FuzzyWeightUndecided( inventory, gs->itemweightconfig, weightnum ); //HACK: to make dropped items more attractive if ( li->timeout ) { weight += GGameType & GAME_Quake3 ? droppedweight->value : 1000; } //use weight scale for item_botroam if ( GGameType & GAME_Quake3 && li->flags & IFL_ROAM ) { weight *= li->weight; } if ( weight > 0 ) { //get the travel time towards the goal area int t = AAS_AreaTravelTimeToGoalArea( areanum, origin, li->goalareanum, travelflags ); //if the goal is reachable if ( t > 0 && t < maxtime ) { if ( GGameType & GAME_Quake3 ) { //if this item won't respawn before we get there float avoidtime = BotAvoidGoalTime( goalstate, li->number ); if ( avoidtime - t * 0.009 > 0 ) { continue; } } weight /= ( float )t * TRAVELTIME_SCALE; if ( weight > bestweight ) { t = 0; if ( ltg && !li->timeout ) { //get the travel time from the goal to the long term goal t = AAS_AreaTravelTimeToGoalArea( li->goalareanum, li->goalorigin, ltg->areanum, travelflags ); } //if the travel back is possible and doesn't take too long if ( t <= ltg_time ) { bestweight = weight; bestitem = li; } } } } } //if no goal item found if ( !bestitem ) { return false; } //create a bot goal for this item bot_goal_t goal; Com_Memset( &goal, 0, sizeof ( bot_goal_t ) ); iteminfo_t* iteminfo = &ic->iteminfo[ bestitem->iteminfo ]; VectorCopy( bestitem->goalorigin, goal.origin ); VectorCopy( iteminfo->mins, goal.mins ); VectorCopy( iteminfo->maxs, goal.maxs ); goal.areanum = bestitem->goalareanum; goal.entitynum = bestitem->entitynum; goal.number = bestitem->number; goal.flags = GFL_ITEM; if ( GGameType & GAME_Quake3 ) { if ( bestitem->timeout ) { goal.flags |= GFL_DROPPED; } if ( bestitem->flags & IFL_ROAM ) { goal.flags |= GFL_ROAM; } } goal.iteminfo = bestitem->iteminfo; float avoidtime; if ( GGameType & GAME_Quake3 ) { //if it's a dropped item if ( bestitem->timeout ) { avoidtime = AVOID_DROPPED_TIME; } else { avoidtime = iteminfo->respawntime; if ( !avoidtime ) { avoidtime = AVOID_DEFAULT_TIME; } if ( avoidtime < AVOID_MINIMUM_TIME ) { avoidtime = AVOID_MINIMUM_TIME; } } } else { avoidtime = iteminfo->respawntime * 0.5; if ( avoidtime < 10 ) { avoidtime = AVOID_DEFAULT_TIME; } //if it's a dropped item if ( bestitem->timeout ) { avoidtime = AVOID_DROPPED_TIME_WOLF; } } //add the chosen goal to the goals to avoid for a while BotAddToAvoidGoals( gs, bestitem->number, avoidtime ); //push the goal on the stack BotPushGoal( goalstate, &goal, sizeof ( goal ) ); return true; }
void CGCam_FollowUpdate ( void ) { vec3_t center, dir, cameraAngles, vec, focus[MAX_CAMERA_GROUP_SUBJECTS];//No more than 16 subjects in a cameraGroup gentity_t *from = NULL; centity_t *fromCent = NULL; int num_subjects = 0, i; if ( client_camera.cameraGroup && client_camera.cameraGroup[0] ) { //Stay centered in my cameraGroup, if I have one while( NULL != (from = G_Find(from, FOFS(cameraGroup), client_camera.cameraGroup))) { /* if ( from->s.number == client_camera.aimEntNum ) {//This is the misc_camera_focus, we'll be removing this ent altogether eventually continue; } */ if ( num_subjects >= MAX_CAMERA_GROUP_SUBJECTS ) { gi.Printf(S_COLOR_RED"ERROR: Too many subjects in shot composition %s", client_camera.cameraGroup); break; } fromCent = &cg_entities[from->s.number]; if ( !fromCent ) { continue; } if ( from->s.pos.trType == TR_INTERPOLATE ) {//use interpolated origin? VectorCopy(fromCent->lerpOrigin, focus[num_subjects]); } else { VectorCopy(from->currentOrigin, focus[num_subjects]); } //FIXME: make a list here of their s.numbers instead so we can do other stuff with the list below if ( from->client ) {//Track to their eyes - FIXME: maybe go off a tag? //FIXME: //Based on FOV and distance to subject from camera, pick the point that //keeps eyes 3/4 up from bottom of screen... what about bars? focus[num_subjects][2] += from->client->ps.viewheight; } num_subjects++; } if ( !num_subjects ) // Bad cameragroup { gi.Printf(S_COLOR_RED"ERROR: Camera Focus unable to locate cameragroup: %s\n", client_camera.cameraGroup); return; } //Now average all points VectorCopy( focus[0], center ); for( i = 1; i < num_subjects; i++ ) { VectorAdd( focus[i], center, center ); } VectorScale( center, 1.0f/((float)num_subjects), center ); } else { return; } //Need to set a speed to keep a distance from //the subject- fixme: only do this if have a distance //set VectorSubtract( client_camera.subjectPos, center, vec ); client_camera.subjectSpeed = VectorLengthSquared( vec ) * 100.0f / cg.frametime; VectorCopy( center, client_camera.subjectPos ); VectorSubtract( center, cg.refdef.vieworg, dir );//can't use client_camera.origin because it's not updated until the end of the move. //Get desired angle vectoangles(dir, cameraAngles); if ( client_camera.followInitLerp ) {//Lerping for( i = 0; i < 3; i++ ) { cameraAngles[i] = LerpAngle( client_camera.angles[i], cameraAngles[i], cg.frametime/100.0f * client_camera.followSpeed/100.f ); } } else {//Snapping, should do this first time if follow_lerp_to_start_duration is zero //will lerp from this point on client_camera.followInitLerp = qtrue; //So tracker doesn't move right away thinking the first angle change //is the subject moving... FIXME: shouldn't set this until lerp done OR snapped? client_camera.subjectSpeed = 0; } //Point camera to lerp angles VectorCopy( cameraAngles, client_camera.angles ); }
void BotInitLevelItems() { //initialize the map locations and camp spots BotInitInfoEntities(); //initialize the level item heap InitLevelItemHeap(); levelitems = NULL; numlevelitems = 0; itemconfig_t* ic = itemconfig; if ( !ic ) { return; } //if there's no AAS file loaded if ( !AAS_Loaded() ) { return; } //update the modelindexes of the item info for ( int i = 0; i < ic->numiteminfo; i++ ) { if ( !ic->iteminfo[ i ].modelindex ) { Log_Write( "item %s has modelindex 0", ic->iteminfo[ i ].classname ); } } for ( int ent = AAS_NextBSPEntity( 0 ); ent; ent = AAS_NextBSPEntity( ent ) ) { char classname[ MAX_EPAIRKEY ]; if ( !AAS_ValueForBSPEpairKey( ent, "classname", classname, MAX_EPAIRKEY ) ) { continue; } int spawnflags = 0; AAS_IntForBSPEpairKey( ent, "spawnflags", &spawnflags ); int i; for ( i = 0; i < ic->numiteminfo; i++ ) { if ( !String::Cmp( classname, ic->iteminfo[ i ].classname ) ) { break; } } if ( i >= ic->numiteminfo ) { Log_Write( "entity %s unknown item\r\n", classname ); continue; } //get the origin of the item vec3_t origin; if ( !AAS_VectorForBSPEpairKey( ent, "origin", origin ) ) { BotImport_Print( PRT_ERROR, "item %s without origin\n", classname ); continue; } int goalareanum = 0; //if it is a floating item if ( spawnflags & 1 ) { if ( !( GGameType & GAME_Quake3 ) ) { continue; } //if the item is not floating in water if ( !( AAS_PointContents( origin ) & BSP46CONTENTS_WATER ) ) { vec3_t end; VectorCopy( origin, end ); end[ 2 ] -= 32; bsp_trace_t trace = AAS_Trace( origin, ic->iteminfo[ i ].mins, ic->iteminfo[ i ].maxs, end, -1, BSP46CONTENTS_SOLID | BSP46CONTENTS_PLAYERCLIP ); //if the item not near the ground if ( trace.fraction >= 1 ) { //if the item is not reachable from a jumppad goalareanum = AAS_BestReachableFromJumpPadArea( origin, ic->iteminfo[ i ].mins, ic->iteminfo[ i ].maxs ); Log_Write( "item %s reachable from jumppad area %d\r\n", ic->iteminfo[ i ].classname, goalareanum ); if ( !goalareanum ) { continue; } } } } levelitem_t* li = AllocLevelItem(); if ( !li ) { return; } li->number = ++numlevelitems; li->timeout = 0; li->entitynum = 0; li->flags = 0; int value; AAS_IntForBSPEpairKey( ent, "notfree", &value ); if ( value ) { li->flags |= IFL_NOTFREE; } AAS_IntForBSPEpairKey( ent, "notteam", &value ); if ( value ) { li->flags |= IFL_NOTTEAM; } AAS_IntForBSPEpairKey( ent, "notsingle", &value ); if ( value ) { li->flags |= IFL_NOTSINGLE; } if ( GGameType & GAME_Quake3 ) { AAS_IntForBSPEpairKey( ent, "notbot", &value ); if ( value ) { li->flags |= IFL_NOTBOT; } if ( !String::Cmp( classname, "item_botroam" ) ) { li->flags |= IFL_ROAM; AAS_FloatForBSPEpairKey( ent, "weight", &li->weight ); } } //if not a stationary item if ( !( spawnflags & 1 ) ) { if ( !AAS_DropToFloor( origin, ic->iteminfo[ i ].mins, ic->iteminfo[ i ].maxs ) ) { BotImport_Print( PRT_MESSAGE, "%s in solid at (%1.1f %1.1f %1.1f)\n", classname, origin[ 0 ], origin[ 1 ], origin[ 2 ] ); } } //item info of the level item li->iteminfo = i; //origin of the item VectorCopy( origin, li->origin ); if ( goalareanum ) { li->goalareanum = goalareanum; VectorCopy( origin, li->goalorigin ); } else { //get the item goal area and goal origin li->goalareanum = AAS_BestReachableArea( origin, ic->iteminfo[ i ].mins, ic->iteminfo[ i ].maxs, li->goalorigin ); if ( !li->goalareanum ) { BotImport_Print( PRT_MESSAGE, "%s not reachable for bots at (%1.1f %1.1f %1.1f)\n", classname, origin[ 0 ], origin[ 1 ], origin[ 2 ] ); } } AddLevelItemToList( li ); } BotImport_Print( PRT_MESSAGE, "found %d level items\n", numlevelitems ); }
void CGCam_TrackEntUpdate ( void ) {//FIXME: only do every 100 ms gentity_t *trackEnt = NULL; gentity_t *newTrackEnt = NULL; qboolean reached = qfalse; vec3_t vec; float dist; if ( client_camera.trackEntNum >= 0 && client_camera.trackEntNum < ENTITYNUM_WORLD ) {//We're already heading to a path_corner trackEnt = &g_entities[client_camera.trackEntNum]; VectorSubtract( trackEnt->currentOrigin, client_camera.origin, vec ); dist = VectorLengthSquared( vec ); if ( dist < 256 )//16 squared {//FIXME: who should be doing the using here? G_UseTargets( trackEnt, trackEnt ); reached = qtrue; } } if ( trackEnt && reached ) { if ( trackEnt->target && trackEnt->target[0] ) {//Find our next path_corner newTrackEnt = G_Find( NULL, FOFS(targetname), trackEnt->target ); if ( newTrackEnt ) { if ( newTrackEnt->radius < 0 ) {//Don't bother trying to maintain a radius client_camera.distance = 0; client_camera.speed = client_camera.initSpeed; } else if ( newTrackEnt->radius > 0 ) { client_camera.distance = newTrackEnt->radius; } if ( newTrackEnt->speed < 0 ) {//go back to our default speed client_camera.speed = client_camera.initSpeed; } else if ( newTrackEnt->speed > 0 ) { client_camera.speed = newTrackEnt->speed/10.0f; } } } else {//stop thinking if this is the last one CGCam_TrackDisable(); } } if ( newTrackEnt ) {//Update will lerp this client_camera.info_state |= CAMERA_TRACKING; client_camera.trackEntNum = newTrackEnt->s.number; VectorCopy( newTrackEnt->currentOrigin, client_camera.trackToOrg ); } client_camera.nextTrackEntUpdateTime = cg.time + 100; }
/* ============ G_TouchTriggersLerped Find all trigger entities that ent's current position touches. Spectators will only interact with teleporters. This version checks at 6 unit steps between last and current origins ============ */ void G_TouchTriggersLerped( gentity_t *ent ) { int i, num; float dist, curDist = 0; gentity_t *touch[MAX_GENTITIES], *hit; trace_t trace; vec3_t end, mins, maxs, diff; const vec3_t range = { 40, 40, 52 }; qboolean touched[MAX_GENTITIES]; qboolean done = qfalse; if ( !ent->client ) { return; } // dead clients don't activate triggers! if ( ent->client->ps.stats[STAT_HEALTH] <= 0 ) { return; } VectorSubtract( ent->currentOrigin, ent->lastOrigin, diff ); dist = VectorNormalize( diff ); memset (touched, qfalse, sizeof(touched) ); for ( curDist = 0; !done; curDist += (float)ent->maxs[1]/2.0f ) { if ( curDist >= dist ) { VectorCopy( ent->currentOrigin, end ); done = qtrue; } else { VectorMA( ent->lastOrigin, curDist, diff, end ); } VectorSubtract( end, range, mins ); VectorAdd( end, range, maxs ); num = gi.EntitiesInBox( mins, maxs, touch, MAX_GENTITIES ); // can't use ent->absmin, because that has a one unit pad VectorAdd( end, ent->mins, mins ); VectorAdd( end, ent->maxs, maxs ); for ( i=0 ; i<num ; i++ ) { hit = touch[i]; if ( (hit->e_TouchFunc == touchF_NULL) && (ent->e_TouchFunc == touchF_NULL) ) { continue; } if ( !( hit->contents & CONTENTS_TRIGGER ) ) { continue; } if ( touched[i] == qtrue ) { continue;//already touched this move } // use seperate code for determining if an item is picked up // so you don't have to actually contact its bounding box /* if ( hit->s.eType == ET_ITEM ) { if ( !BG_PlayerTouchesItem( &ent->client->ps, &hit->s, level.time ) ) { continue; } } else */ { if ( !gi.EntityContact( mins, maxs, hit ) ) { continue; } } touched[i] = qtrue; memset( &trace, 0, sizeof(trace) ); if ( hit->e_TouchFunc != touchF_NULL ) { GEntity_TouchFunc(hit, ent, &trace); } if ( ( ent->NPC != NULL ) && ( ent->e_TouchFunc != touchF_NULL ) ) { GEntity_TouchFunc( ent, hit, &trace ); } } } }
void CGCam_TrackUpdate ( void ) { vec3_t goalVec, curVec, trackPos, vec; float goalDist, dist; qboolean slowDown = qfalse; if ( client_camera.nextTrackEntUpdateTime <= cg.time ) { CGCam_TrackEntUpdate(); } VectorSubtract( client_camera.trackToOrg, client_camera.origin, goalVec ); goalDist = VectorNormalize( goalVec ); if ( goalDist > 100 ) { goalDist = 100; } else if ( goalDist < 10 ) { goalDist = 10; } if ( client_camera.distance && client_camera.info_state & CAMERA_FOLLOWING ) { float adjust = 0.0f, desiredSpeed = 0.0f; float dot; if ( !client_camera.distanceInitLerp ) { VectorSubtract( client_camera.origin, client_camera.subjectPos, vec ); VectorNormalize( vec ); //FIXME: use client_camera.moveDir here? VectorMA( client_camera.subjectPos, client_camera.distance, vec, client_camera.origin ); //Snap to first time only client_camera.distanceInitLerp = qtrue; return; } else if ( client_camera.subjectSpeed > 0.05f ) {//Don't start moving until subject moves VectorSubtract( client_camera.subjectPos, client_camera.origin, vec ); dist = VectorNormalize(vec); dot = DotProduct(goalVec, vec); if ( dist > client_camera.distance ) {//too far away if ( dot > 0 ) {//Camera is moving toward the subject adjust = (dist - client_camera.distance);//Speed up } else if ( dot < 0 ) {//Camera is moving away from the subject adjust = (dist - client_camera.distance) * -1.0f;//Slow down } } else if ( dist < client_camera.distance ) {//too close if(dot > 0) {//Camera is moving toward the subject adjust = (client_camera.distance - dist) * -1.0f;//Slow down } else if(dot < 0) {//Camera is moving away from the subject adjust = (client_camera.distance - dist);//Speed up } } //Speed of the focus + our error //desiredSpeed = aimCent->gent->speed + (adjust * cg.frametime/100.0f);//cg.frameInterpolation); desiredSpeed = (adjust);// * cg.frametime/100.0f);//cg.frameInterpolation); //self->moveInfo.speed = desiredSpeed; //Don't change speeds faster than 10 every 10th of a second float max_allowed_accel = MAX_ACCEL_PER_FRAME * (cg.frametime/100.0f); if ( !client_camera.subjectSpeed ) {//full stop client_camera.speed = desiredSpeed; } else if ( client_camera.speed - desiredSpeed > max_allowed_accel ) {//new speed much slower, slow down at max accel client_camera.speed -= max_allowed_accel; } else if ( desiredSpeed - client_camera.speed > max_allowed_accel ) {//new speed much faster, speed up at max accel client_camera.speed += max_allowed_accel; } else {//remember this speed client_camera.speed = desiredSpeed; } //Com_Printf("Speed: %4.2f (%4.2f)\n", self->moveInfo.speed, aimCent->gent->speed); } } else { //slowDown = qtrue; } //FIXME: this probably isn't right, round it out more VectorScale( goalVec, cg.frametime/100.0f, goalVec ); VectorScale( client_camera.moveDir, (100.0f - cg.frametime)/100.0f, curVec ); VectorAdd( goalVec, curVec, client_camera.moveDir ); VectorNormalize( client_camera.moveDir ); if(slowDown) { VectorMA( client_camera.origin, client_camera.speed * goalDist/100.0f * cg.frametime/100.0f, client_camera.moveDir, trackPos ); } else { VectorMA( client_camera.origin, client_camera.speed * cg.frametime/100.0f , client_camera.moveDir, trackPos ); } //FIXME: Implement //Need to find point on camera's path that is closest to the desired distance from subject //OR: Need to intelligently pick this desired distance based on framing... VectorCopy( trackPos, client_camera.origin ); }
/* ================== RB_AddFlare This is called at surface tesselation time ================== */ void RB_AddFlare( void *surface, int fogNum, vec3_t point, vec3_t color, vec3_t normal ) { int i; flare_t *f; vec3_t local; float d = 1; vec4_t eye, clip, normalized, window; backEnd.pc.c_flareAdds++; if(normal && (normal[0] || normal[1] || normal[2])) { VectorSubtract( backEnd.viewParms.or.origin, point, local ); VectorNormalizeFast(local); d = DotProduct(local, normal); // If the viewer is behind the flare don't add it. if(d < 0) return; } // if the point is off the screen, don't bother adding it // calculate screen coordinates and depth R_TransformModelToClip( point, backEnd.or.modelMatrix, backEnd.viewParms.projectionMatrix, eye, clip ); // check to see if the point is completely off screen for ( i = 0 ; i < 3 ; i++ ) { if ( clip[i] >= clip[3] || clip[i] <= -clip[3] ) { return; } } R_TransformClipToWindow( clip, &backEnd.viewParms, normalized, window ); if ( window[0] < 0 || window[0] >= backEnd.viewParms.viewportWidth || window[1] < 0 || window[1] >= backEnd.viewParms.viewportHeight ) { return; // shouldn't happen, since we check the clip[] above, except for FP rounding } // see if a flare with a matching surface, scene, and view exists for ( f = r_activeFlares ; f ; f = f->next ) { if ( f->surface == surface && f->frameSceneNum == backEnd.viewParms.frameSceneNum && f->inPortal == backEnd.viewParms.isPortal ) { break; } } // allocate a new one if (!f ) { if ( !r_inactiveFlares ) { // the list is completely full return; } f = r_inactiveFlares; r_inactiveFlares = r_inactiveFlares->next; f->next = r_activeFlares; r_activeFlares = f; f->surface = surface; f->frameSceneNum = backEnd.viewParms.frameSceneNum; f->inPortal = backEnd.viewParms.isPortal; f->addedFrame = -1; } if ( f->addedFrame != backEnd.viewParms.frameCount - 1 ) { f->visible = qfalse; f->fadeTime = backEnd.refdef.time - 2000; } f->addedFrame = backEnd.viewParms.frameCount; f->fogNum = fogNum; VectorCopy(point, f->origin); VectorCopy( color, f->color ); // fade the intensity of the flare down as the // light surface turns away from the viewer VectorScale( f->color, d, f->color ); // save info needed to test f->windowX = backEnd.viewParms.viewportX + window[0]; f->windowY = backEnd.viewParms.viewportY + window[1]; f->eyeZ = eye[2]; }
/* =============== UI_PlayerInfo_SetInfo =============== */ void UI_PlayerInfo_SetInfo( playerInfo_t *pi, int legsAnim, int torsoAnim, vec3_t viewAngles, vec3_t moveAngles, weapon_t weaponNumber, qboolean chat ) { int currentAnim; weapon_t weaponNum; int c; pi->chat = chat; c = (int)trap_Cvar_VariableValue( "color1" ); VectorClear( pi->color1 ); if( c < 1 || c > 7 ) { VectorSet( pi->color1, 1, 1, 1 ); } else { if( c & 1 ) { pi->color1[2] = 1.0f; } if( c & 2 ) { pi->color1[1] = 1.0f; } if( c & 4 ) { pi->color1[0] = 1.0f; } } pi->c1RGBA[0] = 255 * pi->color1[0]; pi->c1RGBA[1] = 255 * pi->color1[1]; pi->c1RGBA[2] = 255 * pi->color1[2]; pi->c1RGBA[3] = 255; // view angles VectorCopy( viewAngles, pi->viewAngles ); // move angles VectorCopy( moveAngles, pi->moveAngles ); if ( pi->newModel ) { pi->newModel = qfalse; jumpHeight = 0; pi->pendingLegsAnim = 0; UI_ForceLegsAnim( pi, legsAnim ); pi->legs.yawAngle = viewAngles[YAW]; pi->legs.yawing = qfalse; pi->pendingTorsoAnim = 0; UI_ForceTorsoAnim( pi, torsoAnim ); pi->torso.yawAngle = viewAngles[YAW]; pi->torso.yawing = qfalse; if ( weaponNumber != WP_NUM_WEAPONS ) { pi->weapon = weaponNumber; pi->currentWeapon = weaponNumber; pi->lastWeapon = weaponNumber; pi->pendingWeapon = WP_NUM_WEAPONS; pi->weaponTimer = 0; UI_PlayerInfo_SetWeapon( pi, pi->weapon ); } return; } // weapon if ( weaponNumber == WP_NUM_WEAPONS ) { pi->pendingWeapon = WP_NUM_WEAPONS; pi->weaponTimer = 0; } else if ( weaponNumber != WP_NONE ) { pi->pendingWeapon = weaponNumber; pi->weaponTimer = dp_realtime + UI_TIMER_WEAPON_DELAY; } weaponNum = pi->lastWeapon; pi->weapon = weaponNum; if ( torsoAnim == BOTH_DEATH1 || legsAnim == BOTH_DEATH1 ) { torsoAnim = legsAnim = BOTH_DEATH1; pi->weapon = pi->currentWeapon = WP_NONE; UI_PlayerInfo_SetWeapon( pi, pi->weapon ); jumpHeight = 0; pi->pendingLegsAnim = 0; UI_ForceLegsAnim( pi, legsAnim ); pi->pendingTorsoAnim = 0; UI_ForceTorsoAnim( pi, torsoAnim ); return; } // leg animation currentAnim = pi->legsAnim & ~ANIM_TOGGLEBIT; if ( legsAnim != LEGS_JUMP && ( currentAnim == LEGS_JUMP || currentAnim == LEGS_LAND ) ) { pi->pendingLegsAnim = legsAnim; } else if ( legsAnim != currentAnim ) { jumpHeight = 0; pi->pendingLegsAnim = 0; UI_ForceLegsAnim( pi, legsAnim ); } // torso animation if ( torsoAnim == TORSO_STAND || torsoAnim == TORSO_STAND2 ) { if ( weaponNum == WP_NONE || weaponNum == WP_GAUNTLET ) { torsoAnim = TORSO_STAND2; } else { torsoAnim = TORSO_STAND; } } if ( torsoAnim == TORSO_ATTACK || torsoAnim == TORSO_ATTACK2 ) { if ( weaponNum == WP_NONE || weaponNum == WP_GAUNTLET ) { torsoAnim = TORSO_ATTACK2; } else { torsoAnim = TORSO_ATTACK; } pi->muzzleFlashTime = dp_realtime + UI_TIMER_MUZZLE_FLASH; //FIXME play firing sound here } currentAnim = pi->torsoAnim & ~ANIM_TOGGLEBIT; if ( weaponNum != pi->currentWeapon || currentAnim == TORSO_RAISE || currentAnim == TORSO_DROP ) { pi->pendingTorsoAnim = torsoAnim; } else if ( ( currentAnim == TORSO_GESTURE || currentAnim == TORSO_ATTACK ) && ( torsoAnim != currentAnim ) ) { pi->pendingTorsoAnim = torsoAnim; } else if ( torsoAnim != currentAnim ) { pi->pendingTorsoAnim = 0; UI_ForceTorsoAnim( pi, torsoAnim ); } }