/*** GetFMFromFile - Generate a FILEMARKS for marks in a file region * * Purpose: * * Generates a subset of a FILEMARKS structure whose marks fall * within a certain range. Needed by MarkCopy*. * * Input: * pFile - File to get marks from * xLeft, yTop - Start of range * xRight, yBottom - End of range * * Output: * * Returns Pointer to new structure, NULL if there are no marks in range * *************************************************************************/ FILEMARKS * GetFMFromFile ( PFILE pFile, COL xLeft, LINE yTop, COL xRight, LINE yBottom ) { FILEMARKS UNALIGNED * pfm = NULL; REGISTER MARK UNALIGNED * pm; fl flStart; fl flEnd; flagType fInRange = FALSE; if (!fCacheMarks (pFile)) { return NULL; } flStart.lin = yTop; flStart.col = xLeft; flEnd.lin = yBottom; flEnd.col = xRight; for (pm = pfmCache->marks; !TESTFLAG(pm->flags, MF_DUMMY); (char *)pm += pm->cb) { if ((fInRange || flcmp (&flStart, (fl *) &pm->fl) < 1) && (flcmp ((fl *) &pm->fl, &flEnd) < 1)) { fInRange = TRUE; if ((pm->fl.col >= xLeft && pm->fl.col <= xRight)) { UpdMark ( (FILEMARKS **) &pfm, pm->szName, pm->fl.lin - yTop + 1, pm->fl.col - xLeft + 1, (flagType)pm->flags); } } else { break; /* We're out of range again*/ } } return (FILEMARKS *) pfm; }
/*** UpdMark - Add a mark to a FILEMARKS * * Purpose: * * This creates the FILEMARKS structure, adds marks to it and * updates existing marks in it. The caller does not need to * know which of these is going to happen. * * Input: * ppfm - Pointer to a pointer to FILEMARKS. * pszMark - Mark name. * yMark - Mark location (1-based) * xMark * fTemp - TRUE => This marks should not be written to the markfile * * Output: None. *ppfm may be changed * * Notes: * * The first argument is a ** because the * will be updated when a * re-LMAlloc is required. * *************************************************************************/ void UpdMark ( FILEMARKS ** ppfm, char * pszMark, LINE yMark, COL xMark, flagType flags ) { FILEMARKS UNALIGNED * pfm; FILEMARKS UNALIGNED * pfmOld; /* pfm prior to realloc */ REGISTER MARK UNALIGNED * pm; int cbNewMark; fl flMark; flagType fExist = FALSE; assert (ppfm); /* Convert to 0-based */ flMark.lin = yMark-1; flMark.col = xMark-1; cbNewMark = sizeof(MARK) + strlen(pszMark); // If we already have a FILEMARKS structure, // we look for the slot in pfm->marks // where the new mark will go. // if (pfm = *ppfm) { for (pm = pfm->marks; !TESTFLAG(pm->flags, MF_DUMMY); (char *)pm += pm->cb) { if (!_stricmp (pszMark, pm->szName)) { fExist = TRUE; break; } // Check for current mark coming later than // new mark // if (flcmp ((fl *) &pm->fl, &flMark) > 0) { break; } } } else { // New structure. Allocate mem and create // a dummy mark. // pfm = (FILEMARKS *)ZEROMALLOC (sizeof(FILEMARKS)); pfm->cb = sizeof(FILEMARKS); pm = pfm->marks; pm->cb = sizeof(MARK); pm->fl.lin = 0x7FFFFFFF; pm->fl.col = 0x7FFF; pm->szName[0] = '\0'; pm->flags = MF_DUMMY; } // At this point, pfm points to the current FILEMARKS // structure, and pm points into that structure at // the place where the new mark will go, or the existing // mark be updated. // if (!fExist) { pfmOld = pfm; // First, get enough extra space for a new mark, adjusting pm // if a new alloc was required // pfm = (FILEMARKS *)ZEROREALLOC((PVOID)pfm, pfm->cb + cbNewMark); if (pfmOld != pfm) { pm = (MARK *)((char *)pfm + ((char *)pm - (char *)pfmOld)); } // Now pm points to the location in pfm where // our new mark should go. We will move the // original filemarks up to leave space for the // new one. // memmove ((char *)((char *)pm + cbNewMark), (char *)pm, pfm->cb - ((char *)pm - (char *)pfm)); strcpy (pm->szName, pszMark); pm->flags = 0; pm->cb = cbNewMark; pfm->cb += cbNewMark; } if (pfm == pfmCache) { fCacheDirty = TRUE; } pm->flags = flags; pm->fl = flMark; *ppfm = (FILEMARKS *)pfm; }
/*** MarkDelBox - Adjust Marks after a DelBox * * Purpose: * * After deleting a box of text, we must remove any marks that are * defined inside it, then shift left any marks that are to the * right of it. * * Input: * pFile - Affected file * xLeft, yTop - Upper left hand corner of box * xRight, yBottom - Lower right hand corner of box * * Output: None * *************************************************************************/ void MarkDelBox ( PFILE pFile, COL xLeft, LINE yTop, COL xRight, LINE yBottom ) { MARK UNALIGNED * pm; MARK UNALIGNED * pmStart = NULL; MARK UNALIGNED * pmEnd = NULL; fl flUpLeft; fl flLoRight; flagType fAgain; flagType fInBox = FALSE; /* Marks are within box top/bottom */ if (!fCacheMarks (pFile)) { return; } /* yBottom++; WHY? */ flUpLeft.lin = yTop; flUpLeft.col = xLeft; flLoRight.lin = yBottom; flLoRight.col = xRight; for (pm = pfmCache->marks; !TESTFLAG(pm->flags, MF_DUMMY) ; !fAgain && ((char *)pm += pm->cb)) { /* First, look for lowest possible mark */ fAgain = FALSE; if (!fInBox) { if (flcmp (&flUpLeft, (fl *) &pm->fl) < 1) { fAgain = TRUE; fInBox = TRUE; } else { ; } } else if (flcmp ((fl *) &pm->fl, &flLoRight) < 1) { /* Now we're in range. Check ** for being inside the box. */ if (pm->fl.col >= xLeft) { if (pm->fl.col <= xRight) { DelPMark ((MARK *) pm); fAgain = TRUE; } else { /* Mark to the right of box */ pm->fl.col -= xRight - xLeft + 1; } } else { ; } } else { if (pm->fl.lin == yBottom) { pm->fl.col -= xRight - xLeft + 1; } else { break; /* We've gone past the box */ } } } }
/*** MarkDelStream - Adjust Marks after a DelStream * * Purpose: * * After DelStream or DelLines removes a stream (DelLine removes a * "stream" with the beginning and ending points at the left and right * edges of the file), this takes care of updating any remaining * marks. * * Input: * pFile - Affected file * xStart - 0-based starting point * yStart * xEnd - 0-based ending point * yEnd * * Output: None * *************************************************************************/ void MarkDelStream ( PFILE pFile, COL xStart, LINE yStart, COL xEnd, LINE yEnd ) { REGISTER MARK UNALIGNED * pm; MARK UNALIGNED * pmStart = NULL; MARK UNALIGNED * pmEnd = NULL; fl flStart; fl flEnd; flagType fAgain = FALSE; if (!fCacheMarks (pFile)) { return; } /* yEnd++; WHY? */ flStart.lin = yStart; flStart.col = xStart; flEnd.lin = yEnd; flEnd.col = xEnd; for (pm = pfmCache->marks; pmEnd == NULL ; (char *)pm += pm->cb) { // Look for first mark past beginning // of stream. Assume for the moment that // it is inside the stream // if (pmStart == NULL) { if (flcmp (&flStart, (fl *) &pm->fl) < 1) { pmStart = pm; } else { continue; } } // A first mark has been found. We start // looking for the first mark past the end // of the stream. If these are the same, // there are no marks to remove. // if (flcmp (&flEnd, (fl *) &pm->fl) < 1) { // We know that we will end up here // because the last "mark" is higher // than any real mark // if ((pmEnd = pm) != pmStart) // We're here if there were // any marks inside the deleted // stream // memmove ((char *)pmStart, (char *)pmEnd, ((char *)pfmCache + pfmCache->cb) - (char *)pmEnd ); if (pmStart->fl.lin == yEnd) { pmStart->fl.col -= xEnd; } AdjustMarks ((MARK *)pmStart, yStart - (yEnd + 1)); } assert (pm->cb || (TESTFLAG(pm->flags, MF_DUMMY) && pm->fl.lin == 0x7FFFFFFF && pm->fl.col == 0x7FFF)); } }
void NPC_Probe_Pain( gentity_t *self, gentity_t *attacker, int damage ) { float pain_chance; gentity_t *other = attacker; int mod = gPainMOD; VectorCopy( &self->NPC->lastPathAngles, &self->s.angles ); if ( self->health < 30 || mod == MOD_DEMP2 || mod == MOD_DEMP2_ALT ) // demp2 always messes them up real good { vector3 endPos; trace_t trace; VectorSet( &endPos, self->r.currentOrigin.x, self->r.currentOrigin.y, self->r.currentOrigin.z - 128 ); trap->Trace( &trace, &self->r.currentOrigin, NULL, NULL, &endPos, self->s.number, MASK_SOLID, qfalse, 0, 0 ); if ( flcmp( trace.fraction, 1.0f, 0.001f ) || mod == MOD_DEMP2 ) // demp2 always does this { /* if (self->client->clientInfo.headModel != 0) { vector3 origin; VectorCopy(self->r.currentOrigin,origin); origin.z +=50; // G_PlayEffect( "small_chunks", origin ); G_PlayEffect( "chunks/probehead", origin ); G_PlayEffect( "env/med_explode2", origin ); self->client->clientInfo.headModel = 0; self->client->moveType = MT_RUNJUMP; self->client->ps.gravity = g_gravity->value*.1f; } */ if ( (mod == MOD_DEMP2 || mod == MOD_DEMP2_ALT) && other ) { vector3 dir; NPC_SetAnim( self, SETANIM_BOTH, BOTH_PAIN1, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD ); VectorSubtract( &self->r.currentOrigin, &other->r.currentOrigin, &dir ); VectorNormalize( &dir ); VectorMA( &self->client->ps.velocity, 550, &dir, &self->client->ps.velocity ); self->client->ps.velocity.z -= 127; } //self->s.powerups |= ( 1 << PW_SHOCKED ); //self->client->ps.powerups[PW_SHOCKED] = level.time + 3000; self->client->ps.electrifyTime = level.time + 3000; self->NPC->localState = LSTATE_DROP; } } else { pain_chance = NPC_GetPainChance( self, damage ); if ( random() < pain_chance ) // Spin around in pain? { NPC_SetAnim( self, SETANIM_BOTH, BOTH_PAIN1, SETANIM_FLAG_OVERRIDE ); } } NPC_Pain( self, attacker, damage ); }
void NPC_BSSniper_Attack( void ) { //Don't do anything if we're hurt if ( NPC->painDebounceTime > level.time ) { NPC_UpdateAngles( qtrue, qtrue ); return; } //NPC_CheckEnemy( qtrue, qfalse ); //If we don't have an enemy, just idle if ( NPC_CheckEnemyExt( qfalse ) == qfalse )//!NPC->enemy )// { NPC->enemy = NULL; NPC_BSSniper_Patrol();//FIXME: or patrol? return; } if ( TIMER_Done( NPC, "flee" ) && NPC_CheckForDanger( NPC_CheckAlertEvents( qtrue, qtrue, -1, qfalse, AEL_DANGER ) ) ) {//going to run NPC_UpdateAngles( qtrue, qtrue ); return; } if ( !NPC->enemy ) {//WTF? somehow we lost our enemy? NPC_BSSniper_Patrol();//FIXME: or patrol? return; } enemyLOS2 = enemyCS2 = qfalse; move2 = qtrue; faceEnemy2 = qfalse; shoot2 = qfalse; enemyDist2 = DistanceSquared( &NPC->r.currentOrigin, &NPC->enemy->r.currentOrigin ); if ( enemyDist2 < 16384 )//128 squared {//too close, so switch to primary fire if ( NPC->client->ps.weapon == WP_DISRUPTOR ) {//sniping... should be assumed if ( NPCInfo->scriptFlags & SCF_ALT_FIRE ) {//use primary fire trace_t trace; trap->Trace( &trace, &NPC->enemy->r.currentOrigin, &NPC->enemy->r.mins, &NPC->enemy->r.maxs, &NPC->r.currentOrigin, NPC->enemy->s.number, NPC->enemy->clipmask, qfalse, 0, 0 ); if ( !trace.allsolid && !trace.startsolid && (flcmp( trace.fraction, 1.0f, 0.001f ) || trace.entityNum == NPC->s.number) ) {//he can get right to me NPCInfo->scriptFlags &= ~SCF_ALT_FIRE; //reset fire-timing variables NPC_ChangeWeapon( WP_DISRUPTOR ); NPC_UpdateAngles( qtrue, qtrue ); return; } } //FIXME: switch back if he gets far away again? } } else if ( enemyDist2 > 65536 )//256 squared { if ( NPC->client->ps.weapon == WP_DISRUPTOR ) {//sniping... should be assumed if ( !(NPCInfo->scriptFlags&SCF_ALT_FIRE) ) {//use primary fire NPCInfo->scriptFlags |= SCF_ALT_FIRE; //reset fire-timing variables NPC_ChangeWeapon( WP_DISRUPTOR ); NPC_UpdateAngles( qtrue, qtrue ); return; } } } Sniper_UpdateEnemyPos(); //can we see our target? if ( NPC_ClearLOS4( NPC->enemy ) )//|| (NPCInfo->stats.aim >= 5 && gi.inPVS( NPC->client->renderInfo.eyePoint, NPC->enemy->currentOrigin )) ) { float maxShootDist; NPCInfo->enemyLastSeenTime = level.time; VectorCopy( &NPC->enemy->r.currentOrigin, &NPCInfo->enemyLastSeenLocation ); enemyLOS2 = qtrue; maxShootDist = NPC_MaxDistSquaredForWeapon(); if ( enemyDist2 < maxShootDist ) { vector3 fwd, right, up, muzzle, end; trace_t tr; int hit; AngleVectors( &NPC->client->ps.viewangles, &fwd, &right, &up ); CalcMuzzlePoint( NPC, &fwd, &right, &up, &muzzle ); VectorMA( &muzzle, 8192, &fwd, &end ); trap->Trace( &tr, &muzzle, NULL, NULL, &end, NPC->s.number, MASK_SHOT, qfalse, 0, 0 ); hit = tr.entityNum; //can we shoot our target? if ( Sniper_EvaluateShot( hit ) ) { enemyCS2 = qtrue; } } } /* else if ( gi.inPVS( NPC->enemy->currentOrigin, NPC->currentOrigin ) ) { NPCInfo->enemyLastSeenTime = level.time; faceEnemy2 = qtrue; } */ if ( enemyLOS2 ) {//FIXME: no need to face enemy if we're moving to some other goal and he's too far away to shoot? faceEnemy2 = qtrue; } if ( enemyCS2 ) { shoot2 = qtrue; } else if ( level.time - NPCInfo->enemyLastSeenTime > 3000 ) {//Hmm, have to get around this bastard... FIXME: this NPCInfo->enemyLastSeenTime builds up when ducked seems to make them want to run when they uncrouch Sniper_ResolveBlockedShot(); } //Check for movement to take care of Sniper_CheckMoveState(); //See if we should override shooting decision with any special considerations Sniper_CheckFireState(); if ( move2 ) {//move toward goal if ( NPCInfo->goalEntity )//&& ( NPCInfo->goalEntity != NPC->enemy || enemyDist2 > 10000 ) )//100 squared { move2 = Sniper_Move(); } else { move2 = qfalse; } } if ( !move2 ) { if ( !TIMER_Done( NPC, "duck" ) ) { if ( TIMER_Done( NPC, "watch" ) ) {//not while watching ucmd.upmove = -127; } } //FIXME: what about leaning? //FIXME: also, when stop ducking, start looking, if enemy can see me, chance of ducking back down again } else {//stop ducking! TIMER_Set( NPC, "duck", -1 ); } if ( TIMER_Done( NPC, "duck" ) && TIMER_Done( NPC, "watch" ) && (TIMER_Get( NPC, "attackDelay" ) - level.time) > 1000 && NPC->attackDebounceTime < level.time ) { if ( enemyLOS2 && (NPCInfo->scriptFlags&SCF_ALT_FIRE) ) { if ( NPC->fly_sound_debounce_time < level.time ) { NPC->fly_sound_debounce_time = level.time + 2000; } } } if ( !faceEnemy2 ) {//we want to face in the dir we're running if ( move2 ) {//don't run away and shoot NPCInfo->desiredYaw = NPCInfo->lastPathAngles.yaw; NPCInfo->desiredPitch = 0; shoot2 = qfalse; } NPC_UpdateAngles( qtrue, qtrue ); } else// if ( faceEnemy2 ) {//face the enemy Sniper_FaceEnemy(); } if ( NPCInfo->scriptFlags&SCF_DONT_FIRE ) { shoot2 = qfalse; } //FIXME: don't shoot right away! if ( shoot2 ) {//try to shoot if it's time if ( TIMER_Done( NPC, "attackDelay" ) ) { WeaponThink( qtrue ); if ( ucmd.buttons&(BUTTON_ATTACK | BUTTON_ALT_ATTACK) ) { G_SoundOnEnt( NPC, CHAN_WEAPON, "sound/null.wav" ); } //took a shot, now hide if ( !(NPC->spawnflags&SPF_NO_HIDE) && !Q_irand( 0, 1 ) ) { //FIXME: do this if in combat point and combat point has duck-type cover... also handle lean-type cover Sniper_StartHide(); } else { TIMER_Set( NPC, "attackDelay", NPCInfo->shotTime - level.time ); } } } }