Added a reason parameter to onDisable.

Added new behavior.
Using DamageSources now.
This commit is contained in:
Florian Nücke 2015-09-18 14:47:29 +02:00
parent 155bf0702c
commit aef4165da5
14 changed files with 123 additions and 22 deletions

View File

@ -12,7 +12,7 @@ import li.cil.oc.api.detail.*;
*/
public class API {
public static final String ID_OWNER = "OpenComputers|Core";
public static final String VERSION = "5.5.6";
public static final String VERSION = "5.6.0";
public static DriverAPI driver = null;
public static FileSystemAPI fileSystem = null;

View File

@ -40,8 +40,10 @@ public interface Behavior {
* Called when this behavior becomes inactive.
* <p/>
* Use this to remove permanent effects.
*
* @param reason the reason the behavior is being disabled.
*/
void onDisable();
void onDisable(DisableReason reason);
/**
* Called each tick while this behavior is active.

View File

@ -0,0 +1,23 @@
package li.cil.oc.api.nanomachines;
/**
* Enum with reasons why a nanomachine behavior was disabled.
* <p/>
* This allows some more context specific behavior in a more stable fashion.
*/
public enum DisableReason {
/**
* This covers things like players logging off or the controller being reset.
*/
Default,
/**
* Input state changed, leading to a behavior being disabled.
*/
InputChanged,
/**
* System has run out of energy and is powering down.
*/
OutOfEnergy
}

View File

@ -1,6 +1,7 @@
package li.cil.oc.api.prefab;
import li.cil.oc.api.nanomachines.Behavior;
import li.cil.oc.api.nanomachines.DisableReason;
import net.minecraft.entity.player.EntityPlayer;
/**
@ -42,7 +43,7 @@ public abstract class AbstractBehavior implements Behavior {
}
@Override
public void onDisable() {
public void onDisable(DisableReason reason) {
}
@Override

View File

@ -1036,7 +1036,6 @@ opencomputers {
"potion.fireResistance",
"potion.waterBreathing",
"potion.nightVision",
"potion.healthBoost",
"potion.absorption",
"potion.blindness",
@ -1049,6 +1048,14 @@ opencomputers {
"potion.weakness",
"potion.wither"
]
# How much damage the hungry behavior should deal to the player when the
# nanomachine controller runs out of energy.
hungryDamage: 5
# How much energy the hungry behavior should restore when damaging the
# player.
hungryEnergyRestored: 50
}
# 3D printer related stuff.

View File

@ -451,6 +451,15 @@ achievement.oc.transistor.desc=Create a Transistor to get started. Then listen t
achievement.oc.wirelessNetworkCard=Signals
achievement.oc.wirelessNetworkCard.desc=Time to go where no packet has gone before.
# Death messages. Note that the number of entries here must match the number
# set in the actual damage source in code.
death.attack.oc.nanomachinesOverload.1=%s got too greedy.
death.attack.oc.nanomachinesOverload.2=%s had a nervous breakdown.
death.attack.oc.nanomachinesOverload.3=%s's nanomachines went out of control.
death.attack.oc.nanomachinesHungry.1=%s was eaten by nanomachines.
death.attack.oc.nanomachinesHungry.2=%s didn't keep their nanomachines fed.
death.attack.oc.nanomachinesHungry.3=%s has been digested.
# NEI Integration
nei.options.inventory.oredict=Show OreDictionary names
nei.options.inventory.oredict.true=True

View File

@ -360,6 +360,8 @@ class Settings(val config: Config) {
val nanomachineDisintegrationRange = config.getInt("nanomachines.disintegrationRange") max 0
val nanomachinePotionBlacklist = config.getAnyRefList("nanomachines.potionBlacklist")
val nanomachinePotionWhitelist = config.getAnyRefList("nanomachines.potionWhitelist")
val nanomachinesHungryDamage = config.getDouble("nanomachines.hungryDamage").toFloat max 0
val nanomachinesHungryEnergyRestored = config.getDouble("nanomachines.hungryEnergyRestored") max 0
// ----------------------------------------------------------------------- //
// printer

View File

@ -9,8 +9,10 @@ import li.cil.oc.Settings
import li.cil.oc.api
import li.cil.oc.api.nanomachines.Behavior
import li.cil.oc.api.nanomachines.Controller
import li.cil.oc.api.nanomachines.DisableReason
import li.cil.oc.api.network.Packet
import li.cil.oc.api.network.WirelessEndpoint
import li.cil.oc.integration.util.DamageSourceWithRandomCause
import li.cil.oc.server.PacketSender
import li.cil.oc.util.BlockPosition
import li.cil.oc.util.ExtendedNBT._
@ -32,6 +34,10 @@ class ControllerImpl(val player: EntityPlayer) extends Controller with WirelessE
final val MaxSenderDistance = 2f
final val FullSyncInterval = 20 * 60
final val OverloadDamage = new DamageSourceWithRandomCause("oc.nanomachinesOverload", 3).
setDamageBypassesArmor().
setDamageIsAbsolute()
var uuid = UUID.randomUUID.toString
var responsePort = 0
var storedEnergy = Settings.get.bufferNanomachines * 0.25
@ -154,7 +160,7 @@ class ControllerImpl(val player: EntityPlayer) extends Controller with WirelessE
}
override def getActiveBehaviors: lang.Iterable[Behavior] = configuration.synchronized {
cleanActiveBehaviors()
cleanActiveBehaviors(DisableReason.InputChanged)
activeBehaviors
}
@ -192,12 +198,15 @@ class ControllerImpl(val player: EntityPlayer) extends Controller with WirelessE
return
}
val hasPower = getLocalBuffer > 0 || Settings.get.ignorePower
var hasPower = getLocalBuffer > 0 || Settings.get.ignorePower
lazy val active = getActiveBehaviors.toIterable // Wrap once.
lazy val activeInputs = configuration.triggers.count(_.isActive)
if (hasPower != hadPower) {
if (!hasPower) active.foreach(_.onDisable())
if (!hasPower) {
active.foreach(_.onDisable(DisableReason.OutOfEnergy)) // This may change our energy buffer.
hasPower = getLocalBuffer > 0 || Settings.get.ignorePower
}
else active.foreach(_.onEnable())
}
@ -212,8 +221,7 @@ class ControllerImpl(val player: EntityPlayer) extends Controller with WirelessE
val overload = activeInputs - getSafeInputCount
if (!player.capabilities.isCreativeMode && overload > 0 && player.getEntityWorld.getTotalWorldTime % 20 == 0) {
player.setHealth(player.getHealth - overload)
player.performHurtAnimation()
player.attackEntityFrom(OverloadDamage, overload)
}
}
@ -249,7 +257,7 @@ class ControllerImpl(val player: EntityPlayer) extends Controller with WirelessE
configuration.triggers(index).isActive = false
activeBehaviorsDirty = true
}
cleanActiveBehaviors()
cleanActiveBehaviors(DisableReason.Default)
}
}
@ -283,7 +291,7 @@ class ControllerImpl(val player: EntityPlayer) extends Controller with WirelessE
private def isServer = !isClient
private def cleanActiveBehaviors(): Unit = {
private def cleanActiveBehaviors(reason: DisableReason): Unit = {
if (activeBehaviorsDirty) {
configuration.synchronized(if (activeBehaviorsDirty) {
val newBehaviors = configuration.behaviors.filter(_.isActive).map(_.behavior)
@ -293,7 +301,7 @@ class ControllerImpl(val player: EntityPlayer) extends Controller with WirelessE
activeBehaviors ++= newBehaviors
activeBehaviorsDirty = false
addedBehaviors.foreach(_.onEnable())
removedBehaviors.foreach(_.onDisable())
removedBehaviors.foreach(_.onDisable(reason))
if (isServer) {
PacketSender.sendNanomachineInputs(player)

View File

@ -55,8 +55,8 @@ class NeuralNetwork(controller: ControllerImpl) extends Persistable {
val rng = new Random(controller.player.getEntityWorld.rand.nextInt())
def connect[Sink <: ConnectorNeuron, Source <: Neuron](sinks: Iterable[Sink], sources: mutable.ArrayBuffer[Source]): Unit = {
val sinkPool = sinks.toBuffer
rng.shuffle(sinkPool)
// Shuffle sink list to give each entry the same chance.
val sinkPool = rng.shuffle(sinks.toBuffer)
for (sink <- sinkPool if sources.nonEmpty) {
for (n <- 0 to rng.nextInt(Settings.get.nanomachineMaxInputs) if sources.nonEmpty) {
val sourceIndex = rng.nextInt(sources.length)
@ -65,10 +65,6 @@ class NeuralNetwork(controller: ControllerImpl) extends Persistable {
}
}
// Shuffle behavior and connector list to give each entry the same chance.
rng.shuffle(connectors)
rng.shuffle(behaviors)
// Connect connectors to triggers, then behaviors to connectors and/or remaining triggers.
val sourcePool = mutable.ArrayBuffer.fill(Settings.get.nanomachineMaxOutputs)(triggers.map(_.asInstanceOf[Neuron])).flatten
connect(connectors, sourcePool)

View File

@ -3,6 +3,7 @@ package li.cil.oc.common.nanomachines.provider
import cpw.mods.fml.common.eventhandler.Event
import li.cil.oc.Settings
import li.cil.oc.api
import li.cil.oc.api.nanomachines.DisableReason
import li.cil.oc.api.prefab.AbstractBehavior
import li.cil.oc.util.BlockPosition
import li.cil.oc.util.ExtendedWorld._
@ -28,7 +29,7 @@ object DisintegrationProvider extends ScalaProvider("c4e7e3c2-8069-4fbb-b08e-74b
// Note: intentionally not overriding getNameHint. Gotta find this one manually!
override def onDisable(): Unit = {
override def onDisable(reason: DisableReason): Unit = {
val world = player.getEntityWorld
for (pos <- breakingMap.keys) {
world.destroyBlockInWorldPartially(pos.hashCode(), pos, -1)

View File

@ -0,0 +1,32 @@
package li.cil.oc.common.nanomachines.provider
import li.cil.oc.Settings
import li.cil.oc.api
import li.cil.oc.api.nanomachines.Behavior
import li.cil.oc.api.nanomachines.DisableReason
import li.cil.oc.api.prefab.AbstractBehavior
import li.cil.oc.integration.util.DamageSourceWithRandomCause
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.nbt.NBTTagCompound
object HungryProvider extends ScalaProvider("") {
final val FillCount = 10 // Create a bunch of these to have a higher chance of one being picked / available.
final val HungryDamage = new DamageSourceWithRandomCause("oc.nanomachinesHungry", 3).
setDamageBypassesArmor().
setDamageIsAbsolute()
override def createScalaBehaviors(player: EntityPlayer): Iterable[Behavior] = Iterable.fill(FillCount)(new HungryBehavior(player))
override protected def readBehaviorFromNBT(player: EntityPlayer, nbt: NBTTagCompound): Behavior = new HungryBehavior(player)
class HungryBehavior(player: EntityPlayer) extends AbstractBehavior(player) {
override def onDisable(reason: DisableReason): Unit = {
if (reason == DisableReason.OutOfEnergy) {
player.attackEntityFrom(HungryDamage, Settings.get.nanomachinesHungryDamage)
api.Nanomachines.getController(player).changeBuffer(Settings.get.nanomachinesHungryEnergyRestored)
}
}
}
}

View File

@ -3,6 +3,7 @@ package li.cil.oc.common.nanomachines.provider
import li.cil.oc.Settings
import li.cil.oc.api
import li.cil.oc.api.nanomachines.Behavior
import li.cil.oc.api.nanomachines.DisableReason
import li.cil.oc.api.prefab.AbstractBehavior
import net.minecraft.entity.player.EntityPlayer
import net.minecraft.nbt.NBTTagCompound
@ -51,9 +52,7 @@ object PotionProvider extends ScalaProvider("c29e4eec-5a46-479a-9b3d-ad0f06da784
override def getNameHint: String = potion.getName.stripPrefix("potion.")
override def onEnable(): Unit = {}
override def onDisable(): Unit = {
override def onDisable(reason: DisableReason): Unit = {
player.removePotionEffect(potion.id)
}

View File

@ -29,6 +29,7 @@ import li.cil.oc.common.item.Delegator
import li.cil.oc.common.item.RedstoneCard
import li.cil.oc.common.item.Tablet
import li.cil.oc.common.nanomachines.provider.DisintegrationProvider
import li.cil.oc.common.nanomachines.provider.HungryProvider
import li.cil.oc.common.nanomachines.provider.MagnetProvider
import li.cil.oc.common.nanomachines.provider.ParticleProvider
import li.cil.oc.common.nanomachines.provider.PotionProvider
@ -253,6 +254,7 @@ object ModOpenComputers extends ModProxy {
api.Manual.addTab(new ItemStackTabIconRenderer(api.Items.get("cpu1").createItemStack(1)), "oc:gui.Manual.Items", "%LANGUAGE%/item/index.md")
api.Nanomachines.addProvider(DisintegrationProvider)
api.Nanomachines.addProvider(HungryProvider)
api.Nanomachines.addProvider(ParticleProvider)
api.Nanomachines.addProvider(PotionProvider)
api.Nanomachines.addProvider(MagnetProvider)

View File

@ -0,0 +1,19 @@
package li.cil.oc.integration.util
import net.minecraft.entity.EntityLivingBase
import net.minecraft.util.ChatComponentTranslation
import net.minecraft.util.DamageSource
import net.minecraft.util.IChatComponent
import net.minecraft.util.StatCollector
class DamageSourceWithRandomCause(name: String, numCauses: Int) extends DamageSource(name) {
override def func_151519_b(damagee: EntityLivingBase): IChatComponent = {
val damager = damagee.func_94060_bK
val format = "death.attack." + damageType + "." + (damagee.worldObj.rand.nextInt(numCauses) + 1)
val withCauseFormat = format + ".player"
if (damager != null && StatCollector.canTranslate(withCauseFormat))
new ChatComponentTranslation(withCauseFormat, damagee.func_145748_c_, damager.func_145748_c_)
else
new ChatComponentTranslation(format, damagee.func_145748_c_)
}
}