Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Alteration effects and Impulse based weapons support #43

Open
wants to merge 6 commits into
base: master
from
@@ -7,7 +7,8 @@
"dependencies" : [
{"id" : "Core", "minVersion" : "2.0.0"},
{"id" : "StructureTemplates", "minVersion" : "0.3.0"},
{"id" : "Sensors", "minVersion" : "0.1.0"}
{"id" : "Sensors", "minVersion" : "0.1.0"},
{"id" : "AlterationEffects", "minVersion" : "1.0.1"}
],
"serverSideOnly" : false,
"isGameplay" : "true",
@@ -1,3 +1,18 @@
/*
* 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.combatSystem.hurting;

import org.terasology.entitySystem.Component;
@@ -9,7 +24,7 @@
* Damaging critically means multiplying the original damage by <b>critFactor</b>.
* The critical damage has <b>critChance</b>/100 probability of occurring.
*/
public class CritDamageComponent implements Component{
public class CritDamageComponent implements Component {

This comment has been minimized.

Copy link
@skaldarnar

skaldarnar Aug 21, 2019

Note to self: figure out why CritDamageComponent has an int value do denote a percentage 🤔


@Replicate
public int critChance = 10; // in percentage out of 100
@@ -1,28 +1,55 @@
/*
* 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.combatSystem.hurting;

import org.terasology.entitySystem.entity.EntityRef;
import org.terasology.entitySystem.event.AbstractConsumableEvent;
import org.terasology.math.geom.Vector3f;

/**
* Used to hurt the <b>target</b> entity by the amount specified in {@code HurtingComponent}
*/
public class HurtEvent extends AbstractConsumableEvent{
public class HurtEvent extends AbstractConsumableEvent {

/**
* the target entity which is to be hurt.
*/
EntityRef target = EntityRef.NULL;

public HurtEvent(){
private EntityRef target = EntityRef.NULL;

private Vector3f impulseDirection = new Vector3f();

This comment has been minimized.

Copy link
@skaldarnar

skaldarnar Aug 21, 2019

If the impulseDirection cannot be changed for this event you can make it final:

Suggested change
private Vector3f impulseDirection = new Vector3f();
final private Vector3f impulseDirection;

This comment has been minimized.

Copy link
@skaldarnar

skaldarnar Aug 21, 2019

The member then needs to be initialized in the constructor(s).


public HurtEvent() {

This comment has been minimized.

Copy link
@skaldarnar

skaldarnar Aug 21, 2019

Is this constructor needed? What is a HurtEvent without a target or direction?


}
public HurtEvent(EntityRef entity){

public HurtEvent(EntityRef entity) {
this.target = entity;
}

public HurtEvent(EntityRef entity, Vector3f impulseDirection) {
this.target = entity;
this.impulseDirection = impulseDirection;
}

public EntityRef getTarget(){
public EntityRef getTarget() {
return target;
}

public Vector3f getImpulseDirection() {
return impulseDirection;
}

}
@@ -1,3 +1,18 @@
/*
* 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.combatSystem.hurting;

import org.terasology.entitySystem.Component;
@@ -10,17 +25,22 @@
* <p>
* {@link HurtEvent} is used to hurt other entity/entities.
*/
public class HurtingComponent implements Component{
public class HurtingComponent implements Component {
/**
* The amount of damage the entity will inflict.
*/
@Replicate
public int amount = 3;

This comment has been minimized.

Copy link
@iaronaraujo

iaronaraujo Aug 18, 2019

Contributor

magic number

This comment has been minimized.

Copy link
@skaldarnar

skaldarnar Aug 21, 2019

It's a magic number, yes, but what would be a better solution here?

If this is a default value it should be mentioned in the doc comment. Maybe there's a more sensible default value such as 0 which is kind of neutral?

@iaronaraujo Do you think the default values are important to know outside this component?



@Replicate
public long duration = 2000;

This comment has been minimized.

Copy link
@iaronaraujo

iaronaraujo Aug 18, 2019

Contributor

magic number


/**
* The type of damage.
*/
@Replicate
public Prefab damageType = EngineDamageTypes.DIRECT.get();

@Replicate
public String hurtingType = "damage";
}
@@ -1,44 +1,92 @@
/*
* 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.combatSystem.hurting;

import java.util.Random;

import org.terasology.alterationEffects.damageOverTime.DamageOverTimeAlterationEffect;
import org.terasology.alterationEffects.speed.StunAlterationEffect;
import org.terasology.combatSystem.weaponFeatures.OwnerSpecific;
import org.terasology.context.Context;
import org.terasology.entitySystem.entity.EntityRef;
import org.terasology.entitySystem.event.EventPriority;
import org.terasology.entitySystem.event.ReceiveEvent;
import org.terasology.entitySystem.systems.BaseComponentSystem;
import org.terasology.entitySystem.systems.RegisterSystem;
import org.terasology.logic.characters.CharacterComponent;
import org.terasology.logic.characters.CharacterImpulseEvent;
import org.terasology.logic.health.event.DoDamageEvent;
import org.terasology.logic.health.HealthComponent;
import org.terasology.logic.notifications.NotificationMessageEvent;
import org.terasology.registry.In;

/**
* This system handles all the tasks related to hurting an entity in <b>CombatSystem</b> module.
*/
@RegisterSystem
public class HurtingHandlingSystem extends BaseComponentSystem {

@In
private Context context;

/**
* This event handler handles the hurting of target entity by the amount and damage types
* given in {@link HurtingComponent}.
*
* @param event
* @param entity
*/
@ReceiveEvent(components = HurtingComponent.class, priority = EventPriority.PRIORITY_TRIVIAL)
public void hurting(HurtEvent event, EntityRef entity) {
HurtingComponent hurting = entity.getComponent(HurtingComponent.class);
@ReceiveEvent(priority = EventPriority.PRIORITY_TRIVIAL)
public void hurting(HurtEvent event, EntityRef entity, HurtingComponent hurtingComponent) {

EntityRef otherEntity = event.getTarget();
if (otherEntity == null || otherEntity == EntityRef.NULL) {
return;
}

if (otherEntity.hasComponent(HealthComponent.class)) {
EntityRef instigator = OwnerSpecific.getUltimateOwner(entity);

otherEntity.send(new DoDamageEvent(hurting.amount, hurting.damageType, instigator, entity));
otherEntity.send(new NotificationMessageEvent(new String(hurting.amount + " damage dealt.."), entity));
EntityRef instigator = OwnerSpecific.getUltimateOwner(entity);

switch (hurtingComponent.hurtingType) {
case "attract":
if (otherEntity.hasComponent(CharacterComponent.class)) {
otherEntity.send(new CharacterImpulseEvent(event.getImpulseDirection().negate().mul(hurtingComponent.amount)));
}
break;
case "repulse":
if (otherEntity.hasComponent(CharacterComponent.class)) {
otherEntity.send(new CharacterImpulseEvent(event.getImpulseDirection().mul(hurtingComponent.amount)));
}
break;
case "stun":
if (otherEntity.hasComponent(CharacterComponent.class)) {
StunAlterationEffect stunAlterationEffect = new StunAlterationEffect(context);
stunAlterationEffect.applyEffect(instigator, otherEntity, hurtingComponent.amount, hurtingComponent.duration);
}
break;
case "dot":
if (otherEntity.hasComponent(CharacterComponent.class)) {
DamageOverTimeAlterationEffect dotAlterationEffect = new DamageOverTimeAlterationEffect(context);
dotAlterationEffect.applyEffect(instigator, otherEntity, hurtingComponent.amount, hurtingComponent.duration);
}
break;
default:

This comment has been minimized.

Copy link
@skaldarnar

skaldarnar Aug 21, 2019

This treats everything else than the previously matched cases as "damage" type - is that intended? Keep in mind that the hurtingType is an arbitrary string, thus it may contain full garbage such as "watermelon" - should that be treated as damage or do we want to ignore that case (and just log a warning)?

if (otherEntity.hasComponent(HealthComponent.class)) {
otherEntity.send(new DoDamageEvent(hurtingComponent.amount, hurtingComponent.damageType, instigator, entity));
otherEntity.send(new NotificationMessageEvent(new String(hurtingComponent.amount + " damage dealt.."), entity));
}
}
}

@@ -1,3 +1,18 @@
/*
* 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.combatSystem.hurting;

import org.terasology.entitySystem.Component;
@@ -6,7 +21,7 @@
/**
* To generate a random damage amount between <b>minDamage</b> and <b>maxDamage</b> (both inclusive).
*/
public class RandomDamageComponent implements Component{
public class RandomDamageComponent implements Component {
//inclusive
@Replicate
public int minDamage = 2;
@@ -1,7 +1,23 @@
/*
* 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.combatSystem.weaponFeatures.components;

import org.terasology.entitySystem.Component;
import org.terasology.entitySystem.prefab.Prefab;
import org.terasology.math.geom.Vector3f;
import org.terasology.network.Replicate;

/**
@@ -10,7 +26,9 @@
* the other entity may be defined in <b>explosionPrefab</b> or <b>explosionEntity</b>.
* <b>explosionEntity</b> is given precedence over <b>explosionPrefab</b> if both are present.
*/
public class ExplodeComponent implements Component{
public class ExplodeComponent implements Component {
@Replicate
public Prefab explosionPrefab;
@Replicate
public Vector3f impulseDirection;

This comment has been minimized.

Copy link
@skaldarnar

skaldarnar Aug 21, 2019

Does the ExplodeComponent really need an impulseDirection? Or can it be derived from the location and the fact that it is an explosion?

}
@@ -1,7 +1,22 @@
/*
* 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.combatSystem.weaponFeatures.events;

import org.terasology.entitySystem.event.Event;

public class ExplodeEvent implements Event{
public class ExplodeEvent implements Event {

}
@@ -5,6 +5,7 @@
import org.terasology.combatSystem.weaponFeatures.OwnerSpecific;
import org.terasology.combatSystem.weaponFeatures.components.ArrowComponent;
import org.terasology.combatSystem.weaponFeatures.components.AttackerComponent;
import org.terasology.combatSystem.weaponFeatures.components.ExplodeComponent;
import org.terasology.combatSystem.weaponFeatures.components.LaunchEntityComponent;
import org.terasology.combatSystem.weaponFeatures.events.LaunchEntityEvent;
import org.terasology.combatSystem.weaponFeatures.events.PrimaryAttackEvent;
@@ -158,8 +159,14 @@ private void launchEntity(Vector3f direction, EntityRef entity){
// applies impulse to the entity
Vector3f impulse = finalDir;
impulse.normalize();

if (entityToLaunch.hasComponent(ExplodeComponent.class)) {
ExplodeComponent explodeComponent = entityToLaunch.getComponent(ExplodeComponent.class);
explodeComponent.impulseDirection = impulse;
entityToLaunch.saveComponent(explodeComponent);
}

impulse.mul(launchEntity.impulse);

entityToLaunch.send(new CombatImpulseEvent(impulse));
entity.send(new ReduceAmmoEvent());
}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.