Skip to content

Commit

Permalink
Rework monster decision code #109: cleanup & refactoring
Browse files Browse the repository at this point in the history
move enemy knowledge variables to `.monsterinfo` structure from Game object into the Entity
  • Loading branch information
demoth committed Jan 20, 2024
1 parent ad8993c commit 2535e0b
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 45 deletions.
33 changes: 14 additions & 19 deletions game/src/main/java/jake2/game/GameAI.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ private static boolean FacingIdeal(SubgameEntity self) {
* Turn and close until within an angle to launch a melee attack.
*/
public static void ai_run_melee(SubgameEntity self, GameExportsImpl gameExports) {
self.ideal_yaw = gameExports.enemy_yaw;
self.ideal_yaw = self.monsterinfo.enemyYaw;
M.rotateToIdealYaw(self);

if (FacingIdeal(self)) {
Expand All @@ -60,7 +60,7 @@ public static void ai_run_melee(SubgameEntity self, GameExportsImpl gameExports)
* Turn in place until within an angle to launch a missile attack.
*/
public static void ai_run_missile(SubgameEntity self, GameExportsImpl gameExports) {
self.ideal_yaw = gameExports.enemy_yaw;
self.ideal_yaw = self.monsterinfo.enemyYaw;
M.rotateToIdealYaw(self);

if (FacingIdeal(self)) {
Expand All @@ -75,7 +75,7 @@ public static void ai_run_missile(SubgameEntity self, GameExportsImpl gameExport
*/
public static void ai_run_slide(SubgameEntity self, float distance, GameExportsImpl gameExports) {

self.ideal_yaw = gameExports.enemy_yaw;
self.ideal_yaw = self.monsterinfo.enemyYaw;
M.rotateToIdealYaw(self);

final float angle;
Expand Down Expand Up @@ -114,9 +114,7 @@ public static void ai_run_slide(SubgameEntity self, float distance, GameExportsI
*
* walkmove(angle, speed) primitive is all or nothing
*/
public static boolean ai_checkattack(SubgameEntity self, float dist, GameExportsImpl gameExports) {

boolean hesDeadJim;
public static boolean ai_checkattack(SubgameEntity self, GameExportsImpl gameExports) {

// this causes monsters to run blindly to the combat point w/o firing
if (self.goalentity != null) {
Expand All @@ -140,10 +138,10 @@ public static boolean ai_checkattack(SubgameEntity self, float dist, GameExports
}
}

gameExports.enemy_vis = false;
self.monsterinfo.enemyVisible = false;

// see if the enemy is dead
hesDeadJim = false;
boolean hesDeadJim = false;
if ((null == self.enemy) || (!self.enemy.inuse)) {
hesDeadJim = true;
} else if ((self.monsterinfo.aiflags & GameDefines.AI_MEDIC) != 0) {
Expand Down Expand Up @@ -188,20 +186,17 @@ public static boolean ai_checkattack(SubgameEntity self, float dist, GameExports

// gather knowledge of enemy
// todo: put (into a structure and keep) in the monsterinfo
gameExports.enemy_vis = GameUtil.visible(self, self.enemy, gameExports);
if (gameExports.enemy_vis) {
self.monsterinfo.enemyVisible = GameUtil.visible(self, self.enemy, gameExports);
if (self.monsterinfo.enemyVisible) {
self.monsterinfo.search_time = gameExports.level.time + 5;
Math3D.VectorCopy(self.enemy.s.origin,
self.monsterinfo.last_sighting);
}

gameExports.enemy_infront = GameUtil.infront(self, self.enemy);
gameExports.enemy_range = GameUtil.range(self, self.enemy);
self.monsterinfo.enemyRange = GameUtil.range(self, self.enemy);
float[] temp = {0, 0, 0};
Math3D.VectorSubtract(self.enemy.s.origin, self.s.origin, temp);
gameExports.enemy_yaw = Math3D.vectoyaw(temp);

// JDC self.ideal_yaw = enemy_yaw;
self.monsterinfo.enemyYaw = Math3D.vectoyaw(temp);

if (self.monsterinfo.attack_state == GameDefines.AS_MISSILE) {
ai_run_missile(self, gameExports);
Expand All @@ -213,7 +208,7 @@ public static boolean ai_checkattack(SubgameEntity self, float dist, GameExports
}

// if enemy is not currently visible, we will never attack
if (!gameExports.enemy_vis)
if (!self.monsterinfo.enemyVisible)
return false;

return self.monsterinfo.checkattack.think(self, gameExports);
Expand Down Expand Up @@ -439,7 +434,7 @@ public void ai(SubgameEntity self, float dist, GameExportsImpl gameExports) {
self.monsterinfo.run.think(self, gameExports);
}
M.rotateToIdealYaw(self);
ai_checkattack(self, 0, gameExports);
ai_checkattack(self, gameExports);
} else
GameUtil.FindTarget(self, gameExports);
return;
Expand Down Expand Up @@ -520,15 +515,15 @@ public void ai(SubgameEntity self, float dist, GameExportsImpl gameExports) {

}

if (ai_checkattack(self, dist, gameExports))
if (ai_checkattack(self, gameExports))
return;

if (self.monsterinfo.attack_state == GameDefines.AS_SLIDING) {
ai_run_slide(self, dist, gameExports);
return;
}

if (gameExports.enemy_vis) {
if (self.monsterinfo.enemyVisible) {
//if (self.aiflags & AI_LOST_SIGHT)
// dprint("regained sight\n");
M.M_MoveToGoal(self, dist, gameExports);
Expand Down
11 changes: 0 additions & 11 deletions game/src/main/java/jake2/game/GameExportsImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -116,17 +116,6 @@ public class GameExportsImpl implements GameExports {
// todo: remove and use result of gi.BoxEdicts
SubgameEntity[] touch = new SubgameEntity[Defines.MAX_EDICTS];

// Monster knowledge about the enemy
// todo: move to separate class
@Deprecated
boolean enemy_vis;
@Deprecated
boolean enemy_infront;
@Deprecated
int enemy_range;
@Deprecated
float enemy_yaw;

// Game Items related
public List<GameItem> items;
// todo: move to appropriate places
Expand Down
26 changes: 13 additions & 13 deletions game/src/main/java/jake2/game/GameUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,7 @@ public boolean think(SubgameEntity self, GameExportsImpl gameExports) {
float[] spot1 = { 0, 0, 0 };

float[] spot2 = { 0, 0, 0 };
float chance;
float rangedAttackChance;
trace_t tr;

if (self.enemy.health > 0) {
Expand All @@ -508,7 +508,7 @@ public boolean think(SubgameEntity self, GameExportsImpl gameExports) {
}

// melee attack
if (gameExports.enemy_range == GameDefines.RANGE_MELEE) {
if (self.monsterinfo.enemyRange == GameDefines.RANGE_MELEE) {
// don't always melee in easy mode
if (gameExports.gameCvars.skill.value == 0 && (Lib.rand() & 3) != 0)
return false;
Expand All @@ -526,28 +526,28 @@ public boolean think(SubgameEntity self, GameExportsImpl gameExports) {
if (gameExports.level.time < self.monsterinfo.attack_finished)
return false;

if (gameExports.enemy_range == GameDefines.RANGE_FAR)
if (self.monsterinfo.enemyRange == GameDefines.RANGE_FAR)
return false;

if ((self.monsterinfo.aiflags & GameDefines.AI_STAND_GROUND) != 0) {
chance = 0.4f;
} else if (gameExports.enemy_range == GameDefines.RANGE_MELEE) {
chance = 0.2f;
} else if (gameExports.enemy_range == GameDefines.RANGE_NEAR) {
chance = 0.1f;
} else if (gameExports.enemy_range == GameDefines.RANGE_MID) {
chance = 0.02f;
rangedAttackChance = 0.4f;
} else if (self.monsterinfo.enemyRange == GameDefines.RANGE_MELEE) {
rangedAttackChance = 0.2f;
} else if (self.monsterinfo.enemyRange == GameDefines.RANGE_NEAR) {
rangedAttackChance = 0.1f;
} else if (self.monsterinfo.enemyRange == GameDefines.RANGE_MID) {
rangedAttackChance = 0.02f;
} else {
// chance = 0f
return false;
}

if (gameExports.gameCvars.skill.value == 0)
chance *= 0.5;
rangedAttackChance *= 0.5f;
else if (gameExports.gameCvars.skill.value >= 2)
chance *= 2;
rangedAttackChance *= 2;

if (Lib.random() < chance) {
if (Lib.random() < rangedAttackChance) {
self.monsterinfo.attack_state = GameDefines.AS_MISSILE;
self.monsterinfo.attack_finished = gameExports.level.time + 2 * Lib.random();
return true;
Expand Down
5 changes: 4 additions & 1 deletion game/src/main/java/jake2/game/monsters/monsterinfo_t.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ of the License, or (at your option) any later version.
import jake2.game.adapters.EntInteractAdapter;
import jake2.game.adapters.EntThinkAdapter;
import jake2.game.adapters.SuperAdapter;
import jake2.game.monsters.mmove_t;
import jake2.qcommon.filesystem.QuakeFile;

import java.io.IOException;
Expand Down Expand Up @@ -71,6 +70,10 @@ public class monsterinfo_t {
public int power_armor_type;
public int power_armor_power;

public boolean enemyVisible = false;
public int enemyRange = 0;
public float enemyYaw = 0f;

/** Writes the monsterinfo to the file.*/
public void write(QuakeFile f) throws IOException
{
Expand Down
2 changes: 1 addition & 1 deletion game/src/main/kotlin/jake2/game/character/GameCharacter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ class GameCharacter(
// even though called every frame, it doesn't do anything if already firing
self.character.attackRanged(Random.nextInt(15) + 10)
}
EnforcerActions.SLIDE -> ai_run_slide(self, 15f, game) // fixme: relies on game.enemy_yaw
EnforcerActions.SLIDE -> ai_run_slide(self, 15f, game)
EnforcerActions.ATTACK_MELEE -> self.character.attackMelee()
EnforcerActions.WALK -> self.character.walk()
EnforcerActions.CHASE -> self.character.run()
Expand Down

0 comments on commit 2535e0b

Please sign in to comment.