Lab 7: Virus Robot

Objective

For lab 7, you will create an robot that wanders around the map and infects other entities (that are not virus robots themselves). You will need to understand the basics of entity navigation and the navigation system. You will also need an understanding of handling time with System.currentTimeMillis().

Notes

To Register a New Task With a Specific Priority

tasks.addTask (priority, task)

To Get The Current System Time (in Milliseconds)

long milliseconds = System.currentTimeMillis()

Getting an Entity's Current Attack Target

Entity entity = ...
Entity target = entity.getAttackTarget();

If the entity has no current attack target, it will return null.

Available Entity Properties

You will use the following entity properties throughout your code.

boolean entity.isDead;         // True if the entity is dead
double  entity.posX;           // X position of entity
double  entity.posY;           // Y position of entity
double  entity.posZ;           // Z position of entity
float   entity.rotationPitch;  // Entity pitch (rotation up/down)
float   entity.rotationYaw;    // Entity heading (direction)
World   entity.worldObj;       // Entity's world

To Make a Robot Chase Another Entity "target"

Use the following call:

robot.getNavigator().tryMoveToEntityLiving(target, speed);

For speed, use one of:

  • Robot.SPEED_FAST
  • Robot.SPEED_NORMAL
  • Robot.SPEED_SLOW

To Determine the Distance Between Two Entities

float distanceInBlocks = entity1.getDistanceToEntity(entity2);

Setting an Entity's Position and Orientation

public void entity.setLocationAndAngles (
  double posX, double posY, double posZ, float yaw, float pitch);

Spawning a New Entity in The World

someExistingEntity.worldObj.spawnEntityInWorld(newEntity)

Setting an Entity's State to Dead

public void entity.setDead();

To Spawn a Robot in Game While Playing

Tasks

Part 1 — Create a virus robot that wanders around the world: VirusRobot

  1. Begin by creating a class called VirusRobot that extends the Robot class. Implement a constructor that takes a net.minecraft.world.World variable as a parameter, and call the super constructor with this world parameter.
  2. Inside the new constructor, add the EntityAIWander task with priority 1. When you create the EntityAIWander task, pass in SPEED_FAST.
  3. Inside your EntitiesModule class, register the VirusRobot as you did for the leafbot (lab 6). Use the "red_robot" texture, and name the instance "virusbot".

Part 2 — Create a task to infect other entities: EntityAIInfect

  1. In the entities folder, create a new class called EntityAIInfect. This class extends net.minecraft.entity.ai.EntityAIBase. You will probably find it helpful to refer to the EntityAIConvertLeaves.java file that you wrote for lab 6, since the basic code structure is similar.
  2. Create an EntityAIInfect constructor that takes a VirusRobot instance. As you did for the AIConvertLeaves task, this constructor will just store the entity passed in the constructor in a private field. Call it 'virusbot'.
  3. Create a private EntityAIInfect field of type EntityLivingBase called target. We will use this field to store the current target entity that the robot will try to infect.
  4. The EntityAIInfect class must implement the following methods:
    • boolean shouldExecute()
    • void startExecuting()
    • boolean continueExecuting()
    • void updateTask()
  5. public boolean shouldExecute() — The shouldExecute() method returns true if the virus robot has a current attack target. See the notes above on getting the current attack target.
  6. public void startExecuting() — This method is called if shouldExecute() returned true, so we know we have a current attack target. All you need to do in this method is store the attack target in our private field. Note that you never have to worry about checking to see if the target entity is another VirusRobot, since entities do not attack their own kind.
  7. public boolean continueExecuting() — This method is called after one execution of the updateTask() method. It must return false when the task has completed or should otherwise stop. For this task (chasing after another entity to infect), there are two conditions which should stop it:
    • there is no current target, or
    • the target is dead.

    See the notes above for determining the current target and determining whether an entity is dead.

  8. public void updateTask() — this method implements the core behavior of the EntityAIInfect task. In broad terms, it moves (or tries to move) the virus robot closer to the target entity. If the target is close enough, it infects the entity and converts it to a new VirusRobot.

    This task should be implemented in the following steps. You will be using a lot of the information outlined in the notes above, so if you're stuck, the answer's probably there.

    1. First, you need to ensure that the target is not dead. If the target is dead, then do nothing and skip the remaining steps.
    2. Chase after the target with a fast speed.
    3. If the virus robot is more two blocks or further away from the target, then there's nothing else to do this iteration, so skip the remaining steps.
    4. At this point, we've determined that the target is alive and within infection range. Now it's time to create a new virus robot to replace the target entity. To do this, create a new VirusRobot. The constructor takes a World object, so just pass along this robot's world. You can get an entity's world object from its public worldObj field.
    5. Set the new virus robot at the same location as the target. Set the new yaw and pitch angles to zero.

      Note: The one catch is that you much place the new VirusRobot one position above the target's position (that is, Y + 1), or it will fall below the world.

    6. Spawn the new entity in the world.
    7. Set the target entity's state to dead.
  9. In the VirusRobot class, register the EntityAIInfect task with priority 2.

Part 3 — Implement VirusRobot Expiration

If we let virus robots continue, they'll soon infect the entire world. In order to balance things out, let's give them a limited lifetime to infect other entities.

  1. In the VirusRobot class, implement a new onUpdate() method and call super.onUpdate() as the first statement. This method will be called every world tick.
  2. As you saw in the notes above, you can use System.currentTimeMillis() to query the current time. Let's use that to calculate an expiration time for each virus robot. Create a class constant (public static final long) called lifetime and set it to 20 seconds (in milliseconds).
  3. Now create a public long value named expirationTime. In the virus robot constructor, set it to the expiration time of the robot, using the current time and the lifetime values (both in milliseconds).
  4. Now, in the VirusRobot.onUpdate() method, check to see if the current time is past the robot's expiration time. If so, expire the robot by giving it damage equal to its total health, like so:
    damageEntity(new DamageSource("Died from old age"), getHealth());
  5. Retry the game, and make sure that virus robots expire after 20 seconds.

Part 4 (Optional) — Implment VirusRobot Rejuvenation

Update VirusRobot with rejuvenation powers. After infecting another entity, reset VirusRobot's expiration time. How would you design the code to do this? HINT: The expiration timer reset method should be called from two places in the code.