Skip to content

Commit

Permalink
Create RegenAuthoritySystem for handling regen
Browse files Browse the repository at this point in the history
  • Loading branch information
e-aakash committed Jun 1, 2019
1 parent 9ada6c2 commit f5ce613
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 68 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
import org.terasology.entitySystem.systems.BaseComponentSystem;
import org.terasology.entitySystem.systems.RegisterMode;
import org.terasology.entitySystem.systems.RegisterSystem;
import org.terasology.entitySystem.systems.UpdateSubscriberSystem;
import org.terasology.logic.characters.CharacterMovementComponent;
import org.terasology.logic.characters.CharacterSoundComponent;
import org.terasology.logic.characters.CharacterSoundSystem;
Expand All @@ -42,14 +41,12 @@
import org.terasology.logic.characters.events.VerticalCollisionEvent;
import org.terasology.logic.health.event.BeforeDamagedEvent;
import org.terasology.logic.health.event.BeforeHealEvent;
import org.terasology.logic.health.event.BeforeRegenEvent;
import org.terasology.logic.health.event.DamageSoundComponent;
import org.terasology.logic.health.event.DoDamageEvent;
import org.terasology.logic.health.event.DoHealEvent;
import org.terasology.logic.health.event.OnDamagedEvent;
import org.terasology.logic.health.event.OnFullyHealedEvent;
import org.terasology.logic.health.event.OnHealedEvent;
import org.terasology.logic.health.event.OnRegenedEvent;
import org.terasology.logic.inventory.ItemComponent;
import org.terasology.logic.players.event.OnPlayerRespawnedEvent;
import org.terasology.math.TeraMath;
Expand All @@ -62,12 +59,6 @@
* This system takes care of healing of entities with HealthComponent.
* To increase the health of an entity, send DoHealEvent
*
* Logic flow for Regen:
* - BeforeRegenEvent
* - (Health regenerated, HealthComponent saved)
* - OnRegenedEvent
* - OnFullyHealedEvent (if healed to full health)
*
* Logic flow for healing:
* - DoHealEvent
* - BeforeHealEvent
Expand All @@ -87,7 +78,7 @@
*
*/
@RegisterSystem(RegisterMode.AUTHORITY)
public class HealthAuthoritySystem extends BaseComponentSystem implements UpdateSubscriberSystem {
public class HealthAuthoritySystem extends BaseComponentSystem {

private static final Logger logger = LoggerFactory.getLogger(HealthAuthoritySystem.class);

Expand All @@ -99,64 +90,6 @@ public class HealthAuthoritySystem extends BaseComponentSystem implements Update

private Random random = new FastRandom();

@Override
public void update(float delta) {
for (EntityRef entity : entityManager.getEntitiesWith(HealthComponent.class)) {
HealthComponent health = entity.getComponent(HealthComponent.class);
if (health.currentHealth <= 0) {
continue;
}

if (health.currentHealth == health.maxHealth || health.regenRate == 0) {
continue;
}

int healAmount = 0;
healAmount = regenerateHealthAmount(health, healAmount);

checkRegenerated(entity, health, healAmount);
}
}

private int regenerateHealthAmount(HealthComponent health, int healAmount) {
int newHeal = healAmount;
while (time.getGameTimeInMs() >= health.nextRegenTick) {
newHeal++;
health.nextRegenTick = health.nextRegenTick + (long) (1000 / health.regenRate);
}
return newHeal;
}

private void checkRegenerated(EntityRef entity, HealthComponent health, int healAmount) {
if (healAmount > 0) {
BeforeRegenEvent beforeRegen = entity.send(new BeforeRegenEvent(healAmount, entity));
if (!beforeRegen.isConsumed()) {
int modifiedAmount = TeraMath.floorToInt(beforeRegen.getResultValue());
if (modifiedAmount > 0) {
doRegenerate(entity, modifiedAmount, entity);
} else if (modifiedAmount < 0) {
doDamage(entity, -modifiedAmount, EngineDamageTypes.HEALING.get(), entity, EntityRef.NULL);
}
}
entity.saveComponent(health);
}
}

private void doRegenerate(EntityRef entity, int healAmount, EntityRef instigator) {
HealthComponent health = entity.getComponent(HealthComponent.class);
if (health != null) {
int cappedHealth = Math.min(health.currentHealth + healAmount, health.maxHealth);
int cappedHealAmount = cappedHealth - health.currentHealth;
health.currentHealth = cappedHealth;
entity.saveComponent(health);
entity.send(new OnRegenedEvent(cappedHealAmount, entity));
if (health.currentHealth == health.maxHealth) {
entity.send(new OnFullyHealedEvent(instigator));
}
}
}


private void checkHeal(EntityRef entity, int healAmount, EntityRef instigator) {
BeforeHealEvent beforeHeal = entity.send(new BeforeHealEvent(healAmount, instigator));
if (!beforeHeal.isConsumed()) {
Expand Down
127 changes: 127 additions & 0 deletions src/main/java/org/terasology/logic/health/RegenAuthoritySystem.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/*
* Copyright 2019 MovingBlocks
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.terasology.logic.health;

import org.terasology.engine.Time;
import org.terasology.entitySystem.entity.EntityManager;
import org.terasology.entitySystem.entity.EntityRef;
import org.terasology.entitySystem.systems.BaseComponentSystem;
import org.terasology.entitySystem.systems.RegisterMode;
import org.terasology.entitySystem.systems.RegisterSystem;
import org.terasology.entitySystem.systems.UpdateSubscriberSystem;
import org.terasology.logic.health.event.BeforeRegenEvent;
import org.terasology.logic.health.event.OnFullyHealedEvent;
import org.terasology.logic.health.event.OnRegenedEvent;
import org.terasology.math.TeraMath;
import org.terasology.registry.In;

/**
* This system handles the natural regeneration of entities with HealthComponent.
*
* Logic flow for Regen:
* - BeforeRegenEvent
* - (Health regenerated, HealthComponent saved)
* - OnRegenedEvent
* - OnFullyHealedEvent (if healed to full health)
*/
@RegisterSystem(RegisterMode.AUTHORITY)
public class RegenAuthoritySystem extends BaseComponentSystem implements UpdateSubscriberSystem {
/** Integer storing when to check each effect. */
private static final int CHECK_INTERVAL = 100;

/** Integer storing when to apply regen health */
private static final int REGENERATION_TICK = 1000;

/** Last time the list of regen effects were checked. */
private long lastUpdated;

@In
private Time time;
@In
private EntityManager entityManager;

/**
* For every update, check to see if the time's been over the CHECK_INTERVAL. If so, verify if a REGENERATION_TICK
* has passed for every regeneration effect.
*
* @param delta The time (in seconds) since the last engine update.
*/
@Override
public void update(float delta) {
final long currentTime = time.getGameTimeInMs();

// If the current time passes the CHECK_INTERVAL threshold, regenerate.
if (currentTime >= lastUpdated + CHECK_INTERVAL) {
// Set the lastUpdated time to be the currentTime.
lastUpdated = currentTime;

// For every entity with the health component, ignore if it is dead or maxHealth is reached
// check to see if they have passed a REGENERATION_TICK. If so, regenerate the applicable
// entities with the given regenAmount.
for (EntityRef entity : entityManager.getEntitiesWith(HealthComponent.class)) {
HealthComponent component = entity.getComponent(HealthComponent.class);

if (component.currentHealth <= 0) {
continue;
}

if (component.currentHealth == component.maxHealth || component.regenRate == 0) {
continue;
}

long lastRegenTick = component.nextRegenTick - REGENERATION_TICK;
if (currentTime >= lastRegenTick + REGENERATION_TICK) {
// Calculate this multiplier to account for time delays.
int multiplier = (int) (currentTime - lastRegenTick) / REGENERATION_TICK;

component.nextRegenTick = currentTime + REGENERATION_TICK;

int amount = TeraMath.floorToInt(component.regenRate * multiplier);
checkRegenerated(entity, component, amount);
}
}
}
}

private void checkRegenerated(EntityRef entity, HealthComponent health, int healAmount) {
if (healAmount > 0) {
BeforeRegenEvent beforeRegen = entity.send(new BeforeRegenEvent(healAmount, entity));
if (!beforeRegen.isConsumed()) {
int modifiedAmount = TeraMath.floorToInt(beforeRegen.getResultValue());
if (modifiedAmount > 0) {
doRegenerate(entity, modifiedAmount, entity);
}
}
entity.saveComponent(health);
}
}

private void doRegenerate(EntityRef entity, int healAmount, EntityRef instigator) {
HealthComponent health = entity.getComponent(HealthComponent.class);
if (health != null) {
int cappedHealth = Math.min(health.currentHealth + healAmount, health.maxHealth);
int cappedHealAmount = cappedHealth - health.currentHealth;
health.currentHealth = cappedHealth;
entity.saveComponent(health);
entity.send(new OnRegenedEvent(cappedHealAmount, entity));
if (health.currentHealth == health.maxHealth) {
entity.send(new OnFullyHealedEvent(instigator));
}
}
}

}

0 comments on commit f5ce613

Please sign in to comment.