const char *AIFunc_Heinrich_SwordSideSlash( cast_state_t *cs ) { gentity_t *ent = &g_entities[cs->entityNum]; trace_t *tr; vec3_t right, left; float enemyDist; aicast_predictmove_t move; vec3_t vec; cast_state_t *ecs; cs->aiFlags |= AIFL_SPECIAL_FUNC; if ( cs->enemyNum < 0 ) { if ( ent->client->ps.torsoTimer ) { return NULL; } return AIFunc_DefaultStart( cs ); } ecs = AICast_GetCastState( cs->enemyNum ); if ( ent->client->ps.torsoTimer < 500 ) { if ( !ent->client->ps.legsTimer ) { trap_EA_MoveForward( cs->entityNum ); } ent->client->ps.legsTimer = 0; ent->client->ps.torsoTimer = 0; cs->castScriptStatus.scriptNoMoveTime = 0; AICast_Heinrich_Taunt( cs ); return AIFunc_BattleChaseStart( cs ); } // time for the melee? if ( cs->enemyNum >= 0 && !( cs->aiFlags & AIFL_MISCFLAG1 ) ) { // face them AICast_AimAtEnemy( cs ); // keep checking for impact status tr = CheckMeleeAttack( ent, HEINRICH_SLASH_RANGE, qfalse ); // ready for damage? if ( cs->thinkFuncChangeTime < level.time - HEINRICH_SLASH_DELAY ) { cs->aiFlags |= AIFL_MISCFLAG1; // do melee damage if ( tr && ( tr->entityNum == cs->enemyNum ) ) { AngleVectors( cs->viewangles, NULL, right, NULL ); VectorNegate( right, left ); G_Damage( &g_entities[tr->entityNum], ent, ent, left, tr->endpos, HEINRICH_SLASH_DAMAGE, 0, MOD_GAUNTLET ); // sound G_AddEvent( ent, EV_GENERAL_SOUND, heinrichSoundIndex[HEINRICH_SWORDIMPACT] ); // throw them in direction of impact left[2] = 0.5; VectorMA( g_entities[cs->enemyNum].client->ps.velocity, 400, left, g_entities[cs->enemyNum].client->ps.velocity ); } } } // if they are outside range, move forward AICast_PredictMovement( ecs, 2, 0.3, &move, &g_entities[cs->enemyNum].client->pers.cmd, -1 ); VectorSubtract( move.endpos, cs->bs->origin, vec ); vec[2] = 0; enemyDist = VectorLength( vec ); enemyDist -= g_entities[cs->enemyNum].r.maxs[0]; enemyDist -= ent->r.maxs[0]; if ( enemyDist > 30 ) { // we can get closer if ( ent->client->ps.legsTimer ) { cs->castScriptStatus.scriptNoMoveTime = level.time + 100; ent->client->ps.legsTimer = 0; // allow legs to move us } if ( cs->castScriptStatus.scriptNoMoveTime < level.time ) { trap_EA_MoveForward( cs->entityNum ); } } return NULL; }
char *AIFunc_Heinrich_SwordKnockback(cast_state_t *cs) { gentity_t *ent = &g_entities[cs->entityNum]; trace_t *tr; vec3_t right, left; cs->aiFlags |= AIFL_SPECIAL_FUNC; if (cs->enemyNum < 0) { if (ent->client->ps.torsoTimer) { return NULL; } return AIFunc_DefaultStart(cs); } AICast_GetCastState(cs->enemyNum); if (ent->client->ps.torsoTimer < 500) { if (!ent->client->ps.legsTimer) { trap_EA_MoveForward(cs->entityNum); } ent->client->ps.legsTimer = 0; ent->client->ps.torsoTimer = 0; cs->castScriptStatus.scriptNoMoveTime = 0; AICast_Heinrich_Taunt(cs); return AIFunc_BattleChaseStart(cs); } // time for the melee? if (cs->enemyNum >= 0 && !(cs->aiFlags & AIFL_MISCFLAG1)) { // face them AICast_AimAtEnemy(cs); // keep checking for impact status tr = CheckMeleeAttack(ent, HEINRICH_KNOCKBACK_RANGE, qfalse); /* // do we need to move? if (!(tr && (tr->entityNum == cs->enemyNum))) { ent->client->ps.legsTimer = 0; cs->castScriptStatus.scriptNoMoveTime = 0; trap_EA_MoveForward(cs->entityNum); } */ // ready for damage? if (cs->thinkFuncChangeTime < level.time - HEINRICH_KNOCKBACK_DELAY) { cs->aiFlags |= AIFL_MISCFLAG1; // do melee damage if (tr && (tr->entityNum == cs->enemyNum)) { AngleVectors(cs->viewangles, NULL, right, NULL); VectorNegate(right, left); G_Damage(&g_entities[tr->entityNum], ent, ent, left, tr->endpos, HEINRICH_KNOCKBACK_DAMAGE, 0, MOD_GAUNTLET); // sound G_AddEvent(ent, EV_GENERAL_SOUND, heinrichSoundIndex[HEINRICH_SWORDIMPACT]); // throw them in direction of impact if ((ent->client->ps.torsoAnim & ~ANIM_TOGGLEBIT) == BG_AnimationIndexForString("attack2", cs->entityNum)) { // right right[2] = 0.5; VectorMA(g_entities[cs->enemyNum].client->ps.velocity, 400, right, g_entities[cs->enemyNum].client->ps.velocity); } else { // left left[2] = 0.5; VectorMA(g_entities[cs->enemyNum].client->ps.velocity, 400, left, g_entities[cs->enemyNum].client->ps.velocity); } } } } return NULL; }