コード例 #1
0
char *AIFunc_LoperAttack2Start( cast_state_t *cs ) {
	gentity_t *ent;
	vec3_t vec, avec;
	//
	ent = &g_entities[cs->entityNum];
	//
	if ( cs->enemyNum < 0 ) {
		return AIFunc_DefaultStart( cs );
	}
	// face them
	AICast_AimAtEnemy( cs );
	// if not facing them yet, wait
	VectorSubtract( g_entities[cs->enemyNum].client->ps.origin, cs->bs->origin, vec );
	VectorNormalize( vec );
	AngleVectors( cs->viewangles, avec, NULL, NULL );
	if ( DotProduct( vec, avec ) < 0.9 ) {
		//cs->aifunc = AIFunc_LoperAttack2Start;
		return NULL;
	}
	// OK, start the animation
	BG_PlayAnimName( &ent->client->ps, "legs_extra3", ANIM_BP_LEGS, qtrue, qfalse, qtrue );
	ent->client->ps.legsTimer = 500;    // stay on this until landing
	// send us hurtling towards our enemy
	VectorScale( vec, LOPER_LEAP_VELOCITY_START, vec );
	vec[2] = LOPER_LEAP_VELOCITY_Z;
	VectorCopy( vec, ent->client->ps.velocity );
	VectorCopy( vec, cs->loperLeapVel );
	//
	cs->aiFlags &= ~AIFL_LAND_ANIM_PLAYED;
	// play the sound
	// TODO
	//
	cs->aifunc = AIFunc_LoperAttack2;
	return "AIFunc_LoperAttack2";
}
コード例 #2
0
char *AIFunc_Heinrich_MeleeStart(cast_state_t *cs) {
	gentity_t *ent = &g_entities[cs->entityNum];
	gentity_t *enemy = &g_entities[cs->enemyNum];
	int rnd;
	static int lastStomp;

	if (cs->enemyNum < 0) {
		return NULL;
	}
	// record weapon fire
	cs->weaponFireTimes[cs->weaponNum] = level.time;
	// face them
	AICast_AimAtEnemy(cs);
	// clear flags
	cs->aiFlags &= ~(AIFL_MISCFLAG1|AIFL_MISCFLAG2);
	// decide which attack to use
	if (VectorDistance(ent->r.currentOrigin, enemy->r.currentOrigin) < 60) {
		rnd = 0;   // sword slash up close
	} else if (VectorDistance(ent->r.currentOrigin, enemy->r.currentOrigin) >= HEINRICH_SLASH_RANGE) {
		rnd = 1;   // too far away, stomp
	} else {
		// pick at random
		rnd = rand() % 2;
	}

	switch (rnd) {
	case 0:
	{
		int rnd = rand() % 3;

		switch (rnd) {
		case 0:
			return AIFunc_Heinrich_SwordSideSlashStart(cs);
		case 1:
			return AIFunc_Heinrich_SwordKnockbackStart(cs);
		case 2:
			return AIFunc_Heinrich_SwordLungeStart(cs);
		}
	}

	case 1:
		// dont do stomp too often
		if (lastStomp > level.time - 12000) { // plenty of time to let debris disappear
			return NULL;
		}

		lastStomp = level.time;
		cs->aiFlags |= AIFL_SPECIAL_FUNC;
		// sound
		G_AddEvent(ent, EV_GENERAL_SOUND, heinrichSoundIndex[HEINRICH_EARTHQUAKE_START]);
		// play the anim
		BG_PlayAnimName(&ent->client->ps, "attack7", ANIM_BP_BOTH, qtrue, qfalse, qtrue);
		// start the func
		cs->aifunc = AIFunc_Heinrich_Earthquake;
		return "AIFunc_Heinrich_Earthquake";
	}
	// shutup compiler
	return NULL;
}
コード例 #3
0
char *AIFunc_LoperAttack1Start( cast_state_t *cs ) {
	gentity_t *ent;
	//
	ent = &g_entities[cs->entityNum];
	// face them
	AICast_AimAtEnemy( cs );
	// start the animation
	if ( rand() % 2 ) {
		G_AddEvent( ent, EV_GENERAL_SOUND, G_SoundIndex( aiDefaults[ent->aiCharacter].soundScripts[FOLLOWSOUNDSCRIPT] ) );
		BG_PlayAnimName( &ent->client->ps, "legs_extra", ANIM_BP_LEGS, qtrue, qfalse, qtrue );
	} else {
		G_AddEvent( ent, EV_GENERAL_SOUND, G_SoundIndex( aiDefaults[ent->aiCharacter].soundScripts[STAYSOUNDSCRIPT] ) );
		BG_PlayAnimName( &ent->client->ps, "legs_extra2", ANIM_BP_LEGS, qtrue, qfalse, qtrue );
	}
	//
	cs->aifunc = AIFunc_LoperAttack1;
	return "AIFunc_LoperAttack1";
}
コード例 #4
0
const char *AIFunc_Heinrich_SwordKnockbackStart( cast_state_t *cs ) {
	gentity_t *ent = &g_entities[cs->entityNum];
//	gentity_t	*enemy = &g_entities[cs->enemyNum];

	cs->aiFlags |= AIFL_SPECIAL_FUNC;
	// sound
	G_AddEvent( ent, EV_GENERAL_SOUND, heinrichSoundIndex[HEINRICH_SWORDKNOCKBACK_START] );
	// weapon sound
	G_AddEvent( ent, EV_GENERAL_SOUND, heinrichSoundIndex[HEINRICH_SWORDKNOCKBACK_WEAPON] );
	// face them
	AICast_AimAtEnemy( cs );
	// clear flags
	cs->aiFlags &= ~( AIFL_MISCFLAG1 | AIFL_MISCFLAG2 );
	// play the anim
	if ( rand() % 2 ) {
		BG_PlayAnimName( &ent->client->ps, "attack2", ANIM_BP_BOTH, qtrue, qfalse, qtrue );
	} else {
		BG_PlayAnimName( &ent->client->ps, "attack3", ANIM_BP_BOTH, qtrue, qfalse, qtrue );
	}
	// start the func
	cs->aifunc = AIFunc_Heinrich_SwordKnockback;
	return "AIFunc_Heinrich_SwordKnockback";
}
コード例 #5
0
char *AIFunc_BlackGuardAttack1Start( cast_state_t *cs ) {
	gentity_t   *ent = &g_entities[cs->entityNum];
	//
	cs->weaponFireTimes[cs->weaponNum] = level.time;
	// face them
	AICast_AimAtEnemy( cs );
	// audible sound
	AIChar_AttackSound( cs );
	// start the animation
	BG_PlayAnimName( &ent->client->ps, "kick", ANIM_BP_BOTH, qtrue, qfalse, qtrue );
	// clear flags
	cs->aiFlags &= ~( AIFL_MISCFLAG1 | AIFL_MISCFLAG2 );
	//
	cs->aifunc = AIFunc_BlackGuardAttack1;
	return "AIFunc_BlackGuardAttack1";
}
コード例 #6
0
char *AIFunc_LoperAttack3Start( cast_state_t *cs ) {
	gentity_t *ent;
	//
	ent = &g_entities[cs->entityNum];
	//
	// face them
	AICast_AimAtEnemy( cs );
	// play the animation
	BG_PlayAnimName( &ent->client->ps, "legs_extra5", ANIM_BP_LEGS, qtrue, qfalse, qtrue );
	//
	// play the buildup sound
	// TODO
	//
	cs->aifunc = AIFunc_LoperAttack3;
	return "AIFunc_LoperAttack3";
}
コード例 #7
0
const char *AIFunc_Heinrich_SwordLungeStart( cast_state_t *cs ) {
	gentity_t *ent = &g_entities[cs->entityNum];
//	gentity_t	*enemy = &g_entities[cs->enemyNum];

	cs->aiFlags |= AIFL_SPECIAL_FUNC;
	// sound
	G_AddEvent( ent, EV_GENERAL_SOUND, heinrichSoundIndex[HEINRICH_SWORDLUNGE_START] );
	// face them
	AICast_AimAtEnemy( cs );
	// clear flags
	cs->aiFlags &= ~( AIFL_MISCFLAG1 | AIFL_MISCFLAG2 );
	// play the anim
	BG_PlayAnimName( &ent->client->ps, "attack9", ANIM_BP_BOTH, qtrue, qfalse, qtrue );
	// start the func
	cs->aifunc = AIFunc_Heinrich_SwordLunge;
	return "AIFunc_Heinrich_SwordLunge";
}
コード例 #8
0
char *AIFunc_ZombieFlameAttackStart( cast_state_t *cs ) {
	gentity_t *ent;
	//
	ent = &g_entities[cs->entityNum];
	ent->s.otherEntityNum2 = cs->bs->enemy;
	ent->s.effect3Time = level.time;
	//
	// dont turn
	cs->bs->ideal_viewangles[YAW] = cs->bs->viewangles[YAW];
	cs->bs->ideal_viewangles[PITCH] = -45;  // look upwards
	// start the flame
	ent->s.onFireStart = level.time;
	ent->s.onFireEnd = level.time + ZOMBIE_FLAME_DURATION;
	//
	// set the correct animation
	BG_PlayAnimName( &ent->client->ps, "both_attack1", ANIM_BP_BOTH, qtrue, qfalse, qtrue );
	//
	cs->aifunc = AIFunc_ZombieFlameAttack;
	return "AIFunc_ZombieFlameAttack";
}
コード例 #9
0
const char *AIFunc_Heinrich_SpawnSpiritsStart( cast_state_t *cs ) {
	gentity_t   *ent = &g_entities[cs->entityNum];
	gentity_t *trav, *spirits;
	float circleDist;
	//
	// enable all the spirit spawners
	trav = NULL;
	// TTimo: gcc: suggest () around assignment used as truth value
	while ( ( trav = G_Find( trav, FOFS( classname ), "func_bats" ) ) ) {
		if ( !trav->active && trav->spawnflags & 4 ) {
			trav->active = 1;   // let them release spirits now
		}
	}
	// is the player outside the circle?
	trav = NULL;
	// TTimo: gcc: suggest () around assignment used as truth value
	while ( ( trav = G_Find( trav, FOFS( classname ), "func_bats" ) ) ) {
		if ( trav->spawnflags & 4 ) {
			spirits = trav;
			circleDist = trav->radius;
			trav = G_Find( NULL, FOFS( targetname ), trav->target );
			if ( trav ) {
				if ( VectorDistance( g_entities[0].s.pos.trBase, trav->s.origin ) > circleDist ) {
					cs->aiFlags &= ~AIFL_MISCFLAG1;
					ent->count2 = 0;
					cs->aiFlags |= AIFL_SPECIAL_FUNC;
					// start the animation
					BG_PlayAnimName( &ent->client->ps, "attack4", ANIM_BP_BOTH, qtrue, qfalse, qtrue );
					// play the sound
					G_AddEvent( ent, EV_GENERAL_SOUND, heinrichSoundIndex[HEINRICH_RAISEDEAD_START] );
					// start the func
					cs->aifunc = AIFunc_Heinrich_RaiseDead; // just do raise dead, without raising any warriors
					return "AIFunc_Heinrich_RaiseDead";
				}
			}
			break;
		}
	}
	//
	return NULL;
}
コード例 #10
0
const char *AIFunc_Heinrich_RaiseDeadStart( cast_state_t *cs ) {
	int i, cnt, free;
	gentity_t   *ent = &g_entities[cs->entityNum];
//	gentity_t	*enemy = &g_entities[cs->enemyNum];
	gentity_t *trav, *spirits;
	float circleDist;
	//
	// count the number of active warriors
	cnt = 0;
	free = 0;
	for ( i = 0, trav = g_entities; i < level.maxclients; i++, trav++ ) {
		if ( !trav->inuse ) {
			continue;
		}
		if ( trav->aiCharacter != AICHAR_WARZOMBIE ) {
			continue;
		}
		if ( trav->aiInactive ) {
			free++;
			continue;
		}
		if ( trav->health <= 0 ) {
			continue;
		}
		cnt++;
	}
	//
	if ( cnt < HEINRICH_RAISEDEAD_COUNT && free ) {   // need a new one
		cs->aiFlags &= ~AIFL_MISCFLAG1;
		ent->count2 = HEINRICH_RAISEDEAD_COUNT - cnt;
		lastRaise = level.time;
		cs->aiFlags |= AIFL_SPECIAL_FUNC;
		// start the animation
		BG_PlayAnimName( &ent->client->ps, "attack4", ANIM_BP_BOTH, qtrue, qfalse, qtrue );
		// play the sound
		G_AddEvent( ent, EV_GENERAL_SOUND, heinrichSoundIndex[HEINRICH_RAISEDEAD_START] );
		// start the func
		cs->aifunc = AIFunc_Heinrich_RaiseDead;
		return "AIFunc_Heinrich_RaiseDead";
	}
	// enable all the spirit spawners
	trav = NULL;
	// TTimo: gcc: suggest () around assignment used as truth value
	while ( ( trav = G_Find( trav, FOFS( classname ), "func_bats" ) ) ) {
		if ( !trav->active && trav->spawnflags & 4 ) {
			trav->active = 1;   // let them release spirits now
		}
	}
	// is the player outside the circle?
	trav = NULL;
	// TTimo: gcc: suggest () around assignment used as truth value
	while ( ( trav = G_Find( trav, FOFS( classname ), "func_bats" ) ) ) {
		if ( trav->spawnflags & 4 ) {
			spirits = trav;
			circleDist = trav->radius;
			trav = G_Find( NULL, FOFS( targetname ), trav->target );
			if ( trav ) {
				if ( VectorDistance( g_entities[0].s.pos.trBase, trav->s.origin ) > circleDist ) {
					cs->aiFlags &= ~AIFL_MISCFLAG1;
					ent->count2 = 0;
					cs->aiFlags |= AIFL_SPECIAL_FUNC;
					// start the animation
					BG_PlayAnimName( &ent->client->ps, "attack4", ANIM_BP_BOTH, qtrue, qfalse, qtrue );
					// play the sound
					G_AddEvent( ent, EV_GENERAL_SOUND, heinrichSoundIndex[HEINRICH_RAISEDEAD_START] );
					// start the func
					cs->aifunc = AIFunc_Heinrich_RaiseDead;
					return "AIFunc_Heinrich_RaiseDead";
				}
			}
			break;
		}
	}
	//
	return NULL;
}
コード例 #11
0
/*
===============
AIFunc_LoperAttack2()

  Loper's leaping long range attack
===============
*/
char *AIFunc_LoperAttack2( cast_state_t *cs ) {
	gentity_t *ent;
	vec3_t vec;
	qboolean onGround = qfalse;
	//
	ent = &g_entities[cs->entityNum];
	//
	// are we waiting to inflict damage?
	if ( ( cs->enemyNum >= 0 ) && ( cs->weaponFireTimes[WP_MONSTER_ATTACK2] < level.time - 50 ) &&
		 ( cs->bs->cur_ps.groundEntityNum == ENTITYNUM_NONE ) ) {
		// ready to inflict damage?
		if ( cs->thinkFuncChangeTime < level.time - LOPER_LEAP_DELAY ) {
			// check for damage
			if ( VectorDistance( cs->bs->origin, g_entities[cs->enemyNum].client->ps.origin ) < LOPER_LEAP_RANGE ) {
				// draw the client-side lightning effect
				ent->client->ps.eFlags |= EF_MONSTER_EFFECT;
				// do the damage
				G_Damage( &g_entities[cs->enemyNum], ent, ent, vec3_origin, cs->bs->origin, LOPER_LEAP_DAMAGE, 0, MOD_LOPER_LEAP );
				G_Sound( &g_entities[cs->entityNum], level.loperZapSound );
				cs->weaponFireTimes[WP_MONSTER_ATTACK2] = level.time;
			}
		}
	}
	//
	// landed?
	if ( cs->bs->cur_ps.groundEntityNum != ENTITYNUM_NONE ) {
		onGround = qtrue;
	} else {    // predict a landing
		aicast_predictmove_t move;
		float changeTime;
		AICast_PredictMovement( cs, 1, 0.2, &move, &cs->lastucmd, cs->enemyNum );
		if ( move.groundEntityNum != ENTITYNUM_NONE ) {
			onGround = qtrue;
		}
		//
		// adjust velocity
		VectorCopy( cs->loperLeapVel, vec );
		vec[2] = 0;
		VectorNormalize( vec );
		changeTime = 2.0 * ( 0.001 * ( level.time - cs->thinkFuncChangeTime ) );
		if ( changeTime > 1.0 ) {
			changeTime = 1.0;
		}
		VectorScale( vec, LOPER_LEAP_VELOCITY_START + changeTime * ( LOPER_LEAP_VELOCITY_END - LOPER_LEAP_VELOCITY_START ), vec );
		g_entities[cs->entityNum].s.pos.trDelta[0] = vec[0];
		g_entities[cs->entityNum].s.pos.trDelta[1] = vec[1];
	}
	//
	if ( onGround || ( cs->aiFlags & AIFL_LAND_ANIM_PLAYED ) ) {
		// if we just started the attack recently, we probably haven't had a chance to get airborne yet
		if ( cs->thinkFuncChangeTime < level.time - LOPER_LEAP_DELAY ) {
			// loper is back on ground, wait for animation to play out
			if ( !( cs->aiFlags & AIFL_LAND_ANIM_PLAYED ) ) {
				BG_PlayAnimName( &ent->client->ps, "legs_extra4", ANIM_BP_LEGS, qtrue, qfalse, qtrue );
				//
				cs->aiFlags |= AIFL_LAND_ANIM_PLAYED;
				// TODO:play the landing thud
			}
			//
			if ( ent->client->ps.legsTimer < 800 ) {  // we're done
				ent->client->ps.legsTimer = 0;
				return AIFunc_DefaultStart( cs );
			}
			// keep moving slightly in our facing direction to simulate landing momentum
			AngleVectors( cs->viewangles, vec, NULL, NULL );
			trap_EA_Move( cs->entityNum, vec, ( (float)ent->client->ps.legsTimer / (float)LOPER_LAND_DURATION ) * (float)LOPER_LEAP_LAND_MOMENTUM );
			return NULL;
		}
	}
	ent->client->ps.legsTimer = 500;    // stay on this until landing
	return NULL;
}