From 994c6746e9df464e449738deeb6ec244f7bb9b07 Mon Sep 17 00:00:00 2001 From: LordMZTE Date: Fri, 28 Oct 2022 16:20:12 +0200 Subject: [PATCH] feat: add the source code --- .gitignore | 4 + build.gradle | 19 +- gradlew | 0 src/main/java/calclavia/lib/Calclavia.java | 32 ++ .../java/calclavia/lib/CalculationHelper.java | 111 +++++ src/main/java/calclavia/lib/IPlayerUsing.java | 8 + .../calclavia/lib/IUniversalEnergyTile.java | 7 + .../lib/TileEntityUniversalProducer.java | 25 ++ .../lib/TileEntityUniversalRunnable.java | 28 ++ .../lib/TileEntityUniversalStorable.java | 28 ++ .../java/calclavia/lib/UniversalRecipes.java | 102 +++++ .../java/calclavia/lib/gui/ContainerBase.java | 96 +++++ .../calclavia/lib/gui/GuiContainerBase.java | 296 ++++++++++++++ .../java/calclavia/lib/gui/GuiScreenBase.java | 271 +++++++++++++ .../java/calclavia/lib/gui/GuiSlotType.java | 23 ++ .../lib/render/CalclaviaRenderHelper.java | 111 +++++ .../java/calclavia/lib/render/ITagRender.java | 9 + .../lib/render/RenderTaggedTile.java | 64 +++ .../computercraft/api/ComputerCraftAPI.java | 315 +++++++++++++++ .../computercraft/api/filesystem/IMount.java | 57 +++ .../api/filesystem/IWritableMount.java | 52 +++ .../api/filesystem/package-info.java | 10 + .../computercraft/api/lua/ILuaContext.java | 58 +++ .../computercraft/api/lua/ILuaObject.java | 26 ++ .../computercraft/api/lua/ILuaTask.java | 12 + .../computercraft/api/lua/LuaException.java | 36 ++ .../computercraft/api/lua/package-info.java | 10 + .../computercraft/api/media/IMedia.java | 59 +++ .../api/media/IMediaProvider.java | 23 ++ .../computercraft/api/media/package-info.java | 10 + .../computercraft/api/package-info.java | 10 + .../api/peripheral/IComputerAccess.java | 102 +++++ .../api/peripheral/IPeripheral.java | 100 +++++ .../api/peripheral/IPeripheralProvider.java | 23 ++ .../api/peripheral/package-info.java | 10 + .../ITurtlePermissionProvider.java | 19 + .../api/permissions/package-info.java | 10 + .../redstone/IBundledRedstoneProvider.java | 23 ++ .../api/redstone/package-info.java | 10 + .../api/turtle/ITurtleAccess.java | 168 ++++++++ .../api/turtle/ITurtleCommand.java | 25 ++ .../api/turtle/ITurtleUpgrade.java | 94 +++++ .../api/turtle/TurtleAnimation.java | 22 + .../api/turtle/TurtleCommandResult.java | 73 ++++ .../computercraft/api/turtle/TurtleSide.java | 23 ++ .../api/turtle/TurtleUpgradeType.java | 27 ++ .../computercraft/api/turtle/TurtleVerb.java | 26 ++ .../api/turtle/package-info.java | 10 + src/main/java/icbm/api/IAmmunition.java | 10 + src/main/java/icbm/api/IBlockFrequency.java | 9 + src/main/java/icbm/api/ICBM.java | 41 ++ src/main/java/icbm/api/ICBMFlags.java | 15 + .../java/icbm/api/ICamouflageMaterial.java | 5 + src/main/java/icbm/api/IHackable.java | 10 + src/main/java/icbm/api/IItemFrequency.java | 10 + .../java/icbm/api/ILauncherContainer.java | 13 + .../java/icbm/api/ILauncherController.java | 28 ++ src/main/java/icbm/api/IMissile.java | 26 ++ src/main/java/icbm/api/IMissileLockable.java | 11 + src/main/java/icbm/api/LauncherType.java | 14 + src/main/java/icbm/api/RadarRegistry.java | 110 +++++ .../icbm/api/explosion/ExplosionEvent.java | 36 ++ .../java/icbm/api/explosion/IEMPBlock.java | 10 + .../java/icbm/api/explosion/IEMPItem.java | 11 + .../java/icbm/api/explosion/IExplosive.java | 23 ++ .../api/explosion/IExplosiveContainer.java | 8 + .../icbm/api/explosion/IExplosiveIgnore.java | 8 + src/main/java/mffs/ClientProxy.java | 131 ++++++ src/main/java/mffs/CommonProxy.java | 94 +++++ src/main/java/mffs/DelayedEvent.java | 23 ++ src/main/java/mffs/IDelayedEventHandler.java | 10 + src/main/java/mffs/MFFSCreativeTab.java | 23 ++ src/main/java/mffs/MFFSHelper.java | 370 +++++++++++++++++ src/main/java/mffs/ManipulatorHelper.java | 67 +++ .../java/mffs/ModularForceFieldSystem.java | 355 ++++++++++++++++ src/main/java/mffs/Recipes.java | 331 +++++++++++++++ src/main/java/mffs/Settings.java | 176 ++++++++ src/main/java/mffs/SubscribeEventHandler.java | 86 ++++ src/main/java/mffs/TransferMode.java | 16 + src/main/java/mffs/api/Blacklist.java | 19 + src/main/java/mffs/api/IActivatable.java | 8 + .../mffs/api/IBiometricIdentifierLink.java | 11 + src/main/java/mffs/api/ICache.java | 10 + src/main/java/mffs/api/IFieldInteraction.java | 41 ++ src/main/java/mffs/api/IForceFieldBlock.java | 11 + src/main/java/mffs/api/IProjector.java | 14 + .../mffs/api/ISpecialForceManipulation.java | 10 + src/main/java/mffs/api/card/ICard.java | 5 + .../mffs/api/card/ICardIdentification.java | 17 + .../java/mffs/api/card/ICardInfinite.java | 5 + src/main/java/mffs/api/card/ICardLink.java | 11 + .../mffs/api/fortron/IFortronCapacitor.java | 12 + .../mffs/api/fortron/IFortronFrequency.java | 7 + .../mffs/api/fortron/IFortronStorage.java | 14 + .../modules/IInterdictionMatrixModule.java | 9 + src/main/java/mffs/api/modules/IModule.java | 22 + .../mffs/api/modules/IModuleAcceptor.java | 17 + .../java/mffs/api/modules/IProjectorMode.java | 17 + .../api/security/IBiometricIdentifier.java | 12 + .../api/security/IInterdictionMatrix.java | 24 ++ .../java/mffs/api/security/Permission.java | 45 +++ src/main/java/mffs/base/BlockBase.java | 21 + src/main/java/mffs/base/BlockMachine.java | 137 +++++++ src/main/java/mffs/base/ContainerBase.java | 95 +++++ src/main/java/mffs/base/GuiBase.java | 362 +++++++++++++++++ src/main/java/mffs/base/ItemBase.java | 30 ++ src/main/java/mffs/base/PacketFxs.java | 55 +++ src/main/java/mffs/base/PacketFxsHandler.java | 24 ++ src/main/java/mffs/base/PacketTile.java | 65 +++ .../java/mffs/base/PacketTileHandler.java | 24 ++ src/main/java/mffs/base/TileEntityBase.java | 133 ++++++ .../java/mffs/base/TileEntityFortron.java | 171 ++++++++ .../java/mffs/base/TileEntityFrequency.java | 95 +++++ .../java/mffs/base/TileEntityInventory.java | 345 ++++++++++++++++ .../mffs/base/TileEntityModuleAcceptor.java | 217 ++++++++++ .../mffs/base/TileEntityUniversalEnergy.java | 64 +++ .../mffs/block/BlockBiometricIdentifier.java | 16 + .../java/mffs/block/BlockCoercionDeriver.java | 18 + src/main/java/mffs/block/BlockForceField.java | 323 +++++++++++++++ .../mffs/block/BlockForceFieldProjector.java | 40 ++ .../mffs/block/BlockForceManipulator.java | 70 ++++ .../mffs/block/BlockFortronCapacitor.java | 17 + .../mffs/block/BlockInterdictionMatrix.java | 16 + .../java/mffs/block/BlockMachineBlock.java | 63 +++ src/main/java/mffs/card/ItemCard.java | 11 + .../ContainerBiometricIdentifier.java | 25 ++ .../container/ContainerCoercionDeriver.java | 23 ++ .../ContainerForceFieldProjector.java | 38 ++ .../container/ContainerForceManipulator.java | 38 ++ .../container/ContainerFortronCapacitor.java | 25 ++ .../ContainerInterdictionMatrix.java | 29 ++ .../mffs/event/BlockDropDelayedEvent.java | 35 ++ .../event/BlockInventoryDropDelayedEvent.java | 38 ++ .../mffs/event/BlockNotifyDelayedEvent.java | 52 +++ .../mffs/event/BlockPostMoveDelayedEvent.java | 63 +++ .../mffs/event/BlockPreMoveDelayedEvent.java | 52 +++ src/main/java/mffs/fortron/FortronHelper.java | 28 ++ src/main/java/mffs/fortron/FrequencyGrid.java | 131 ++++++ .../java/mffs/gui/GuiBiometricIdentifier.java | 147 +++++++ .../java/mffs/gui/GuiCoercionDeriver.java | 110 +++++ .../java/mffs/gui/GuiForceFieldProjector.java | 150 +++++++ .../java/mffs/gui/GuiForceManipulator.java | 194 +++++++++ .../java/mffs/gui/GuiFortronCapacitor.java | 96 +++++ .../java/mffs/gui/GuiInterdictionMatrix.java | 105 +++++ .../java/mffs/gui/button/GuiButtonPress.java | 89 ++++ .../button/GuiButtonPressTransferMode.java | 30 ++ src/main/java/mffs/gui/button/GuiIcon.java | 70 ++++ .../java/mffs/item/ItemRemoteController.java | 145 +++++++ .../mffs/item/card/ItemCardFrequency.java | 77 ++++ src/main/java/mffs/item/card/ItemCardID.java | 106 +++++ .../java/mffs/item/card/ItemCardInfinite.java | 8 + .../java/mffs/item/card/ItemCardLink.java | 66 +++ src/main/java/mffs/item/mode/ItemMode.java | 27 ++ .../java/mffs/item/mode/ItemModeCube.java | 79 ++++ .../java/mffs/item/mode/ItemModeSphere.java | 98 +++++ .../java/mffs/item/mode/ItemModeTube.java | 61 +++ .../java/mffs/item/module/ItemModule.java | 68 ++++ .../interdiction/ItemModuleAntiFriendly.java | 22 + .../interdiction/ItemModuleAntiHostile.java | 22 + .../interdiction/ItemModuleAntiPersonnel.java | 39 ++ .../interdiction/ItemModuleConfiscate.java | 77 ++++ .../ItemModuleInterdictionMatrix.java | 28 ++ .../module/interdiction/ItemModuleWarn.java | 22 + .../item/module/projector/ItemModeCustom.java | 339 ++++++++++++++++ .../module/projector/ItemModeCylinder.java | 122 ++++++ .../module/projector/ItemModePyramid.java | 137 +++++++ .../projector/ItemModuleDisintegration.java | 109 +++++ .../module/projector/ItemModuleFusion.java | 48 +++ .../projector/ItemModuleManipulator.java | 24 ++ .../module/projector/ItemModuleShock.java | 24 ++ .../module/projector/ItemModuleSponge.java | 31 ++ .../module/projector/ItemModuleStablize.java | 124 ++++++ src/main/java/mffs/recipe/IRecipeAdapter.java | 14 + src/main/java/mffs/recipe/RecipeBuilder.java | 49 +++ .../mffs/recipe/ShapedOreRecipeAdapter.java | 41 ++ .../recipe/ShapelessOreRecipeAdapter.java | 31 ++ src/main/java/mffs/render/FXBeam.java | 185 +++++++++ src/main/java/mffs/render/FXHologram.java | 93 +++++ .../java/mffs/render/FXHologramMoving.java | 79 ++++ .../java/mffs/render/RenderBlockHandler.java | 84 ++++ .../mffs/render/RenderCoercionDeriver.java | 39 ++ .../java/mffs/render/RenderForceField.java | 137 +++++++ .../render/RenderForceFieldProjector.java | 119 ++++++ .../mffs/render/RenderForceManipulator.java | 38 ++ .../mffs/render/RenderFortronCapacitor.java | 39 ++ src/main/java/mffs/render/RenderIDCard.java | 213 ++++++++++ .../render/model/ModelCoercionDeriver.java | 125 ++++++ .../java/mffs/render/model/ModelCube.java | 28 ++ .../model/ModelForceFieldProjector.java | 237 +++++++++++ .../render/model/ModelForceManipulator.java | 94 +++++ .../render/model/ModelFortronCapacitor.java | 129 ++++++ .../java/mffs/render/model/ModelPlane.java | 28 ++ .../java/mffs/render/model/ModelTriangle.java | 28 ++ src/main/java/mffs/slot/SlotActive.java | 21 + src/main/java/mffs/slot/SlotBase.java | 29 ++ src/main/java/mffs/slot/SlotCard.java | 23 ++ .../ManipulatorCalculationThread.java | 47 +++ .../ProjectorCalculationThread.java | 71 ++++ .../TileEntityBiometricIdentifier.java | 140 +++++++ .../tileentity/TileEntityCoercionDeriver.java | 200 +++++++++ .../TileEntityFieldInteraction.java | 367 +++++++++++++++++ .../mffs/tileentity/TileEntityForceField.java | 107 +++++ .../TileEntityForceFieldProjector.java | 272 +++++++++++++ .../TileEntityForceManipulator.java | 381 ++++++++++++++++++ .../TileEntityFortronCapacitor.java | 164 ++++++++ .../TileEntityInterdictionMatrix.java | 233 +++++++++++ .../api/block/IPartialSealableBlock.java | 9 + .../assets/mffs/lang/de_DE.properties | 155 +++++++ .../assets/mffs/lang/en_US.properties | 155 +++++++ .../assets/mffs/lang/zh_CN.properties | 144 +++++++ src/main/resources/assets/mffs/sounds.json | 52 +++ .../resources/assets/mffs/sounds/field1.ogg | Bin 0 -> 38935 bytes .../resources/assets/mffs/sounds/field2.ogg | Bin 0 -> 37185 bytes .../resources/assets/mffs/sounds/field3.ogg | Bin 0 -> 34970 bytes .../resources/assets/mffs/sounds/field4.ogg | Bin 0 -> 41407 bytes .../resources/assets/mffs/sounds/field5.ogg | Bin 0 -> 36591 bytes .../assets/mffs/sounds/fieldmove1.ogg | Bin 0 -> 17946 bytes .../assets/mffs/sounds/fieldmove2.ogg | Bin 0 -> 19154 bytes .../assets/mffs/sounds/fieldmove3.ogg | Bin 0 -> 19021 bytes .../assets/mffs/sounds/fieldmove4.ogg | Bin 0 -> 18579 bytes .../assets/mffs/sounds/fieldmove5.ogg | Bin 0 -> 18876 bytes .../textures/blocks/biometricIdentifier.png | Bin 0 -> 1361 bytes .../blocks/biometricIdentifier_on.png | Bin 0 -> 1733 bytes .../blocks/biometricIdentifier_top.png | Bin 0 -> 1784 bytes .../blocks/biometricIdentifier_top_on.png | Bin 0 -> 1983 bytes .../mffs/textures/blocks/forceField.png | Bin 0 -> 28417 bytes .../textures/blocks/forceField.png.mcmeta | 33 ++ .../assets/mffs/textures/blocks/fortron.png | Bin 0 -> 5892 bytes .../textures/blocks/interdictionMatrix.png | Bin 0 -> 1736 bytes .../textures/blocks/interdictionMatrix_on.png | Bin 0 -> 1834 bytes .../blocks/interdictionMatrix_top.png | Bin 0 -> 1611 bytes .../blocks/interdictionMatrix_top_on.png | Bin 0 -> 1855 bytes .../assets/mffs/textures/blocks/machine.png | Bin 0 -> 4557 bytes .../assets/mffs/textures/gui/gui_base.png | Bin 0 -> 3682 bytes .../assets/mffs/textures/gui/gui_button.png | Bin 0 -> 7399 bytes .../mffs/textures/gui/gui_components.png | Bin 0 -> 7235 bytes .../assets/mffs/textures/items/cardBlank.png | Bin 0 -> 2993 bytes .../mffs/textures/items/cardFrequency.png | Bin 0 -> 3062 bytes .../textures/items/cardIdentification.png | Bin 0 -> 3114 bytes .../mffs/textures/items/cardInfinite.png | Bin 0 -> 3554 bytes .../assets/mffs/textures/items/cardLink.png | Bin 0 -> 3257 bytes .../mffs/textures/items/focusMatrix.png | Bin 0 -> 4294 bytes .../assets/mffs/textures/items/fortron.png | Bin 0 -> 5892 bytes .../assets/mffs/textures/items/modeCube.png | Bin 0 -> 4719 bytes .../assets/mffs/textures/items/modeCustom.png | Bin 0 -> 4536 bytes .../mffs/textures/items/modeCylinder.png | Bin 0 -> 4804 bytes .../mffs/textures/items/modePyramid.png | Bin 0 -> 4702 bytes .../assets/mffs/textures/items/modeSphere.png | Bin 0 -> 4655 bytes .../assets/mffs/textures/items/modeTube.png | Bin 0 -> 4715 bytes .../textures/items/moduleAntiFriendly.png | Bin 0 -> 4847 bytes .../mffs/textures/items/moduleAntiHostile.png | Bin 0 -> 4837 bytes .../textures/items/moduleAntiPersonnel.png | Bin 0 -> 4800 bytes .../mffs/textures/items/moduleAntiSpawn.png | Bin 0 -> 4901 bytes .../mffs/textures/items/moduleBlockAccess.png | Bin 0 -> 4625 bytes .../mffs/textures/items/moduleBlockAlter.png | Bin 0 -> 4680 bytes .../mffs/textures/items/moduleCamouflage.png | Bin 0 -> 5545 bytes .../mffs/textures/items/moduleCapacity.png | Bin 0 -> 4581 bytes .../mffs/textures/items/moduleCollection.png | Bin 0 -> 2111 bytes .../mffs/textures/items/moduleConfiscate.png | Bin 0 -> 4511 bytes .../textures/items/moduleDisintegration.png | Bin 0 -> 4782 bytes .../mffs/textures/items/moduleFusion.png | Bin 0 -> 4661 bytes .../assets/mffs/textures/items/moduleGlow.png | Bin 0 -> 4685 bytes .../mffs/textures/items/moduleInvert.png | Bin 0 -> 2100 bytes .../mffs/textures/items/moduleManipulator.png | Bin 0 -> 4704 bytes .../mffs/textures/items/moduleRotate.png | Bin 0 -> 4787 bytes .../mffs/textures/items/moduleScale.png | Bin 0 -> 4752 bytes .../mffs/textures/items/moduleShock.png | Bin 0 -> 4803 bytes .../mffs/textures/items/moduleSilence.png | Bin 0 -> 2117 bytes .../mffs/textures/items/moduleSpeed.png | Bin 0 -> 4713 bytes .../mffs/textures/items/moduleSponge.png | Bin 0 -> 5354 bytes .../mffs/textures/items/moduleStabilize.png | Bin 0 -> 4919 bytes .../mffs/textures/items/moduleTranslate.png | Bin 0 -> 4932 bytes .../assets/mffs/textures/items/moduleWarn.png | Bin 0 -> 5233 bytes .../mffs/textures/items/remoteController.png | Bin 0 -> 1476 bytes .../textures/models/coercionDeriver_off.png | Bin 0 -> 6928 bytes .../textures/models/coercionDeriver_on.png | Bin 0 -> 4041 bytes .../textures/models/forceManipulator_off.png | Bin 0 -> 5337 bytes .../textures/models/forceManipulator_on.png | Bin 0 -> 5399 bytes .../mffs/textures/models/force_cube.png | Bin 0 -> 6031 bytes .../textures/models/fortronCapacitor_off.png | Bin 0 -> 5482 bytes .../textures/models/fortronCapacitor_on.png | Bin 0 -> 2932 bytes .../mffs/textures/models/projector_off.png | Bin 0 -> 10853 bytes .../mffs/textures/models/projector_on.png | Bin 0 -> 11407 bytes src/main/resources/mffs_at.cfg | 2 + 284 files changed, 15413 insertions(+), 3 deletions(-) mode change 100644 => 100755 gradlew create mode 100644 src/main/java/calclavia/lib/Calclavia.java create mode 100644 src/main/java/calclavia/lib/CalculationHelper.java create mode 100644 src/main/java/calclavia/lib/IPlayerUsing.java create mode 100644 src/main/java/calclavia/lib/IUniversalEnergyTile.java create mode 100644 src/main/java/calclavia/lib/TileEntityUniversalProducer.java create mode 100644 src/main/java/calclavia/lib/TileEntityUniversalRunnable.java create mode 100644 src/main/java/calclavia/lib/TileEntityUniversalStorable.java create mode 100644 src/main/java/calclavia/lib/UniversalRecipes.java create mode 100644 src/main/java/calclavia/lib/gui/ContainerBase.java create mode 100644 src/main/java/calclavia/lib/gui/GuiContainerBase.java create mode 100644 src/main/java/calclavia/lib/gui/GuiScreenBase.java create mode 100644 src/main/java/calclavia/lib/gui/GuiSlotType.java create mode 100644 src/main/java/calclavia/lib/render/CalclaviaRenderHelper.java create mode 100644 src/main/java/calclavia/lib/render/ITagRender.java create mode 100644 src/main/java/calclavia/lib/render/RenderTaggedTile.java create mode 100755 src/main/java/dan200/computercraft/api/ComputerCraftAPI.java create mode 100755 src/main/java/dan200/computercraft/api/filesystem/IMount.java create mode 100755 src/main/java/dan200/computercraft/api/filesystem/IWritableMount.java create mode 100755 src/main/java/dan200/computercraft/api/filesystem/package-info.java create mode 100755 src/main/java/dan200/computercraft/api/lua/ILuaContext.java create mode 100755 src/main/java/dan200/computercraft/api/lua/ILuaObject.java create mode 100755 src/main/java/dan200/computercraft/api/lua/ILuaTask.java create mode 100755 src/main/java/dan200/computercraft/api/lua/LuaException.java create mode 100755 src/main/java/dan200/computercraft/api/lua/package-info.java create mode 100755 src/main/java/dan200/computercraft/api/media/IMedia.java create mode 100755 src/main/java/dan200/computercraft/api/media/IMediaProvider.java create mode 100755 src/main/java/dan200/computercraft/api/media/package-info.java create mode 100755 src/main/java/dan200/computercraft/api/package-info.java create mode 100755 src/main/java/dan200/computercraft/api/peripheral/IComputerAccess.java create mode 100755 src/main/java/dan200/computercraft/api/peripheral/IPeripheral.java create mode 100755 src/main/java/dan200/computercraft/api/peripheral/IPeripheralProvider.java create mode 100755 src/main/java/dan200/computercraft/api/peripheral/package-info.java create mode 100644 src/main/java/dan200/computercraft/api/permissions/ITurtlePermissionProvider.java create mode 100644 src/main/java/dan200/computercraft/api/permissions/package-info.java create mode 100755 src/main/java/dan200/computercraft/api/redstone/IBundledRedstoneProvider.java create mode 100755 src/main/java/dan200/computercraft/api/redstone/package-info.java create mode 100755 src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java create mode 100755 src/main/java/dan200/computercraft/api/turtle/ITurtleCommand.java create mode 100755 src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java create mode 100755 src/main/java/dan200/computercraft/api/turtle/TurtleAnimation.java create mode 100755 src/main/java/dan200/computercraft/api/turtle/TurtleCommandResult.java create mode 100755 src/main/java/dan200/computercraft/api/turtle/TurtleSide.java create mode 100755 src/main/java/dan200/computercraft/api/turtle/TurtleUpgradeType.java create mode 100755 src/main/java/dan200/computercraft/api/turtle/TurtleVerb.java create mode 100755 src/main/java/dan200/computercraft/api/turtle/package-info.java create mode 100644 src/main/java/icbm/api/IAmmunition.java create mode 100644 src/main/java/icbm/api/IBlockFrequency.java create mode 100644 src/main/java/icbm/api/ICBM.java create mode 100644 src/main/java/icbm/api/ICBMFlags.java create mode 100644 src/main/java/icbm/api/ICamouflageMaterial.java create mode 100644 src/main/java/icbm/api/IHackable.java create mode 100644 src/main/java/icbm/api/IItemFrequency.java create mode 100644 src/main/java/icbm/api/ILauncherContainer.java create mode 100644 src/main/java/icbm/api/ILauncherController.java create mode 100644 src/main/java/icbm/api/IMissile.java create mode 100644 src/main/java/icbm/api/IMissileLockable.java create mode 100644 src/main/java/icbm/api/LauncherType.java create mode 100644 src/main/java/icbm/api/RadarRegistry.java create mode 100644 src/main/java/icbm/api/explosion/ExplosionEvent.java create mode 100644 src/main/java/icbm/api/explosion/IEMPBlock.java create mode 100644 src/main/java/icbm/api/explosion/IEMPItem.java create mode 100644 src/main/java/icbm/api/explosion/IExplosive.java create mode 100644 src/main/java/icbm/api/explosion/IExplosiveContainer.java create mode 100644 src/main/java/icbm/api/explosion/IExplosiveIgnore.java create mode 100644 src/main/java/mffs/ClientProxy.java create mode 100644 src/main/java/mffs/CommonProxy.java create mode 100644 src/main/java/mffs/DelayedEvent.java create mode 100644 src/main/java/mffs/IDelayedEventHandler.java create mode 100644 src/main/java/mffs/MFFSCreativeTab.java create mode 100644 src/main/java/mffs/MFFSHelper.java create mode 100644 src/main/java/mffs/ManipulatorHelper.java create mode 100644 src/main/java/mffs/ModularForceFieldSystem.java create mode 100644 src/main/java/mffs/Recipes.java create mode 100644 src/main/java/mffs/Settings.java create mode 100644 src/main/java/mffs/SubscribeEventHandler.java create mode 100644 src/main/java/mffs/TransferMode.java create mode 100644 src/main/java/mffs/api/Blacklist.java create mode 100644 src/main/java/mffs/api/IActivatable.java create mode 100644 src/main/java/mffs/api/IBiometricIdentifierLink.java create mode 100644 src/main/java/mffs/api/ICache.java create mode 100644 src/main/java/mffs/api/IFieldInteraction.java create mode 100644 src/main/java/mffs/api/IForceFieldBlock.java create mode 100644 src/main/java/mffs/api/IProjector.java create mode 100644 src/main/java/mffs/api/ISpecialForceManipulation.java create mode 100644 src/main/java/mffs/api/card/ICard.java create mode 100644 src/main/java/mffs/api/card/ICardIdentification.java create mode 100644 src/main/java/mffs/api/card/ICardInfinite.java create mode 100644 src/main/java/mffs/api/card/ICardLink.java create mode 100644 src/main/java/mffs/api/fortron/IFortronCapacitor.java create mode 100644 src/main/java/mffs/api/fortron/IFortronFrequency.java create mode 100644 src/main/java/mffs/api/fortron/IFortronStorage.java create mode 100644 src/main/java/mffs/api/modules/IInterdictionMatrixModule.java create mode 100644 src/main/java/mffs/api/modules/IModule.java create mode 100644 src/main/java/mffs/api/modules/IModuleAcceptor.java create mode 100644 src/main/java/mffs/api/modules/IProjectorMode.java create mode 100644 src/main/java/mffs/api/security/IBiometricIdentifier.java create mode 100644 src/main/java/mffs/api/security/IInterdictionMatrix.java create mode 100644 src/main/java/mffs/api/security/Permission.java create mode 100644 src/main/java/mffs/base/BlockBase.java create mode 100644 src/main/java/mffs/base/BlockMachine.java create mode 100644 src/main/java/mffs/base/ContainerBase.java create mode 100644 src/main/java/mffs/base/GuiBase.java create mode 100644 src/main/java/mffs/base/ItemBase.java create mode 100644 src/main/java/mffs/base/PacketFxs.java create mode 100644 src/main/java/mffs/base/PacketFxsHandler.java create mode 100644 src/main/java/mffs/base/PacketTile.java create mode 100644 src/main/java/mffs/base/PacketTileHandler.java create mode 100644 src/main/java/mffs/base/TileEntityBase.java create mode 100644 src/main/java/mffs/base/TileEntityFortron.java create mode 100644 src/main/java/mffs/base/TileEntityFrequency.java create mode 100644 src/main/java/mffs/base/TileEntityInventory.java create mode 100644 src/main/java/mffs/base/TileEntityModuleAcceptor.java create mode 100644 src/main/java/mffs/base/TileEntityUniversalEnergy.java create mode 100644 src/main/java/mffs/block/BlockBiometricIdentifier.java create mode 100644 src/main/java/mffs/block/BlockCoercionDeriver.java create mode 100644 src/main/java/mffs/block/BlockForceField.java create mode 100644 src/main/java/mffs/block/BlockForceFieldProjector.java create mode 100644 src/main/java/mffs/block/BlockForceManipulator.java create mode 100644 src/main/java/mffs/block/BlockFortronCapacitor.java create mode 100644 src/main/java/mffs/block/BlockInterdictionMatrix.java create mode 100644 src/main/java/mffs/block/BlockMachineBlock.java create mode 100644 src/main/java/mffs/card/ItemCard.java create mode 100644 src/main/java/mffs/container/ContainerBiometricIdentifier.java create mode 100644 src/main/java/mffs/container/ContainerCoercionDeriver.java create mode 100644 src/main/java/mffs/container/ContainerForceFieldProjector.java create mode 100644 src/main/java/mffs/container/ContainerForceManipulator.java create mode 100644 src/main/java/mffs/container/ContainerFortronCapacitor.java create mode 100644 src/main/java/mffs/container/ContainerInterdictionMatrix.java create mode 100644 src/main/java/mffs/event/BlockDropDelayedEvent.java create mode 100644 src/main/java/mffs/event/BlockInventoryDropDelayedEvent.java create mode 100644 src/main/java/mffs/event/BlockNotifyDelayedEvent.java create mode 100644 src/main/java/mffs/event/BlockPostMoveDelayedEvent.java create mode 100644 src/main/java/mffs/event/BlockPreMoveDelayedEvent.java create mode 100644 src/main/java/mffs/fortron/FortronHelper.java create mode 100644 src/main/java/mffs/fortron/FrequencyGrid.java create mode 100644 src/main/java/mffs/gui/GuiBiometricIdentifier.java create mode 100644 src/main/java/mffs/gui/GuiCoercionDeriver.java create mode 100644 src/main/java/mffs/gui/GuiForceFieldProjector.java create mode 100644 src/main/java/mffs/gui/GuiForceManipulator.java create mode 100644 src/main/java/mffs/gui/GuiFortronCapacitor.java create mode 100644 src/main/java/mffs/gui/GuiInterdictionMatrix.java create mode 100644 src/main/java/mffs/gui/button/GuiButtonPress.java create mode 100644 src/main/java/mffs/gui/button/GuiButtonPressTransferMode.java create mode 100644 src/main/java/mffs/gui/button/GuiIcon.java create mode 100644 src/main/java/mffs/item/ItemRemoteController.java create mode 100644 src/main/java/mffs/item/card/ItemCardFrequency.java create mode 100644 src/main/java/mffs/item/card/ItemCardID.java create mode 100644 src/main/java/mffs/item/card/ItemCardInfinite.java create mode 100644 src/main/java/mffs/item/card/ItemCardLink.java create mode 100644 src/main/java/mffs/item/mode/ItemMode.java create mode 100644 src/main/java/mffs/item/mode/ItemModeCube.java create mode 100644 src/main/java/mffs/item/mode/ItemModeSphere.java create mode 100644 src/main/java/mffs/item/mode/ItemModeTube.java create mode 100644 src/main/java/mffs/item/module/ItemModule.java create mode 100644 src/main/java/mffs/item/module/interdiction/ItemModuleAntiFriendly.java create mode 100644 src/main/java/mffs/item/module/interdiction/ItemModuleAntiHostile.java create mode 100644 src/main/java/mffs/item/module/interdiction/ItemModuleAntiPersonnel.java create mode 100644 src/main/java/mffs/item/module/interdiction/ItemModuleConfiscate.java create mode 100644 src/main/java/mffs/item/module/interdiction/ItemModuleInterdictionMatrix.java create mode 100644 src/main/java/mffs/item/module/interdiction/ItemModuleWarn.java create mode 100644 src/main/java/mffs/item/module/projector/ItemModeCustom.java create mode 100644 src/main/java/mffs/item/module/projector/ItemModeCylinder.java create mode 100644 src/main/java/mffs/item/module/projector/ItemModePyramid.java create mode 100644 src/main/java/mffs/item/module/projector/ItemModuleDisintegration.java create mode 100644 src/main/java/mffs/item/module/projector/ItemModuleFusion.java create mode 100644 src/main/java/mffs/item/module/projector/ItemModuleManipulator.java create mode 100644 src/main/java/mffs/item/module/projector/ItemModuleShock.java create mode 100644 src/main/java/mffs/item/module/projector/ItemModuleSponge.java create mode 100644 src/main/java/mffs/item/module/projector/ItemModuleStablize.java create mode 100644 src/main/java/mffs/recipe/IRecipeAdapter.java create mode 100644 src/main/java/mffs/recipe/RecipeBuilder.java create mode 100644 src/main/java/mffs/recipe/ShapedOreRecipeAdapter.java create mode 100644 src/main/java/mffs/recipe/ShapelessOreRecipeAdapter.java create mode 100644 src/main/java/mffs/render/FXBeam.java create mode 100644 src/main/java/mffs/render/FXHologram.java create mode 100644 src/main/java/mffs/render/FXHologramMoving.java create mode 100644 src/main/java/mffs/render/RenderBlockHandler.java create mode 100644 src/main/java/mffs/render/RenderCoercionDeriver.java create mode 100644 src/main/java/mffs/render/RenderForceField.java create mode 100644 src/main/java/mffs/render/RenderForceFieldProjector.java create mode 100644 src/main/java/mffs/render/RenderForceManipulator.java create mode 100644 src/main/java/mffs/render/RenderFortronCapacitor.java create mode 100644 src/main/java/mffs/render/RenderIDCard.java create mode 100644 src/main/java/mffs/render/model/ModelCoercionDeriver.java create mode 100644 src/main/java/mffs/render/model/ModelCube.java create mode 100644 src/main/java/mffs/render/model/ModelForceFieldProjector.java create mode 100644 src/main/java/mffs/render/model/ModelForceManipulator.java create mode 100644 src/main/java/mffs/render/model/ModelFortronCapacitor.java create mode 100644 src/main/java/mffs/render/model/ModelPlane.java create mode 100644 src/main/java/mffs/render/model/ModelTriangle.java create mode 100644 src/main/java/mffs/slot/SlotActive.java create mode 100644 src/main/java/mffs/slot/SlotBase.java create mode 100644 src/main/java/mffs/slot/SlotCard.java create mode 100644 src/main/java/mffs/tileentity/ManipulatorCalculationThread.java create mode 100644 src/main/java/mffs/tileentity/ProjectorCalculationThread.java create mode 100644 src/main/java/mffs/tileentity/TileEntityBiometricIdentifier.java create mode 100644 src/main/java/mffs/tileentity/TileEntityCoercionDeriver.java create mode 100644 src/main/java/mffs/tileentity/TileEntityFieldInteraction.java create mode 100644 src/main/java/mffs/tileentity/TileEntityForceField.java create mode 100644 src/main/java/mffs/tileentity/TileEntityForceFieldProjector.java create mode 100644 src/main/java/mffs/tileentity/TileEntityForceManipulator.java create mode 100644 src/main/java/mffs/tileentity/TileEntityFortronCapacitor.java create mode 100644 src/main/java/mffs/tileentity/TileEntityInterdictionMatrix.java create mode 100644 src/main/java/micdoodle8/mods/galacticraft/api/block/IPartialSealableBlock.java create mode 100644 src/main/resources/assets/mffs/lang/de_DE.properties create mode 100644 src/main/resources/assets/mffs/lang/en_US.properties create mode 100644 src/main/resources/assets/mffs/lang/zh_CN.properties create mode 100644 src/main/resources/assets/mffs/sounds.json create mode 100644 src/main/resources/assets/mffs/sounds/field1.ogg create mode 100644 src/main/resources/assets/mffs/sounds/field2.ogg create mode 100644 src/main/resources/assets/mffs/sounds/field3.ogg create mode 100644 src/main/resources/assets/mffs/sounds/field4.ogg create mode 100644 src/main/resources/assets/mffs/sounds/field5.ogg create mode 100644 src/main/resources/assets/mffs/sounds/fieldmove1.ogg create mode 100644 src/main/resources/assets/mffs/sounds/fieldmove2.ogg create mode 100644 src/main/resources/assets/mffs/sounds/fieldmove3.ogg create mode 100644 src/main/resources/assets/mffs/sounds/fieldmove4.ogg create mode 100644 src/main/resources/assets/mffs/sounds/fieldmove5.ogg create mode 100644 src/main/resources/assets/mffs/textures/blocks/biometricIdentifier.png create mode 100644 src/main/resources/assets/mffs/textures/blocks/biometricIdentifier_on.png create mode 100644 src/main/resources/assets/mffs/textures/blocks/biometricIdentifier_top.png create mode 100644 src/main/resources/assets/mffs/textures/blocks/biometricIdentifier_top_on.png create mode 100644 src/main/resources/assets/mffs/textures/blocks/forceField.png create mode 100644 src/main/resources/assets/mffs/textures/blocks/forceField.png.mcmeta create mode 100644 src/main/resources/assets/mffs/textures/blocks/fortron.png create mode 100644 src/main/resources/assets/mffs/textures/blocks/interdictionMatrix.png create mode 100644 src/main/resources/assets/mffs/textures/blocks/interdictionMatrix_on.png create mode 100644 src/main/resources/assets/mffs/textures/blocks/interdictionMatrix_top.png create mode 100644 src/main/resources/assets/mffs/textures/blocks/interdictionMatrix_top_on.png create mode 100644 src/main/resources/assets/mffs/textures/blocks/machine.png create mode 100644 src/main/resources/assets/mffs/textures/gui/gui_base.png create mode 100644 src/main/resources/assets/mffs/textures/gui/gui_button.png create mode 100644 src/main/resources/assets/mffs/textures/gui/gui_components.png create mode 100644 src/main/resources/assets/mffs/textures/items/cardBlank.png create mode 100644 src/main/resources/assets/mffs/textures/items/cardFrequency.png create mode 100644 src/main/resources/assets/mffs/textures/items/cardIdentification.png create mode 100644 src/main/resources/assets/mffs/textures/items/cardInfinite.png create mode 100644 src/main/resources/assets/mffs/textures/items/cardLink.png create mode 100644 src/main/resources/assets/mffs/textures/items/focusMatrix.png create mode 100644 src/main/resources/assets/mffs/textures/items/fortron.png create mode 100644 src/main/resources/assets/mffs/textures/items/modeCube.png create mode 100644 src/main/resources/assets/mffs/textures/items/modeCustom.png create mode 100644 src/main/resources/assets/mffs/textures/items/modeCylinder.png create mode 100644 src/main/resources/assets/mffs/textures/items/modePyramid.png create mode 100644 src/main/resources/assets/mffs/textures/items/modeSphere.png create mode 100644 src/main/resources/assets/mffs/textures/items/modeTube.png create mode 100644 src/main/resources/assets/mffs/textures/items/moduleAntiFriendly.png create mode 100644 src/main/resources/assets/mffs/textures/items/moduleAntiHostile.png create mode 100644 src/main/resources/assets/mffs/textures/items/moduleAntiPersonnel.png create mode 100644 src/main/resources/assets/mffs/textures/items/moduleAntiSpawn.png create mode 100644 src/main/resources/assets/mffs/textures/items/moduleBlockAccess.png create mode 100644 src/main/resources/assets/mffs/textures/items/moduleBlockAlter.png create mode 100644 src/main/resources/assets/mffs/textures/items/moduleCamouflage.png create mode 100644 src/main/resources/assets/mffs/textures/items/moduleCapacity.png create mode 100644 src/main/resources/assets/mffs/textures/items/moduleCollection.png create mode 100644 src/main/resources/assets/mffs/textures/items/moduleConfiscate.png create mode 100644 src/main/resources/assets/mffs/textures/items/moduleDisintegration.png create mode 100644 src/main/resources/assets/mffs/textures/items/moduleFusion.png create mode 100644 src/main/resources/assets/mffs/textures/items/moduleGlow.png create mode 100644 src/main/resources/assets/mffs/textures/items/moduleInvert.png create mode 100644 src/main/resources/assets/mffs/textures/items/moduleManipulator.png create mode 100644 src/main/resources/assets/mffs/textures/items/moduleRotate.png create mode 100644 src/main/resources/assets/mffs/textures/items/moduleScale.png create mode 100644 src/main/resources/assets/mffs/textures/items/moduleShock.png create mode 100644 src/main/resources/assets/mffs/textures/items/moduleSilence.png create mode 100644 src/main/resources/assets/mffs/textures/items/moduleSpeed.png create mode 100644 src/main/resources/assets/mffs/textures/items/moduleSponge.png create mode 100644 src/main/resources/assets/mffs/textures/items/moduleStabilize.png create mode 100644 src/main/resources/assets/mffs/textures/items/moduleTranslate.png create mode 100644 src/main/resources/assets/mffs/textures/items/moduleWarn.png create mode 100644 src/main/resources/assets/mffs/textures/items/remoteController.png create mode 100644 src/main/resources/assets/mffs/textures/models/coercionDeriver_off.png create mode 100644 src/main/resources/assets/mffs/textures/models/coercionDeriver_on.png create mode 100644 src/main/resources/assets/mffs/textures/models/forceManipulator_off.png create mode 100644 src/main/resources/assets/mffs/textures/models/forceManipulator_on.png create mode 100644 src/main/resources/assets/mffs/textures/models/force_cube.png create mode 100644 src/main/resources/assets/mffs/textures/models/fortronCapacitor_off.png create mode 100644 src/main/resources/assets/mffs/textures/models/fortronCapacitor_on.png create mode 100644 src/main/resources/assets/mffs/textures/models/projector_off.png create mode 100644 src/main/resources/assets/mffs/textures/models/projector_on.png create mode 100644 src/main/resources/mffs_at.cfg diff --git a/.gitignore b/.gitignore index 8d16946..bbc8ac8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ +.project +.classpath +bin +.settings .gradle .idea build diff --git a/build.gradle b/build.gradle index ee53ffc..54d8090 100644 --- a/build.gradle +++ b/build.gradle @@ -17,9 +17,22 @@ buildscript { apply plugin: 'forge' +sourceCompatibility = JavaVersion.VERSION_1_8 +targetCompatibility = JavaVersion.VERSION_1_8 + +sourceSets { + api {} +} + version = "1.0" -group= "modgroup" -archivesBaseName = "modid" +group = "universalelectricity" +archivesBaseName = "mffs" + +jar { + manifest { + attributes "FMLAT": "mffs_at.cfg" + } +} minecraft { version = "1.7.10-10.13.4.1614-1.7.10" @@ -31,7 +44,7 @@ repositories { } dependencies { - compile "universalelectricity:basiccomponents:1.0.0-dirty:deobf" + compile "universalelectricity:basiccomponents:1.0.2-dirty:deobf" } processResources diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 diff --git a/src/main/java/calclavia/lib/Calclavia.java b/src/main/java/calclavia/lib/Calclavia.java new file mode 100644 index 0000000..ff6b180 --- /dev/null +++ b/src/main/java/calclavia/lib/Calclavia.java @@ -0,0 +1,32 @@ +package calclavia.lib; + +import java.util.ArrayList; +import java.util.List; + +public class Calclavia { + + public static final String RESOURCE_DIRECTORY = "/mods/calclavia/"; + public static final String TEXTURE_DIRECTORY = "/mods/calclavia/textures/"; + public static final String GUI_DIRECTORY = "/mods/calclavia/textures/gui/"; + public static final String GUI_COMPONENTS = "/mods/calclavia/textures/gui/gui_components.png"; + public static final String GUI_BASE_FILE = "/mods/calclavia/textures/gui/gui_base.png"; + public static final String GUI_EMPTY_FILE = "/mods/calclavia/textures/gui/gui_empty.png"; + + + public static List splitStringPerWord(String string, int wordsPerLine) { + String[] words = string.split(" "); + ArrayList lines = new ArrayList<>(); + + for(int lineCount = 0; (double)lineCount < Math.ceil((double)((float)words.length / (float)wordsPerLine)); ++lineCount) { + String stringInLine = ""; + + for(int i = lineCount * wordsPerLine; i < Math.min(wordsPerLine + lineCount * wordsPerLine, words.length); ++i) { + stringInLine = stringInLine + words[i] + " "; + } + + lines.add(stringInLine.trim()); + } + + return lines; + } +} diff --git a/src/main/java/calclavia/lib/CalculationHelper.java b/src/main/java/calclavia/lib/CalculationHelper.java new file mode 100644 index 0000000..1748b8b --- /dev/null +++ b/src/main/java/calclavia/lib/CalculationHelper.java @@ -0,0 +1,111 @@ +package calclavia.lib; + +import java.util.Iterator; +import java.util.List; +import net.minecraft.entity.Entity; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.util.MovingObjectPosition; +import net.minecraft.util.Vec3; +import net.minecraft.world.World; +import universalelectricity.core.vector.Vector3; + +public class CalculationHelper { + + public static void rotateByAngle(Vector3 vector, double yaw) { + double yawRadians = Math.toRadians(yaw); + double x = vector.x; + double z = vector.z; + if(yaw != 0.0D) { + vector.x = x * Math.cos(yawRadians) - z * Math.sin(yawRadians); + vector.z = x * Math.sin(yawRadians) + z * Math.cos(yawRadians); + } + + } + + public static void rotateByAngle(Vector3 vector, double yaw, double pitch) { + rotateByAngle(vector, yaw, pitch, 0.0D); + } + + public static void rotateByAngle(Vector3 vector, double yaw, double pitch, double roll) { + double yawRadians = Math.toRadians(yaw); + double pitchRadians = Math.toRadians(pitch); + double rollRadians = Math.toRadians(roll); + double x = vector.x; + double y = vector.y; + double z = vector.z; + vector.x = x * Math.cos(yawRadians) * Math.cos(pitchRadians) + z * (Math.cos(yawRadians) * Math.sin(pitchRadians) * Math.sin(rollRadians) - Math.sin(yawRadians) * Math.cos(rollRadians)) + y * (Math.cos(yawRadians) * Math.sin(pitchRadians) * Math.cos(rollRadians) + Math.sin(yawRadians) * Math.sin(rollRadians)); + vector.z = x * Math.sin(yawRadians) * Math.cos(pitchRadians) + z * (Math.sin(yawRadians) * Math.sin(pitchRadians) * Math.sin(rollRadians) + Math.cos(yawRadians) * Math.cos(rollRadians)) + y * (Math.sin(yawRadians) * Math.sin(pitchRadians) * Math.cos(rollRadians) - Math.cos(yawRadians) * Math.sin(rollRadians)); + vector.y = -x * Math.sin(pitchRadians) + z * Math.cos(pitchRadians) * Math.sin(rollRadians) + y * Math.cos(pitchRadians) * Math.cos(rollRadians); + } + + public static Vector3 getDeltaPositionFromRotation(float rotationYaw, float rotationPitch) { + rotationYaw += 90.0F; + rotationPitch = -rotationPitch; + return new Vector3(Math.cos(Math.toRadians((double)rotationYaw)), Math.sin(Math.toRadians((double)rotationPitch)), Math.sin(Math.toRadians((double)rotationYaw))); + } + + public static MovingObjectPosition raytraceEntities(World world, Vector3 startPosition, float rotationYaw, float rotationPitch, boolean collisionFlag, double reachDistance) { + MovingObjectPosition pickedEntity = null; + Vec3 startingPosition = startPosition.toVec3(); + Vec3 look = getDeltaPositionFromRotation(rotationYaw, rotationPitch).toVec3(); + Vec3 reachPoint = Vec3.createVectorHelper(startingPosition.xCoord + look.xCoord * reachDistance, startingPosition.yCoord + look.yCoord * reachDistance, startingPosition.zCoord + look.zCoord * reachDistance); + double playerBorder = 1.1D * reachDistance; + AxisAlignedBB boxToScan = AxisAlignedBB.getBoundingBox(-playerBorder, -playerBorder, -playerBorder, playerBorder, playerBorder, playerBorder); + List entitiesHit = world.getEntitiesWithinAABBExcludingEntity((Entity)null, boxToScan); + double closestEntity = reachDistance; + if(entitiesHit != null && !entitiesHit.isEmpty()) { + Iterator i$ = entitiesHit.iterator(); + + while(i$.hasNext()) { + Entity entityHit = (Entity)i$.next(); + if(entityHit != null && entityHit.canBeCollidedWith() && entityHit.boundingBox != null) { + float border = entityHit.getCollisionBorderSize(); + AxisAlignedBB aabb = entityHit.boundingBox.expand((double)border, (double)border, (double)border); + MovingObjectPosition hitMOP = aabb.calculateIntercept(startingPosition, reachPoint); + if(hitMOP != null) { + if(aabb.isVecInside(startingPosition)) { + if(0.0D < closestEntity || closestEntity == 0.0D) { + pickedEntity = new MovingObjectPosition(entityHit); + if(pickedEntity != null) { + pickedEntity.hitVec = hitMOP.hitVec; + closestEntity = 0.0D; + } + } + } else { + double distance = startingPosition.distanceTo(hitMOP.hitVec); + if(distance < closestEntity || closestEntity == 0.0D) { + pickedEntity = new MovingObjectPosition(entityHit); + pickedEntity.hitVec = hitMOP.hitVec; + closestEntity = distance; + } + } + } + } + } + + return pickedEntity; + } else { + return null; + } + } + + public static MovingObjectPosition raytraceBlocks(World world, Vector3 startPosition, float rotationYaw, float rotationPitch, boolean collisionFlag, double reachDistance) { + Vector3 lookVector = getDeltaPositionFromRotation(rotationYaw, rotationPitch); + Vector3 reachPoint = Vector3.add(startPosition, Vector3.multiply(lookVector, reachDistance)); + return world.rayTraceBlocks(startPosition.toVec3(), reachPoint.toVec3(), collisionFlag); + } + + public static MovingObjectPosition doCustomRayTrace(World world, Vector3 startPosition, float rotationYaw, float rotationPitch, boolean collisionFlag, double reachDistance) { + MovingObjectPosition pickedBlock = raytraceBlocks(world, startPosition, rotationYaw, rotationPitch, collisionFlag, reachDistance); + MovingObjectPosition pickedEntity = raytraceEntities(world, startPosition, rotationYaw, rotationPitch, collisionFlag, reachDistance); + if(pickedBlock == null) { + return pickedEntity; + } else if(pickedEntity == null) { + return pickedBlock; + } else { + double dBlock = startPosition.distanceTo(new Vector3(pickedBlock.hitVec)); + double dEntity = startPosition.distanceTo(new Vector3(pickedEntity.hitVec)); + return dEntity < dBlock?pickedEntity:pickedBlock; + } + } +} diff --git a/src/main/java/calclavia/lib/IPlayerUsing.java b/src/main/java/calclavia/lib/IPlayerUsing.java new file mode 100644 index 0000000..c7681eb --- /dev/null +++ b/src/main/java/calclavia/lib/IPlayerUsing.java @@ -0,0 +1,8 @@ +package calclavia.lib; + +import java.util.HashSet; + +public interface IPlayerUsing { + + HashSet getPlayersUsing(); +} diff --git a/src/main/java/calclavia/lib/IUniversalEnergyTile.java b/src/main/java/calclavia/lib/IUniversalEnergyTile.java new file mode 100644 index 0000000..ed5452c --- /dev/null +++ b/src/main/java/calclavia/lib/IUniversalEnergyTile.java @@ -0,0 +1,7 @@ +package calclavia.lib; + +import universalelectricity.core.block.IConnector; +import universalelectricity.core.block.IVoltage; + +public interface IUniversalEnergyTile extends IConnector, IVoltage { +} diff --git a/src/main/java/calclavia/lib/TileEntityUniversalProducer.java b/src/main/java/calclavia/lib/TileEntityUniversalProducer.java new file mode 100644 index 0000000..e90c0c9 --- /dev/null +++ b/src/main/java/calclavia/lib/TileEntityUniversalProducer.java @@ -0,0 +1,25 @@ +package calclavia.lib; + +import net.minecraftforge.common.util.ForgeDirection; +import universalelectricity.core.electricity.ElectricityNetworkHelper; +import universalelectricity.core.electricity.ElectricityPack; +import universalelectricity.prefab.implement.IRotatable; +import universalelectricity.prefab.tile.TileEntityElectrical; + +public class TileEntityUniversalProducer extends TileEntityElectrical { + public ElectricityPack produce(double watts) { + ElectricityPack pack = + new ElectricityPack(watts / this.getVoltage(), this.getVoltage()); + ElectricityPack remaining = + ElectricityNetworkHelper.produceFromMultipleSides(this, pack); + + return remaining; + } + + @Override + public boolean canConnect(ForgeDirection direction) { + return this instanceof IRotatable + ? direction.ordinal() == this.getBlockMetadata() + : true; + } +} diff --git a/src/main/java/calclavia/lib/TileEntityUniversalRunnable.java b/src/main/java/calclavia/lib/TileEntityUniversalRunnable.java new file mode 100644 index 0000000..19387fb --- /dev/null +++ b/src/main/java/calclavia/lib/TileEntityUniversalRunnable.java @@ -0,0 +1,28 @@ +package calclavia.lib; + +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; +import universalelectricity.prefab.implement.IRotatable; +import universalelectricity.prefab.tile.TileEntityElectricityRunnable; + +public abstract class TileEntityUniversalRunnable + extends TileEntityElectricityRunnable implements IUniversalEnergyTile { + @Override + public boolean canConnect(ForgeDirection direction) { + return this instanceof IRotatable + ? direction == ForgeDirection.getOrientation(this.getBlockMetadata()) + .getOpposite() + : true; + } + + public ForgeDirection getDirection(IBlockAccess world, int x, int y, int z) { + return ForgeDirection.getOrientation(this.getBlockMetadata()); + } + + public void setDirection(World world, int x, int y, int z, + ForgeDirection facingDirection) { + this.worldObj.setBlockMetadataWithNotify( + this.xCoord, this.yCoord, this.zCoord, facingDirection.ordinal(), 2); + } +} diff --git a/src/main/java/calclavia/lib/TileEntityUniversalStorable.java b/src/main/java/calclavia/lib/TileEntityUniversalStorable.java new file mode 100644 index 0000000..a5a1978 --- /dev/null +++ b/src/main/java/calclavia/lib/TileEntityUniversalStorable.java @@ -0,0 +1,28 @@ +package calclavia.lib; + +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; +import universalelectricity.prefab.implement.IRotatable; +import universalelectricity.prefab.tile.TileEntityElectricityStorage; + +public abstract class TileEntityUniversalStorable + extends TileEntityElectricityStorage implements IUniversalEnergyTile { + @Override + public boolean canConnect(ForgeDirection direction) { + return this instanceof IRotatable + ? direction == ForgeDirection.getOrientation(this.getBlockMetadata()) + .getOpposite() + : true; + } + + public ForgeDirection getDirection(IBlockAccess world, int x, int y, int z) { + return ForgeDirection.getOrientation(this.getBlockMetadata()); + } + + public void setDirection(World world, int x, int y, int z, + ForgeDirection facingDirection) { + this.worldObj.setBlockMetadataWithNotify( + this.xCoord, this.yCoord, this.zCoord, facingDirection.ordinal(), 2); + } +} diff --git a/src/main/java/calclavia/lib/UniversalRecipes.java b/src/main/java/calclavia/lib/UniversalRecipes.java new file mode 100644 index 0000000..198b506 --- /dev/null +++ b/src/main/java/calclavia/lib/UniversalRecipes.java @@ -0,0 +1,102 @@ +package calclavia.lib; + +import cpw.mods.fml.common.FMLLog; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import net.minecraft.item.ItemStack; +import net.minecraftforge.oredict.OreDictionary; + +public class UniversalRecipes { + public static final String PRIMARY_METAL = "ingotSteel"; + public static final String PRIMARY_PLATE = "plateSteel"; + public static final String SECONDARY_METAL = "ingotBronze"; + public static final String SECONDARY_PLATE = "plateBronze"; + public static final String CIRCUIT_T1 = "calclavia:CIRCUIT_T1"; + public static final String CIRCUIT_T2 = "calclavia:CIRCUIT_T2"; + public static final String CIRCUIT_T3 = "calclavia:CIRCUIT_T3"; + public static String ADVANCED_BATTERY = "calclavia:ADVANCED_BATTERY"; + public static String BATTERY = "calclavia:BATTERY"; + public static String BATTERY_BOX = "calclavia:BATTERY_BOX"; + public static final String WRENCH = "calclavia:WRENCH"; + public static final String WIRE = "calclavia:WIRE"; + public static final String MOTOR = "calclavia:MOTOR"; + public static boolean isInit = false; + + public static void init() { + if (!isInit) { + // TODO: WTF + // register("calclavia:CIRCUIT_T1", new Object[]{"circuitBasic", + // Items.getItem("electronicCircuit"), new + // ItemStack(Blocks.redstone_torch)}); register("calclavia:CIRCUIT_T2", + // new Object[]{"circuitAdvanced", Items.getItem("advancedCircuit"), new + // ItemStack(Items.repeater)}); register("calclavia:CIRCUIT_T3", new + // Object[]{"circuitElite", Items.getItem("iridiumPlate"), new + // ItemStack(Block.field_94346_cn)}); register(ADVANCED_BATTERY, new + // Object[]{"advancedBattery", Items.getItem("energyCrystal"), "battery", + // new ItemStack(Items.repeater)}); register(BATTERY, new + // Object[]{"battery", Items.getItem("reBattery"), new + // ItemStack(Items.repeater)}); + // register(BATTERY_BOX, new Object[]{"batteryBox", + // Items.getItem("batBox"), new ItemStack(Block.field_72105_ah)}); + // register("calclavia:WRENCH", new Object[]{"wrench", + // Items.getItem("wrench"), new ItemStack(Item.field_77708_h)}); + // register("calclavia:WIRE", new Object[]{"copperWire", + // "copperCableBlock", new ItemStack(Item.field_77767_aC)}); + // register("calclavia:MOTOR", new Object[]{"motor", + // Items.getItem("generator"), new ItemStack(Block.field_71963_Z)}); + isInit = true; + } + } + + public static void register(String name, Object... possiblities) { + Object[] arr$ = possiblities; + int len$ = possiblities.length; + + for (int i$ = 0; i$ < len$; ++i$) { + Object possiblity = arr$[i$]; + if (possiblity instanceof ItemStack) { + if (registerItemStacksToDictionary( + name, new ItemStack[] {(ItemStack)possiblity})) { + break; + } + } else if (possiblity instanceof String) { + if (registerItemStacksToDictionary(name, (String)possiblity)) { + break; + } + } else { + FMLLog.severe("Universal Recipes: Error Registering " + name, + new Object[0]); + } + } + } + + public static boolean registerItemStacksToDictionary(String name, + List itemStacks) { + boolean returnValue = false; + if (itemStacks != null && itemStacks.size() > 0) { + Iterator i$ = itemStacks.iterator(); + + while (i$.hasNext()) { + ItemStack stack = (ItemStack)i$.next(); + if (stack != null) { + OreDictionary.registerOre(name, stack); + returnValue = true; + } + } + } + + return returnValue; + } + + public static boolean + registerItemStacksToDictionary(String name, ItemStack... itemStacks) { + return registerItemStacksToDictionary(name, Arrays.asList(itemStacks)); + } + + public static boolean registerItemStacksToDictionary(String name, + String stackName) { + return registerItemStacksToDictionary( + name, (List)OreDictionary.getOres(stackName)); + } +} diff --git a/src/main/java/calclavia/lib/gui/ContainerBase.java b/src/main/java/calclavia/lib/gui/ContainerBase.java new file mode 100644 index 0000000..d2c20d4 --- /dev/null +++ b/src/main/java/calclavia/lib/gui/ContainerBase.java @@ -0,0 +1,96 @@ +package calclavia.lib.gui; + +import calclavia.lib.IPlayerUsing; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; + +public class ContainerBase extends Container { + + protected int slotCount = 0; + private IInventory inventory; + + + public ContainerBase(IInventory inventory) { + this.inventory = inventory; + this.slotCount = inventory.getSizeInventory(); + } + + public void onContainerClosed(EntityPlayer player) { + if(this.inventory instanceof IPlayerUsing) { + ((IPlayerUsing)this.inventory).getPlayersUsing().remove(player); + } + + } + + public void addPlayerInventory(EntityPlayer player) { + if(this.inventory instanceof IPlayerUsing) { + ((IPlayerUsing)this.inventory).getPlayersUsing().add(player); + } + + int var3; + for(var3 = 0; var3 < 3; ++var3) { + for(int var4 = 0; var4 < 9; ++var4) { + this.addSlotToContainer(new Slot(player.inventory, var4 + var3 * 9 + 9, 8 + var4 * 18, 135 + var3 * 18)); + } + } + + for(var3 = 0; var3 < 9; ++var3) { + this.addSlotToContainer(new Slot(player.inventory, var3, 8 + var3 * 18, 193)); + } + + } + + public ItemStack transferStackInSlot(EntityPlayer par1EntityPlayer, int slotID) { + ItemStack var2 = null; + Slot var3 = (Slot)super.inventorySlots.get(slotID); + if(var3 != null && var3.getHasStack()) { + ItemStack itemStack = var3.getStack(); + var2 = itemStack.copy(); + if(slotID >= this.slotCount) { + boolean didTry = false; + + for(int i = 0; i < this.slotCount; ++i) { + if(this.getSlot(i).isItemValid(itemStack)) { + didTry = true; + if(this.mergeItemStack(itemStack, i, i + 1, false)) { + break; + } + } + } + + if(!didTry) { + if(slotID < 27 + this.slotCount) { + if(!this.mergeItemStack(itemStack, 27 + this.slotCount, 36 + this.slotCount, false)) { + return null; + } + } else if(slotID >= 27 + this.slotCount && slotID < 36 + this.slotCount && !this.mergeItemStack(itemStack, this.slotCount, 27 + this.slotCount, false)) { + return null; + } + } + } else if(!this.mergeItemStack(itemStack, this.slotCount, 36 + this.slotCount, false)) { + return null; + } + + if(itemStack.stackSize == 0) { + var3.putStack((ItemStack)null); + } else { + var3.onSlotChanged(); + } + + if(itemStack.stackSize == var2.stackSize) { + return null; + } + + var3.onPickupFromSlot(par1EntityPlayer, itemStack); + } + + return var2; + } + + public boolean canInteractWith(EntityPlayer entityplayer) { + return this.inventory.isUseableByPlayer(entityplayer); + } +} diff --git a/src/main/java/calclavia/lib/gui/GuiContainerBase.java b/src/main/java/calclavia/lib/gui/GuiContainerBase.java new file mode 100644 index 0000000..8d2cad3 --- /dev/null +++ b/src/main/java/calclavia/lib/gui/GuiContainerBase.java @@ -0,0 +1,296 @@ +package calclavia.lib.gui; + +import calclavia.lib.Calclavia; +import java.util.HashMap; +import java.util.Map.Entry; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.gui.inventory.GuiContainer; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.inventory.Container; +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fluids.FluidStack; +import org.lwjgl.input.Keyboard; +import org.lwjgl.opengl.GL11; +import universalelectricity.core.vector.Vector2; +import universalelectricity.prefab.TranslationHelper; +import universalelectricity.prefab.vector.Region2; + +public class GuiContainerBase extends GuiContainer { + + //private static final int METER_X = 54; + public static final int METER_HEIGHT = 49; + public static final int METER_WIDTH = 14; + public static final int METER_END = 68; + public String tooltip = ""; + protected HashMap tooltips = new HashMap<>(); + protected int containerWidth; + protected int containerHeight; + + public GuiContainerBase(Container container) { + super(container); + this.ySize = 217; + } + + @Override + public void initGui() { + super.initGui(); + } + + @Override + public void onGuiClosed() { + Keyboard.enableRepeatEvents(false); + super.onGuiClosed(); + } + + @Override + protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) { + for (Entry entry : this.tooltips.entrySet()) { + if (((Region2)entry.getKey()) + .isIn(new Vector2((double)(mouseX - this.guiLeft), + (double)(mouseY - this.guiTop)))) { + this.tooltip = (String)entry.getValue(); + break; + } + } + + if (this.tooltip != null && this.tooltip != "") { + this.drawTooltip(mouseX - this.guiLeft, mouseY - this.guiTop, + (String[])Calclavia.splitStringPerWord(this.tooltip, 5) + .toArray(new String[0])); + } + + this.tooltip = ""; + } + + @Override + protected void drawGuiContainerBackgroundLayer(float var1, int x, int y) { + this.containerWidth = (this.width - this.xSize) / 2; + this.containerHeight = (this.height - this.ySize) / 2; + this.mc.renderEngine.bindTexture( + new ResourceLocation("calclavia", "textures/gui/gui_base.png")); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + this.drawTexturedModalRect(this.containerWidth, this.containerHeight, 0, 0, + this.xSize, this.ySize); + } + + protected void drawBulb(int x, int y, boolean isOn) { + this.mc.renderEngine.bindTexture( + new ResourceLocation("calclavia", "textures/gui/gui_base.png")); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + if (isOn) { + this.drawTexturedModalRect(this.containerWidth + x, + this.containerHeight + y, 161, 0, 6, 6); + } else { + this.drawTexturedModalRect(this.containerWidth + x, + this.containerHeight + y, 161, 4, 6, 6); + } + } + + protected void drawSlot(int x, int y, ItemStack itemStack) { + this.mc.renderEngine.bindTexture( + new ResourceLocation("calclavia", "textures/gui/gui_base.png")); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + this.drawTexturedModalRect(this.containerWidth + x, + this.containerHeight + y, 0, 0, 18, 18); + this.drawItemStack(itemStack, this.containerWidth + x, + this.containerHeight + y); + } + + protected void drawItemStack(ItemStack itemStack, int x, int y) { + ++x; + ++y; + GL11.glTranslatef(0.0F, 0.0F, 32.0F); + itemRender.renderItemAndEffectIntoGUI( + this.fontRendererObj, this.mc.renderEngine, itemStack, x, y); + } + + protected void drawTextWithTooltip(String textName, String format, int x, + int y, int mouseX, int mouseY) { + this.drawTextWithTooltip(textName, format, x, y, mouseX, mouseY, 4210752); + } + + protected void drawTextWithTooltip(String textName, String format, int x, + int y, int mouseX, int mouseY, int color) { + String name = TranslationHelper.getLocal("gui." + textName + ".name"); + String text = format.replaceAll("%1", name); + this.fontRendererObj.drawString(text, x, y, color); + String tooltip = TranslationHelper.getLocal("gui." + textName + ".tooltip"); + if (tooltip != null && tooltip != "" && + this.func_146978_c(x, y, (int)((double)text.length() * 4.8D), 12, + mouseX, mouseY)) { + this.tooltip = tooltip; + } + } + + protected void drawTextWithTooltip(String textName, int x, int y, int mouseX, + int mouseY) { + this.drawTextWithTooltip(textName, "%1", x, y, mouseX, mouseY); + } + + protected void drawSlot(int x, int y, GuiSlotType type, float r, float g, + float b) { + this.mc.renderEngine.bindTexture( + new ResourceLocation("calclavia", "textures/gui/gui_components.png")); + GL11.glColor4f(r, g, b, 1.0F); + this.drawTexturedModalRect(this.containerWidth + x, + this.containerHeight + y, 0, 0, 18, 18); + if (type != GuiSlotType.NONE) { + this.drawTexturedModalRect(this.containerWidth + x, + this.containerHeight + y, 0, + 18 * type.ordinal(), 18, 18); + } + } + + protected void drawSlot(int x, int y, GuiSlotType type) { + this.drawSlot(x, y, type, 1.0F, 1.0F, 1.0F); + } + + protected void drawSlot(int x, int y) { + this.drawSlot(x, y, GuiSlotType.NONE); + } + + protected void drawBar(int x, int y, float scale) { + this.mc.renderEngine.bindTexture( + new ResourceLocation("calclavia", "textures/gui/gui_components.png")); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + this.drawTexturedModalRect(this.containerWidth + x, + this.containerHeight + y, 18, 0, 22, 15); + if (scale > 0.0F) { + this.drawTexturedModalRect(this.containerWidth + x, + this.containerHeight + y, 18, 15, + 22 - (int)(scale * 22.0F), 15); + } + } + + protected void drawForce(int x, int y, float scale) { + this.mc.renderEngine.bindTexture( + new ResourceLocation("calclavia", "textures/gui/gui_components.png")); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + this.drawTexturedModalRect(this.containerWidth + x, + this.containerHeight + y, 54, 0, 107, 11); + if (scale > 0.0F) { + this.drawTexturedModalRect(this.containerWidth + x, + this.containerHeight + y, 54, 11, + (int)(scale * 107.0F), 11); + } + } + + protected void drawElectricity(int x, int y, float scale) { + this.mc.renderEngine.bindTexture( + new ResourceLocation("calclavia", "textures/gui/gui_components.png")); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + this.drawTexturedModalRect(this.containerWidth + x, + this.containerHeight + y, 54, 0, 107, 11); + if (scale > 0.0F) { + this.drawTexturedModalRect(this.containerWidth + x, + this.containerHeight + y, 54, 22, + (int)(scale * 107.0F), 11); + } + } + + protected void drawMeter(int x, int y, float scale, FluidStack liquidStack) { + this.mc.renderEngine.bindTexture( + new ResourceLocation("calclavia", "textures/gui/gui_base.png")); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + this.drawTexturedModalRect(this.containerWidth + x, + this.containerHeight + y, 40, 0, 14, 49); + this.displayGauge(this.containerWidth + x, this.containerHeight + y, 0, 0, + (int)(48.0F * scale), liquidStack); + this.mc.renderEngine.bindTexture( + new ResourceLocation("calclavia", "textures/gui/gui_base.png")); + this.drawTexturedModalRect(this.containerWidth + x, + this.containerHeight + y, 40, 98, 14, 49); + } + + public void drawTooltip(int x, int y, String... toolTips) { + if (!GuiScreen.isShiftKeyDown()) { + GL11.glDisable('\u803a'); + RenderHelper.disableStandardItemLighting(); + GL11.glDisable(2896); + GL11.glDisable(2929); + if (toolTips != null) { + int var5 = 0; + + int var6; + int var7; + for (var6 = 0; var6 < toolTips.length; ++var6) { + var7 = this.fontRendererObj.getStringWidth(toolTips[var6]); + if (var7 > var5) { + var5 = var7; + } + } + + var6 = x + 12; + var7 = y - 12; + int var9 = 8; + if (toolTips.length > 1) { + var9 += 2 + (toolTips.length - 1) * 10; + } + + if (this.guiTop + var7 + var9 + 6 > this.height) { + var7 = this.height - var9 - this.guiTop - 6; + } + + super.zLevel = 300.0F; + int var10 = -267386864; + this.drawGradientRect(var6 - 3, var7 - 4, var6 + var5 + 3, var7 - 3, + var10, var10); + this.drawGradientRect(var6 - 3, var7 + var9 + 3, var6 + var5 + 3, + var7 + var9 + 4, var10, var10); + this.drawGradientRect(var6 - 3, var7 - 3, var6 + var5 + 3, + var7 + var9 + 3, var10, var10); + this.drawGradientRect(var6 - 4, var7 - 3, var6 - 3, var7 + var9 + 3, + var10, var10); + this.drawGradientRect(var6 + var5 + 3, var7 - 3, var6 + var5 + 4, + var7 + var9 + 3, var10, var10); + int var11 = 1347420415; + int var12 = (var11 & 16711422) >> 1 | var11 & -16777216; + this.drawGradientRect(var6 - 3, var7 - 3 + 1, var6 - 3 + 1, + var7 + var9 + 3 - 1, var11, var12); + this.drawGradientRect(var6 + var5 + 2, var7 - 3 + 1, var6 + var5 + 3, + var7 + var9 + 3 - 1, var11, var12); + this.drawGradientRect(var6 - 3, var7 - 3, var6 + var5 + 3, var7 - 3 + 1, + var11, var11); + this.drawGradientRect(var6 - 3, var7 + var9 + 2, var6 + var5 + 3, + var7 + var9 + 3, var12, var12); + + for (int var13 = 0; var13 < toolTips.length; ++var13) { + String var14 = toolTips[var13]; + this.fontRendererObj.drawStringWithShadow(var14, var6, var7, -1); + var7 += 10; + } + + super.zLevel = 0.0F; + GL11.glEnable(2929); + GL11.glEnable(2896); + RenderHelper.enableGUIStandardItemLighting(); + GL11.glEnable('\u803a'); + } + } + } + + protected void displayGauge(int j, int k, int line, int col, int squaled, + FluidStack liquid) { + if (liquid != null) { + int start = 0; + IIcon liquidIcon = liquid.getFluid().getIcon(); + + int x1; + do { + if (squaled > 16) { + x1 = 16; + squaled -= 16; + } else { + x1 = squaled; + squaled = 0; + } + + this.drawTexturedModelRectFromIcon(j + col, k + line + 58 - x1 - start, + liquidIcon, 16, 16 - (16 - x1)); + start += 16; + } while (x1 != 0 && squaled != 0); + } + } +} diff --git a/src/main/java/calclavia/lib/gui/GuiScreenBase.java b/src/main/java/calclavia/lib/gui/GuiScreenBase.java new file mode 100644 index 0000000..10e570a --- /dev/null +++ b/src/main/java/calclavia/lib/gui/GuiScreenBase.java @@ -0,0 +1,271 @@ +package calclavia.lib.gui; + +import calclavia.lib.Calclavia; +import java.util.HashMap; +import java.util.Map.Entry; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.util.IIcon; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fluids.FluidStack; +import org.lwjgl.opengl.GL11; +import universalelectricity.core.vector.Vector2; +import universalelectricity.prefab.GuiBase; +import universalelectricity.prefab.TranslationHelper; +import universalelectricity.prefab.vector.Region2; + +public class GuiScreenBase extends GuiBase { + + // private static final int METER_X = 54; + public static final int METER_HEIGHT = 49; + public static final int METER_WIDTH = 14; + public static final int METER_END = 68; + public String tooltip = ""; + protected HashMap tooltips = new HashMap<>(); + protected int containerWidth; + protected int containerHeight; + + public GuiScreenBase() { super.ySize = 217; } + + @Override + protected void drawForegroundLayer(int mouseX, int mouseY, float var1) { + for (Entry entry : this.tooltips.entrySet()) { + if (((Region2)entry.getKey()) + .isIn(new Vector2((double)(mouseX - this.guiLeft), + (double)(mouseY - this.guiTop)))) { + this.tooltip = (String)entry.getValue(); + break; + } + } + + if (this.tooltip != null && this.tooltip != "") { + this.drawTooltip(mouseX - this.guiLeft, mouseY - this.guiTop, + (String[])Calclavia.splitStringPerWord(this.tooltip, 5) + .toArray(new String[0])); + } + + this.tooltip = ""; + } + + @Override + protected void drawBackgroundLayer(int x, int y, float var1) { + this.containerWidth = (this.width - this.xSize) / 2; + this.containerHeight = (this.height - this.ySize) / 2; + this.mc.renderEngine.bindTexture( + new ResourceLocation("calclavia", "textures/gui/gui_base.png")); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + this.drawTexturedModalRect(this.containerWidth, this.containerHeight, 0, 0, + this.xSize, this.ySize); + } + + protected void drawBulb(int x, int y, boolean isOn) { + this.mc.renderEngine.bindTexture( + new ResourceLocation("calclavia", "textures/gui/gui_base.png")); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + if (isOn) { + this.drawTexturedModalRect(this.containerWidth + x, + this.containerHeight + y, 161, 0, 6, 6); + } else { + this.drawTexturedModalRect(this.containerWidth + x, + this.containerHeight + y, 161, 4, 6, 6); + } + } + + protected void drawTextWithTooltip(String textName, String format, int x, + int y, int mouseX, int mouseY) { + this.drawTextWithTooltip(textName, format, x, y, mouseX, mouseY, 4210752); + } + + protected void drawTextWithTooltip(String textName, String format, int x, + int y, int mouseX, int mouseY, int color) { + String name = TranslationHelper.getLocal("gui." + textName + ".name"); + String text = format.replaceAll("%1", name); + this.fontRendererObj.drawString(text, x, y, color); + String tooltip = TranslationHelper.getLocal("gui." + textName + ".tooltip"); + if (tooltip != null && tooltip != "" && + this.isPointInRegion(x, y, (int)((double)text.length() * 4.8D), 12, + mouseX, mouseY)) { + this.tooltip = tooltip; + } + } + + protected boolean isPointInRegion(int par1, int par2, int par3, int par4, + int par5, int par6) { + int k1 = super.guiLeft; + int l1 = super.guiTop; + par5 -= k1; + par6 -= l1; + return par5 >= par1 - 1 && par5 < par1 + par3 + 1 && par6 >= par2 - 1 && + par6 < par2 + par4 + 1; + } + + protected void drawTextWithTooltip(String textName, int x, int y, int mouseX, + int mouseY) { + this.drawTextWithTooltip(textName, "%1", x, y, mouseX, mouseY); + } + + protected void drawSlot(int x, int y, GuiSlotType type, float r, float g, + float b) { + this.mc.renderEngine.bindTexture( + new ResourceLocation("calclavia", "textures/gui/gui_empty.png")); + GL11.glColor4f(r, g, b, 1.0F); + this.drawTexturedModalRect(this.containerWidth + x, + this.containerHeight + y, 0, 0, 18, 18); + if (type != GuiSlotType.NONE) { + this.drawTexturedModalRect(this.containerWidth + x, + this.containerHeight + y, 0, + 18 * type.ordinal(), 18, 18); + } + } + + protected void drawSlot(int x, int y, GuiSlotType type) { + this.drawSlot(x, y, type, 1.0F, 1.0F, 1.0F); + } + + protected void drawSlot(int x, int y) { + this.drawSlot(x, y, GuiSlotType.NONE); + } + + protected void drawBar(int x, int y, float scale) { + this.mc.renderEngine.bindTexture( + new ResourceLocation("calclavia", "textures/gui/gui_empty.png")); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + this.drawTexturedModalRect(this.containerWidth + x, + this.containerHeight + y, 18, 0, 22, 15); + if (scale > 0.0F) { + this.drawTexturedModalRect(this.containerWidth + x, + this.containerHeight + y, 18, 15, + 22 - (int)(scale * 22.0F), 15); + } + } + + protected void drawForce(int x, int y, float scale) { + this.mc.renderEngine.bindTexture( + new ResourceLocation("calclavia", "textures/gui/gui_empty.png")); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + this.drawTexturedModalRect(this.containerWidth + x, + this.containerHeight + y, 54, 0, 107, 11); + if (scale > 0.0F) { + this.drawTexturedModalRect(this.containerWidth + x, + this.containerHeight + y, 54, 11, + (int)(scale * 107.0F), 11); + } + } + + protected void drawElectricity(int x, int y, float scale) { + this.mc.renderEngine.bindTexture( + new ResourceLocation("calclavia", "textures/gui/gui_empty.png")); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + this.drawTexturedModalRect(this.containerWidth + x, + this.containerHeight + y, 54, 0, 107, 11); + if (scale > 0.0F) { + this.drawTexturedModalRect(this.containerWidth + x, + this.containerHeight + y, 54, 22, + (int)(scale * 107.0F), 11); + } + } + + protected void drawMeter(int x, int y, float scale, FluidStack liquidStack) { + this.mc.renderEngine.bindTexture( + new ResourceLocation("calclavia", "textures/gui/gui_empty.png")); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + this.drawTexturedModalRect(this.containerWidth + x, + this.containerHeight + y, 40, 0, 14, 49); + this.displayGauge(this.containerWidth + x, this.containerHeight + y, 0, 0, + (int)(48.0F * scale), liquidStack); + this.mc.renderEngine.bindTexture( + new ResourceLocation("calclavia", "textures/gui/gui_empty.png")); + this.drawTexturedModalRect(this.containerWidth + x, + this.containerHeight + y, 40, 98, 14, 49); + } + + public void drawTooltip(int x, int y, String... toolTips) { + if (!GuiScreen.isShiftKeyDown()) { + GL11.glDisable('\u803a'); + RenderHelper.disableStandardItemLighting(); + GL11.glDisable(2896); + GL11.glDisable(2929); + if (toolTips != null) { + int var5 = 0; + + int var6; + int var7; + for (var6 = 0; var6 < toolTips.length; ++var6) { + var7 = this.fontRendererObj.getStringWidth(toolTips[var6]); + if (var7 > var5) { + var5 = var7; + } + } + + var6 = x + 12; + var7 = y - 12; + int var9 = 8; + if (toolTips.length > 1) { + var9 += 2 + (toolTips.length - 1) * 10; + } + + if (super.guiTop + var7 + var9 + 6 > this.height) { + var7 = this.height - var9 - super.guiTop - 6; + } + + super.zLevel = 300.0F; + int var10 = -267386864; + this.drawGradientRect(var6 - 3, var7 - 4, var6 + var5 + 3, var7 - 3, + var10, var10); + this.drawGradientRect(var6 - 3, var7 + var9 + 3, var6 + var5 + 3, + var7 + var9 + 4, var10, var10); + this.drawGradientRect(var6 - 3, var7 - 3, var6 + var5 + 3, + var7 + var9 + 3, var10, var10); + this.drawGradientRect(var6 - 4, var7 - 3, var6 - 3, var7 + var9 + 3, + var10, var10); + this.drawGradientRect(var6 + var5 + 3, var7 - 3, var6 + var5 + 4, + var7 + var9 + 3, var10, var10); + int var11 = 1347420415; + int var12 = (var11 & 16711422) >> 1 | var11 & -16777216; + this.drawGradientRect(var6 - 3, var7 - 3 + 1, var6 - 3 + 1, + var7 + var9 + 3 - 1, var11, var12); + this.drawGradientRect(var6 + var5 + 2, var7 - 3 + 1, var6 + var5 + 3, + var7 + var9 + 3 - 1, var11, var12); + this.drawGradientRect(var6 - 3, var7 - 3, var6 + var5 + 3, var7 - 3 + 1, + var11, var11); + this.drawGradientRect(var6 - 3, var7 + var9 + 2, var6 + var5 + 3, + var7 + var9 + 3, var12, var12); + + for (int var13 = 0; var13 < toolTips.length; ++var13) { + String var14 = toolTips[var13]; + this.fontRendererObj.drawStringWithShadow(var14, var6, var7, -1); + var7 += 10; + } + + super.zLevel = 0.0F; + GL11.glEnable(2929); + GL11.glEnable(2896); + RenderHelper.enableGUIStandardItemLighting(); + GL11.glEnable('\u803a'); + } + } + } + + protected void displayGauge(int j, int k, int line, int col, int squaled, + FluidStack liquid) { + if (liquid != null) { + int start = 0; + IIcon liquidIcon = liquid.getFluid().getIcon(); + + int x1; + do { + if (squaled > 16) { + x1 = 16; + squaled -= 16; + } else { + x1 = squaled; + squaled = 0; + } + + this.drawTexturedModelRectFromIcon(j + col, k + line + 58 - x1 - start, + liquidIcon, 16, 16 - (16 - x1)); + start += 16; + } while (x1 != 0 && squaled != 0); + } + } +} diff --git a/src/main/java/calclavia/lib/gui/GuiSlotType.java b/src/main/java/calclavia/lib/gui/GuiSlotType.java new file mode 100644 index 0000000..02757f0 --- /dev/null +++ b/src/main/java/calclavia/lib/gui/GuiSlotType.java @@ -0,0 +1,23 @@ +package calclavia.lib.gui; + + +public enum GuiSlotType { + + NONE("NONE", 0), + BATTERY("BATTERY", 1), + LIQUID("LIQUID", 2), + ARR_UP("ARR_UP", 3), + ARR_DOWN("ARR_DOWN", 4), + ARR_LEFT("ARR_LEFT", 5), + ARR_RIGHT("ARR_RIGHT", 6), + ARR_UP_RIGHT("ARR_UP_RIGHT", 7), + ARR_UP_LEFT("ARR_UP_LEFT", 8), + ARR_DOWN_LEFT("ARR_DOWN_LEFT", 9), + ARR_DOWN_RIGHT("ARR_DOWN_RIGHT", 10); + // $FF: synthetic field + private static final GuiSlotType[] $VALUES = new GuiSlotType[]{NONE, BATTERY, LIQUID, ARR_UP, ARR_DOWN, ARR_LEFT, ARR_RIGHT, ARR_UP_RIGHT, ARR_UP_LEFT, ARR_DOWN_LEFT, ARR_DOWN_RIGHT}; + + + private GuiSlotType(String var1, int var2) {} + +} diff --git a/src/main/java/calclavia/lib/render/CalclaviaRenderHelper.java b/src/main/java/calclavia/lib/render/CalclaviaRenderHelper.java new file mode 100644 index 0000000..120743d --- /dev/null +++ b/src/main/java/calclavia/lib/render/CalclaviaRenderHelper.java @@ -0,0 +1,111 @@ +package calclavia.lib.render; + +import net.minecraft.block.Block; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.RenderBlocks; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.entity.RenderManager; +import org.lwjgl.opengl.GL11; + +public class CalclaviaRenderHelper { + + public static void enableBlending() { + GL11.glShadeModel(7425); + GL11.glEnable(3042); + GL11.glBlendFunc(770, 771); + } + + public static void disableBlending() { + GL11.glShadeModel(7424); + GL11.glDisable(2848); + GL11.glDisable(2881); + GL11.glDisable(3042); + } + + public static void enableLighting() { + RenderHelper.enableStandardItemLighting(); + } + + public static void disableLighting() { + RenderHelper.disableStandardItemLighting(); + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, 240.0F, 240.0F); + } + + public static void renderNormalBlockAsItem(Block block, int metadata, RenderBlocks renderer) { + Tessellator tessellator = Tessellator.instance; + block.setBlockBoundsForItemRender(); + renderer.setRenderBoundsFromBlock(block); + GL11.glRotatef(90.0F, 0.0F, 1.0F, 0.0F); + GL11.glTranslatef(-0.5F, -0.5F, -0.5F); + tessellator.startDrawingQuads(); + tessellator.setNormal(0.0F, -1.0F, 0.0F); + renderer.renderFaceYNeg(block, 0.0D, 0.0D, 0.0D, renderer.getBlockIconFromSideAndMetadata(block, 0, metadata)); + tessellator.draw(); + tessellator.startDrawingQuads(); + tessellator.setNormal(0.0F, 1.0F, 0.0F); + renderer.renderFaceYPos(block, 0.0D, 0.0D, 0.0D, renderer.getBlockIconFromSideAndMetadata(block, 1, metadata)); + tessellator.draw(); + tessellator.startDrawingQuads(); + tessellator.setNormal(0.0F, 0.0F, -1.0F); + renderer.renderFaceZNeg(block, 0.0D, 0.0D, 0.0D, renderer.getBlockIconFromSideAndMetadata(block, 2, metadata)); + tessellator.draw(); + tessellator.startDrawingQuads(); + tessellator.setNormal(0.0F, 0.0F, 1.0F); + renderer.renderFaceZPos(block, 0.0D, 0.0D, 0.0D, renderer.getBlockIconFromSideAndMetadata(block, 3, metadata)); + tessellator.draw(); + tessellator.startDrawingQuads(); + tessellator.setNormal(-1.0F, 0.0F, 0.0F); + renderer.renderFaceXNeg(block, 0.0D, 0.0D, 0.0D, renderer.getBlockIconFromSideAndMetadata(block, 4, metadata)); + tessellator.draw(); + tessellator.startDrawingQuads(); + tessellator.setNormal(1.0F, 0.0F, 0.0F); + renderer.renderFaceXPos(block, 0.0D, 0.0D, 0.0D, renderer.getBlockIconFromSideAndMetadata(block, 5, metadata)); + tessellator.draw(); + GL11.glTranslatef(0.5F, 0.5F, 0.5F); + } + + public static void renderFloatingText(String text, float x, float y, float z) { + renderFloatingText(text, x, y, z, 16777215); + } + + public static void renderFloatingText(String text, float x, float y, float z, int color) { + RenderManager renderManager = RenderManager.instance; + FontRenderer fontRenderer = renderManager.getFontRenderer(); + float scale = 0.027F; + GL11.glColor4f(1.0F, 1.0F, 1.0F, 0.5F); + GL11.glPushMatrix(); + GL11.glTranslatef(x + 0.0F, y + 2.3F, z); + GL11.glNormal3f(0.0F, 1.0F, 0.0F); + GL11.glRotatef(-renderManager.playerViewY, 0.0F, 1.0F, 0.0F); + GL11.glRotatef(renderManager.playerViewX, 1.0F, 0.0F, 0.0F); + GL11.glScalef(-scale, -scale, scale); + GL11.glDisable(2896); + GL11.glDepthMask(false); + GL11.glDisable(2929); + GL11.glEnable(3042); + GL11.glBlendFunc(770, 771); + Tessellator tessellator = Tessellator.instance; + byte yOffset = 0; + GL11.glDisable(3553); + tessellator.startDrawingQuads(); + int stringMiddle = fontRenderer.getStringWidth(text) / 2; + tessellator.setColorRGBA_F(0.0F, 0.0F, 0.0F, 0.5F); + tessellator.addVertex((double)(-stringMiddle - 1), (double)(-1 + yOffset), 0.0D); + tessellator.addVertex((double)(-stringMiddle - 1), (double)(8 + yOffset), 0.0D); + tessellator.addVertex((double)(stringMiddle + 1), (double)(8 + yOffset), 0.0D); + tessellator.addVertex((double)(stringMiddle + 1), (double)(-1 + yOffset), 0.0D); + tessellator.draw(); + GL11.glEnable(3553); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 0.5F); + fontRenderer.drawString(text, -fontRenderer.getStringWidth(text) / 2, yOffset, color); + GL11.glEnable(2929); + GL11.glDepthMask(true); + fontRenderer.drawString(text, -fontRenderer.getStringWidth(text) / 2, yOffset, color); + GL11.glEnable(2896); + GL11.glDisable(3042); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + GL11.glPopMatrix(); + } +} diff --git a/src/main/java/calclavia/lib/render/ITagRender.java b/src/main/java/calclavia/lib/render/ITagRender.java new file mode 100644 index 0000000..dad2bb7 --- /dev/null +++ b/src/main/java/calclavia/lib/render/ITagRender.java @@ -0,0 +1,9 @@ +package calclavia.lib.render; + +import java.util.HashMap; +import net.minecraft.entity.player.EntityPlayer; + +public interface ITagRender { + + float addInformation(HashMap var1, EntityPlayer var2); +} diff --git a/src/main/java/calclavia/lib/render/RenderTaggedTile.java b/src/main/java/calclavia/lib/render/RenderTaggedTile.java new file mode 100644 index 0000000..bd1c55c --- /dev/null +++ b/src/main/java/calclavia/lib/render/RenderTaggedTile.java @@ -0,0 +1,64 @@ +package calclavia.lib.render; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map.Entry; +import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.EntityClientPlayerMP; +import net.minecraft.client.renderer.entity.RendererLivingEntity; +import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.MovingObjectPosition; + +@SideOnly(Side.CLIENT) +public abstract class RenderTaggedTile extends TileEntitySpecialRenderer { + @Override + public void renderTileEntityAt(TileEntity t, double x, double y, double z, + float f) { + if (t != null && t instanceof ITagRender && + this.getPlayer().getDistance((double)t.xCoord, (double)t.yCoord, + (double)t.zCoord) <= + (double)RendererLivingEntity.NAME_TAG_RANGE) { + HashMap tags = new HashMap(); + float height = ((ITagRender)t).addInformation(tags, this.getPlayer()); + EntityClientPlayerMP player = Minecraft.getMinecraft().thePlayer; + if (player.ridingEntity == null) { + MovingObjectPosition objectPosition = player.rayTrace(8.0D, 1.0F); + if (objectPosition != null) { + boolean isLooking = false; + + for (int it = 0; (float)it < height; ++it) { + if (objectPosition.blockX == t.xCoord && + objectPosition.blockY == t.yCoord + it && + objectPosition.blockZ == t.zCoord) { + isLooking = true; + } + } + + if (isLooking) { + Iterator var17 = tags.entrySet().iterator(); + + for (int i = 0; var17.hasNext(); ++i) { + Entry entry = (Entry)var17.next(); + if (entry.getKey() != null) { + CalclaviaRenderHelper.renderFloatingText( + (String)entry.getKey(), (float)x + 0.5F, + (float)y + (float)i * 0.25F - 2.0F + height, + (float)z + 0.5F, ((Integer)entry.getValue()).intValue()); + } + } + } + } + } + } + } + + public EntityPlayer getPlayer() { + EntityLivingBase entity = this.field_147501_a.field_147551_g; + return entity instanceof EntityPlayer ? (EntityPlayer)entity : null; + } +} diff --git a/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java b/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java new file mode 100755 index 0000000..4f84caa --- /dev/null +++ b/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java @@ -0,0 +1,315 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2015. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +package dan200.computercraft.api; + +import dan200.computercraft.api.filesystem.IMount; +import dan200.computercraft.api.filesystem.IWritableMount; +import dan200.computercraft.api.media.IMediaProvider; +import dan200.computercraft.api.peripheral.IPeripheralProvider; +import dan200.computercraft.api.permissions.ITurtlePermissionProvider; +import dan200.computercraft.api.redstone.IBundledRedstoneProvider; +import dan200.computercraft.api.turtle.ITurtleUpgrade; +import net.minecraft.world.World; + +import java.lang.reflect.Method; + +/** + * The static entry point to the ComputerCraft API. + * Members in this class must be called after mod_ComputerCraft has been initialised, + * but may be called before it is fully loaded. + */ +public final class ComputerCraftAPI +{ + public static boolean isInstalled() + { + findCC(); + return computerCraft != null; + } + + public static String getInstalledVersion() + { + findCC(); + if( computerCraft_getVersion != null ) + { + try { + return (String)computerCraft_getVersion.invoke( null ); + } catch (Exception e) { + // It failed + } + } + return ""; + } + + public static String getAPIVersion() + { + return "1.75"; + } + + /** + * Creates a numbered directory in a subfolder of the save directory for a given world, and returns that number.
+ * Use in conjuction with createSaveDirMount() to create a unique place for your peripherals or media items to store files.
+ * @param world The world for which the save dir should be created. This should be the serverside world object. + * @param parentSubPath The folder path within the save directory where the new directory should be created. eg: "computercraft/disk" + * @return The numerical value of the name of the new folder, or -1 if the folder could not be created for some reason.
+ * eg: if createUniqueNumberedSaveDir( world, "computer/disk" ) was called returns 42, then "computer/disk/42" is now available for writing. + * @see #createSaveDirMount(World, String, long) + */ + public static int createUniqueNumberedSaveDir( World world, String parentSubPath ) + { + findCC(); + if( computerCraft_createUniqueNumberedSaveDir != null ) + { + try { + return (Integer)computerCraft_createUniqueNumberedSaveDir.invoke( null, world, parentSubPath ); + } catch (Exception e) { + // It failed + } + } + return -1; + } + + /** + * Creates a file system mount that maps to a subfolder of the save directory for a given world, and returns it.
+ * Use in conjuction with IComputerAccess.mount() or IComputerAccess.mountWritable() to mount a folder from the + * users save directory onto a computers file system.
+ * @param world The world for which the save dir can be found. This should be the serverside world object. + * @param subPath The folder path within the save directory that the mount should map to. eg: "computer/disk/42".
+ * Use createUniqueNumberedSaveDir() to create a new numbered folder to use. + * @param capacity The ammount of data that can be stored in the directory before it fills up, in bytes. + * @return The mount, or null if it could be created for some reason. Use IComputerAccess.mount() or IComputerAccess.mountWritable() + * to mount this on a Computers' file system. + * @see #createUniqueNumberedSaveDir(World, String) + * @see dan200.computercraft.api.peripheral.IComputerAccess#mount(String, dan200.computercraft.api.filesystem.IMount) + * @see dan200.computercraft.api.peripheral.IComputerAccess#mountWritable(String, dan200.computercraft.api.filesystem.IWritableMount) + * @see dan200.computercraft.api.filesystem.IMount + * @see IWritableMount + */ + public static IWritableMount createSaveDirMount( World world, String subPath, long capacity ) + { + findCC(); + if( computerCraft_createSaveDirMount != null ) + { + try { + return (IWritableMount)computerCraft_createSaveDirMount.invoke( null, world, subPath, capacity ); + } catch (Exception e){ + // It failed + } + } + return null; + } + + /** + * Creates a file system mount to a resource folder, and returns it.
+ * Use in conjuction with IComputerAccess.mount() or IComputerAccess.mountWritable() to mount a resource folder onto a computers file system.
+ * The files in this mount will be a combination of files in the specified mod jar, and resource packs that contain resources with the same domain and path.
+ * @param modClass A class in whose jar to look first for the resources to mount. Using your main mod class is recommended. eg: MyMod.class + * @param domain The domain under which to look for resources. eg: "mymod" + * @param subPath The domain under which to look for resources. eg: "mymod/lua/myfiles" + * @return The mount, or null if it could be created for some reason. Use IComputerAccess.mount() or IComputerAccess.mountWritable() + * to mount this on a Computers' file system. + * @see dan200.computercraft.api.peripheral.IComputerAccess#mount(String, dan200.computercraft.api.filesystem.IMount) + * @see dan200.computercraft.api.peripheral.IComputerAccess#mountWritable(String, IWritableMount) + * @see dan200.computercraft.api.filesystem.IMount + */ + public static IMount createResourceMount( Class modClass, String domain, String subPath ) + { + findCC(); + if( computerCraft_createResourceMount != null ) + { + try { + return (IMount)computerCraft_createResourceMount.invoke( null, modClass, domain, subPath ); + } catch (Exception e){ + // It failed + } + } + return null; + } + + /** + * Registers a peripheral handler to convert blocks into IPeripheral implementations. + * @see dan200.computercraft.api.peripheral.IPeripheral + * @see dan200.computercraft.api.peripheral.IPeripheralProvider + */ + public static void registerPeripheralProvider( IPeripheralProvider handler ) + { + findCC(); + if ( computerCraft_registerPeripheralProvider != null) + { + try { + computerCraft_registerPeripheralProvider.invoke( null, handler ); + } catch (Exception e){ + // It failed + } + } + } + + /** + * Registers a new turtle turtle for use in ComputerCraft. After calling this, + * users should be able to craft Turtles with your new turtle. It is recommended to call + * this during the load() method of your mod. + * @see dan200.computercraft.api.turtle.ITurtleUpgrade + */ + public static void registerTurtleUpgrade( ITurtleUpgrade upgrade ) + { + if( upgrade != null ) + { + findCC(); + if( computerCraft_registerTurtleUpgrade != null ) + { + try { + computerCraft_registerTurtleUpgrade.invoke( null, upgrade ); + } catch( Exception e ) { + // It failed + } + } + } + } + + /** + * Registers a bundled redstone handler to provide bundled redstone output for blocks + * @see dan200.computercraft.api.redstone.IBundledRedstoneProvider + */ + public static void registerBundledRedstoneProvider( IBundledRedstoneProvider handler ) + { + findCC(); + if( computerCraft_registerBundledRedstoneProvider != null ) + { + try { + computerCraft_registerBundledRedstoneProvider.invoke( null, handler ); + } catch (Exception e) { + // It failed + } + } + } + + /** + * If there is a Computer or Turtle at a certain position in the world, get it's bundled redstone output. + * @see dan200.computercraft.api.redstone.IBundledRedstoneProvider + * @return If there is a block capable of emitting bundled redstone at the location, it's signal (0-65535) will be returned. + * If there is no block capable of emitting bundled redstone at the location, -1 will be returned. + */ + public static int getBundledRedstoneOutput( World world, int x, int y, int z, int side ) + { + findCC(); + if( computerCraft_getDefaultBundledRedstoneOutput != null ) + { + try { + return (Integer)computerCraft_getDefaultBundledRedstoneOutput.invoke( null, world, x, y, z, side ); + } catch (Exception e){ + // It failed + } + } + return -1; + } + + /** + * Registers a media handler to provide IMedia implementations for Items + * @see dan200.computercraft.api.media.IMediaProvider + */ + public static void registerMediaProvider( IMediaProvider handler ) + { + findCC(); + if( computerCraft_registerMediaProvider != null ) + { + try { + computerCraft_registerMediaProvider.invoke( null, handler ); + } catch (Exception e){ + // It failed + } + } + } + + /** + * Registers a permission handler to restrict where turtles can move or build + * @see dan200.computercraft.api.permissions.ITurtlePermissionProvider + */ + public static void registerPermissionProvider( ITurtlePermissionProvider handler ) + { + findCC(); + if( computerCraft_registerPermissionProvider != null ) + { + try { + computerCraft_registerPermissionProvider.invoke( null, handler ); + } catch (Exception e) { + // It failed + } + } + } + + // The functions below here are private, and are used to interface with the non-API ComputerCraft classes. + // Reflection is used here so you can develop your mod without decompiling ComputerCraft and including + // it in your solution, and so your mod won't crash if ComputerCraft is installed. + + private static void findCC() + { + if( !ccSearched ) { + try { + computerCraft = Class.forName( "dan200.computercraft.ComputerCraft" ); + computerCraft_getVersion = findCCMethod( "getVersion", new Class[]{ + } ); + computerCraft_createUniqueNumberedSaveDir = findCCMethod( "createUniqueNumberedSaveDir", new Class[]{ + World.class, String.class + } ); + computerCraft_createSaveDirMount = findCCMethod( "createSaveDirMount", new Class[] { + World.class, String.class, Long.TYPE + } ); + computerCraft_createResourceMount = findCCMethod( "createResourceMount", new Class[] { + Class.class, String.class, String.class + } ); + computerCraft_registerPeripheralProvider = findCCMethod( "registerPeripheralProvider", new Class[] { + IPeripheralProvider.class + } ); + computerCraft_registerTurtleUpgrade = findCCMethod( "registerTurtleUpgrade", new Class[] { + ITurtleUpgrade.class + } ); + computerCraft_registerBundledRedstoneProvider = findCCMethod( "registerBundledRedstoneProvider", new Class[] { + IBundledRedstoneProvider.class + } ); + computerCraft_getDefaultBundledRedstoneOutput = findCCMethod( "getDefaultBundledRedstoneOutput", new Class[] { + World.class, Integer.TYPE, Integer.TYPE, Integer.TYPE, Integer.TYPE + } ); + computerCraft_registerMediaProvider = findCCMethod( "registerMediaProvider", new Class[] { + IMediaProvider.class + } ); + computerCraft_registerPermissionProvider = findCCMethod( "registerPermissionProvider", new Class[] { + ITurtlePermissionProvider.class + } ); + } catch( Exception e ) { + System.out.println( "ComputerCraftAPI: ComputerCraft not found." ); + } finally { + ccSearched = true; + } + } + } + + private static Method findCCMethod( String name, Class[] args ) + { + try { + if( computerCraft != null ) + { + return computerCraft.getMethod( name, args ); + } + return null; + } catch( NoSuchMethodException e ) { + System.out.println( "ComputerCraftAPI: ComputerCraft method " + name + " not found." ); + return null; + } + } + + private static boolean ccSearched = false; + private static Class computerCraft = null; + private static Method computerCraft_getVersion = null; + private static Method computerCraft_createUniqueNumberedSaveDir = null; + private static Method computerCraft_createSaveDirMount = null; + private static Method computerCraft_createResourceMount = null; + private static Method computerCraft_registerPeripheralProvider = null; + private static Method computerCraft_registerTurtleUpgrade = null; + private static Method computerCraft_registerBundledRedstoneProvider = null; + private static Method computerCraft_getDefaultBundledRedstoneOutput = null; + private static Method computerCraft_registerMediaProvider = null; + private static Method computerCraft_registerPermissionProvider = null; +} diff --git a/src/main/java/dan200/computercraft/api/filesystem/IMount.java b/src/main/java/dan200/computercraft/api/filesystem/IMount.java new file mode 100755 index 0000000..cf884d9 --- /dev/null +++ b/src/main/java/dan200/computercraft/api/filesystem/IMount.java @@ -0,0 +1,57 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2015. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +package dan200.computercraft.api.filesystem; + +import java.io.IOException; +import java.io.InputStream; +import java.util.List; + +/** + * Represents a read only part of a virtual filesystem that can be mounted onto a computercraft using IComputerAccess.mount(). + * Ready made implementations of this interface can be created using ComputerCraftAPI.createSaveDirMount() or ComputerCraftAPI.createResourceMount(), or you're free to implement it yourselves! + * @see dan200.computercraft.api.ComputerCraftAPI#createSaveDirMount(World, String) + * @see dan200.computercraft.api.ComputerCraftAPI#createResourceMount(Class, String, String) + * @see dan200.computercraft.api.peripheral.IComputerAccess#mount(String, IMount) + * @see IWritableMount + */ +public interface IMount +{ + /** + * Returns whether a file with a given path exists or not. + * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram" + * @return true if the file exists, false otherwise + */ + public boolean exists( String path ) throws IOException; + + /** + * Returns whether a file with a given path is a directory or not. + * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprograms" + * @return true if the file exists and is a directory, false otherwise + */ + public boolean isDirectory( String path ) throws IOException; + + /** + * Returns the file names of all the files in a directory. + * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprograms" + * @param contents A list of strings. Add all the file names to this list + */ + public void list( String path, List contents ) throws IOException; + + /** + * Returns the size of a file with a given path, in bytes + * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram" + * @return the size of the file, in bytes + */ + public long getSize( String path ) throws IOException; + + /** + * Opens a file with a given path, and returns an inputstream representing it's contents. + * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram" + * @return a stream representing the contents of the file + */ + public InputStream openForRead( String path ) throws IOException; +} diff --git a/src/main/java/dan200/computercraft/api/filesystem/IWritableMount.java b/src/main/java/dan200/computercraft/api/filesystem/IWritableMount.java new file mode 100755 index 0000000..ffe3290 --- /dev/null +++ b/src/main/java/dan200/computercraft/api/filesystem/IWritableMount.java @@ -0,0 +1,52 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2015. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +package dan200.computercraft.api.filesystem; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * Represents a part of a virtual filesystem that can be mounted onto a computercraft using IComputerAccess.mount() or IComputerAccess.mountWritable(), that can also be written to. + * Ready made implementations of this interface can be created using ComputerCraftAPI.createSaveDirMount(), or you're free to implement it yourselves! + * @see dan200.computercraft.api.ComputerCraftAPI#createSaveDirMount(World, String) + * @see dan200.computercraft.api.peripheral.IComputerAccess#mountWritable(String, dan200.computercraft.api.filesystem.IMount) + * @see dan200.computercraft.api.filesystem.IMount + */ +public interface IWritableMount extends IMount +{ + /** + * Creates a directory at a given path inside the virtual file system. + * @param path A file path in normalised format, relative to the mount location. ie: "programs/mynewprograms" + */ + public void makeDirectory( String path ) throws IOException; + + /** + * Deletes a directory at a given path inside the virtual file system. + * @param path A file path in normalised format, relative to the mount location. ie: "programs/myoldprograms" + */ + public void delete( String path ) throws IOException; + + /** + * Opens a file with a given path, and returns an outputstream for writing to it. + * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram" + * @return a stream for writing to + */ + public OutputStream openForWrite( String path ) throws IOException; + + /** + * Opens a file with a given path, and returns an outputstream for appending to it. + * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram" + * @return a stream for writing to + */ + public OutputStream openForAppend( String path ) throws IOException; + + /** + * Get the ammount of free space on the mount, in bytes. You should decrease this value as the user writes to the mount, and write operations should fail once it reaches zero. + * @return The ammount of free space, in bytes. + */ + public long getRemainingSpace() throws IOException; +} diff --git a/src/main/java/dan200/computercraft/api/filesystem/package-info.java b/src/main/java/dan200/computercraft/api/filesystem/package-info.java new file mode 100755 index 0000000..d7a2d59 --- /dev/null +++ b/src/main/java/dan200/computercraft/api/filesystem/package-info.java @@ -0,0 +1,10 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2015. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +@API( owner="ComputerCraft", provides="ComputerCraft|API|FileSystem", apiVersion="1.75" ) +package dan200.computercraft.api.filesystem; + +import cpw.mods.fml.common.API; \ No newline at end of file diff --git a/src/main/java/dan200/computercraft/api/lua/ILuaContext.java b/src/main/java/dan200/computercraft/api/lua/ILuaContext.java new file mode 100755 index 0000000..1ffbeea --- /dev/null +++ b/src/main/java/dan200/computercraft/api/lua/ILuaContext.java @@ -0,0 +1,58 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2015. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +package dan200.computercraft.api.lua; + +/** + * An interface passed to peripherals and ILuaObjects' by computers or turtles, providing methods + * that allow the peripheral call to wait for events before returning, just like in lua. + * This is very useful if you need to signal work to be performed on the main thread, and don't want to return + * until the work has been completed. + */ +public interface ILuaContext +{ + /** + * Wait for an event to occur on the computercraft, suspending the thread until it arises. This method is exactly equivalent to os.pullEvent() in lua. + * @param filter A specific event to wait for, or null to wait for any event + * @return An object array containing the name of the event that occurred, and any event parameters + * @throws Exception If the user presses CTRL+T to terminate the current program while pullEvent() is waiting for an event, a "Terminated" exception will be thrown here. + * Do not attempt to common this exception, unless you wish to prevent termination, which is not recommended. + * @throws InterruptedException If the user shuts down or reboots the computercraft while pullEvent() is waiting for an event, InterruptedException will be thrown. This exception must not be caught or intercepted, or the computercraft will leak memory and end up in a broken state. + */ + public Object[] pullEvent( String filter ) throws LuaException, InterruptedException; + + /** + * The same as pullEvent(), except "terminated" events are ignored. Only use this if you want to prevent program termination, which is not recommended. This method is exactly equivalent to os.pullEventRaw() in lua. + * @param filter A specific event to wait for, or null to wait for any event + * @return An object array containing the name of the event that occurred, and any event parameters + * @throws InterruptedException If the user shuts down or reboots the computercraft while pullEventRaw() is waiting for an event, InterruptedException will be thrown. This exception must not be caught or intercepted, or the computercraft will leak memory and end up in a broken state. + * @see #pullEvent(String) + */ + public Object[] pullEventRaw( String filter ) throws InterruptedException; + + /** + * Yield the current coroutine with some arguments until it is resumed. This method is exactly equivalent to coroutine.yield() in lua. Use pullEvent() if you wish to wait for events. + * @param arguments An object array containing the arguments to pass to coroutine.yield() + * @return An object array containing the return values from coroutine.yield() + * @throws InterruptedException If the user shuts down or reboots the computercraft the coroutine is suspended, InterruptedException will be thrown. This exception must not be caught or intercepted, or the computercraft will leak memory and end up in a broken state. + * @see #pullEvent(String) + */ + public Object[] yield( Object[] arguments ) throws InterruptedException; + + /** + * TODO: Document me + * @param task + * @return + */ + public Object[] executeMainThreadTask( ILuaTask task ) throws LuaException, InterruptedException; + + /** + * TODO: Document me + * @param task + * @return + */ + public long issueMainThreadTask( ILuaTask task ) throws LuaException; +} diff --git a/src/main/java/dan200/computercraft/api/lua/ILuaObject.java b/src/main/java/dan200/computercraft/api/lua/ILuaObject.java new file mode 100755 index 0000000..abd8b40 --- /dev/null +++ b/src/main/java/dan200/computercraft/api/lua/ILuaObject.java @@ -0,0 +1,26 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2015. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +package dan200.computercraft.api.lua; + +/** + * An interface for representing custom objects returned by IPeripheral.callMethod() calls. + * Return objects implementing this interface to expose objects with methods to lua. + */ +public interface ILuaObject +{ + /** + * Get the names of the methods that this object implements. This works the same as IPeripheral.getMethodNames(). See that method for detailed documentation. + * @see dan200.computercraft.api.peripheral.IPeripheral#getMethodNames() + */ + public String[] getMethodNames(); + + /** + * Called when a user calls one of the methods that this object implements. This works the same as IPeripheral.callMethod(). See that method for detailed documentation. + * @see dan200.computercraft.api.peripheral.IPeripheral#callMethod(dan200.computercraft.api.peripheral.IComputerAccess, ILuaContext, int, Object[]) + */ + public Object[] callMethod( ILuaContext context, int method, Object[] arguments ) throws LuaException, InterruptedException; +} diff --git a/src/main/java/dan200/computercraft/api/lua/ILuaTask.java b/src/main/java/dan200/computercraft/api/lua/ILuaTask.java new file mode 100755 index 0000000..45feead --- /dev/null +++ b/src/main/java/dan200/computercraft/api/lua/ILuaTask.java @@ -0,0 +1,12 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2015. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +package dan200.computercraft.api.lua; + +public interface ILuaTask +{ + public Object[] execute() throws LuaException; +} diff --git a/src/main/java/dan200/computercraft/api/lua/LuaException.java b/src/main/java/dan200/computercraft/api/lua/LuaException.java new file mode 100755 index 0000000..6683c4b --- /dev/null +++ b/src/main/java/dan200/computercraft/api/lua/LuaException.java @@ -0,0 +1,36 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2015. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +package dan200.computercraft.api.lua; + +/** + * An exception representing an error in Lua, like that raised by the error() function + */ +public class LuaException extends Exception +{ + private final int m_level; + + public LuaException() + { + this( "error", 1 ); + } + + public LuaException( String message ) + { + this( message, 1 ); + } + + public LuaException( String message, int level ) + { + super( message ); + m_level = level; + } + + public int getLevel() + { + return m_level; + } +} diff --git a/src/main/java/dan200/computercraft/api/lua/package-info.java b/src/main/java/dan200/computercraft/api/lua/package-info.java new file mode 100755 index 0000000..3ea3d91 --- /dev/null +++ b/src/main/java/dan200/computercraft/api/lua/package-info.java @@ -0,0 +1,10 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2015. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +@API( owner="ComputerCraft", provides="ComputerCraft|API|Lua", apiVersion="1.75" ) +package dan200.computercraft.api.lua; + +import cpw.mods.fml.common.API; diff --git a/src/main/java/dan200/computercraft/api/media/IMedia.java b/src/main/java/dan200/computercraft/api/media/IMedia.java new file mode 100755 index 0000000..57ebc08 --- /dev/null +++ b/src/main/java/dan200/computercraft/api/media/IMedia.java @@ -0,0 +1,59 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2015. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +package dan200.computercraft.api.media; + +import dan200.computercraft.api.filesystem.IMount; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +/** + * Represents an item that can be placed in a disk drive and used by a Computer. + * Implement this interface on your Item class to allow it to be used in the drive. + */ +public interface IMedia +{ + /** + * Get a string representing the label of this item. Will be called vi disk.getLabel() in lua. + * @param stack The itemstack to inspect + * @return The label. ie: "Dan's Programs" + */ + public String getLabel( ItemStack stack ); + + /** + * Set a string representing the label of this item. Will be called vi disk.setLabel() in lua. + * @param stack The itemstack to modify. + * @param label The string to set the label to. + * @return true if the label was updated, false if the label may not be modified. + */ + public boolean setLabel( ItemStack stack, String label ); + + /** + * If this disk represents an item with audio (like a record), get the readable name of the audio track. ie: "Jonathon Coulton - Still Alive" + * @param stack The itemstack to inspect. + * @return The name, or null if this item does not represent an item with audio. + */ + public String getAudioTitle( ItemStack stack ); + + /** + * If this disk represents an item with audio (like a record), get the resource name of the audio track to play. + * @param stack The itemstack to inspect. + * @return The name, or null if this item does not represent an item with audio. + */ + public String getAudioRecordName( ItemStack stack ); + + /** + * If this disk represents an item with data (like a floppy disk), get a mount representing it's contents. This will be mounted onto the filesystem of the computercraft while the media is in the disk drive. + * @param stack The itemstack to inspect. + * @param world The world in which the item and disk drive reside. + * @return The mount, or null if this item does not represent an item with data. If the IMount returned also implements IWritableMount, it will mounted using mountWritable() + * @see dan200.computercraft.api.filesystem.IMount + * @see dan200.computercraft.api.filesystem.IWritableMount + * @see dan200.computercraft.api.ComputerCraftAPI#createSaveDirMount(World, String, long) + * @see dan200.computercraft.api.ComputerCraftAPI#createResourceMount(Class, String, String) + */ + public IMount createDataMount( ItemStack stack, World world ); +} diff --git a/src/main/java/dan200/computercraft/api/media/IMediaProvider.java b/src/main/java/dan200/computercraft/api/media/IMediaProvider.java new file mode 100755 index 0000000..c0aabd5 --- /dev/null +++ b/src/main/java/dan200/computercraft/api/media/IMediaProvider.java @@ -0,0 +1,23 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2015. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +package dan200.computercraft.api.media; + +import net.minecraft.item.ItemStack; + +/** + * This interface is used to provide IMedia implementations for ItemStack + * @see dan200.computercraft.api.ComputerCraftAPI#registerMediaProvider(IMediaProvider) + */ +public interface IMediaProvider +{ + /** + * Produce an IMedia implementation from an ItemStack. + * @see dan200.computercraft.api.ComputerCraftAPI#registerMediaProvider(IMediaProvider) + * @return an IMedia implementation, or null if the item is not something you wish to handle + */ + public IMedia getMedia( ItemStack stack ); +} diff --git a/src/main/java/dan200/computercraft/api/media/package-info.java b/src/main/java/dan200/computercraft/api/media/package-info.java new file mode 100755 index 0000000..9e2f507 --- /dev/null +++ b/src/main/java/dan200/computercraft/api/media/package-info.java @@ -0,0 +1,10 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2015. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +@API( owner="ComputerCraft", provides="ComputerCraft|API|Media", apiVersion="1.75" ) +package dan200.computercraft.api.media; + +import cpw.mods.fml.common.API; diff --git a/src/main/java/dan200/computercraft/api/package-info.java b/src/main/java/dan200/computercraft/api/package-info.java new file mode 100755 index 0000000..f3a706a --- /dev/null +++ b/src/main/java/dan200/computercraft/api/package-info.java @@ -0,0 +1,10 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2015. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +@API( owner="ComputerCraft", provides="ComputerCraft|API", apiVersion="1.75" ) +package dan200.computercraft.api; + +import cpw.mods.fml.common.API; \ No newline at end of file diff --git a/src/main/java/dan200/computercraft/api/peripheral/IComputerAccess.java b/src/main/java/dan200/computercraft/api/peripheral/IComputerAccess.java new file mode 100755 index 0000000..2458c06 --- /dev/null +++ b/src/main/java/dan200/computercraft/api/peripheral/IComputerAccess.java @@ -0,0 +1,102 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2015. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +package dan200.computercraft.api.peripheral; + +import dan200.computercraft.api.filesystem.IMount; +import dan200.computercraft.api.filesystem.IWritableMount; + +/** + * The interface passed to peripherals by computers or turtles, providing methods + * that they can call. This should not be implemented by your classes. Do not interact + * with computers except via this interface. + */ +public interface IComputerAccess +{ + /** + * Mount a mount onto the computers' file system in a read only mode.
+ * @param desiredLocation The location on the computercraft's file system where you would like the mount to be mounted. + * @param mount The mount object to mount on the computercraft. These can be obtained by calling ComputerCraftAPI.createSaveDirMount(), ComputerCraftAPI.createResourceMount() or by creating your own objects that implement the IMount interface. + * @return The location on the computercraft's file system where you the mount mounted, or null if there was already a file in the desired location. Store this value if you wish to unmount the mount later. + * @see dan200.computercraft.api.ComputerCraftAPI#createSaveDirMount(World, String) + * @see dan200.computercraft.api.ComputerCraftAPI#createResourceMount(Class, String, String) + * @see #mountWritable(String, dan200.computercraft.api.filesystem.IWritableMount) + * @see #unmount(String) + * @see dan200.computercraft.api.filesystem.IMount + */ + public String mount( String desiredLocation, IMount mount ); + + /** + * TODO: Document me + */ + public String mount( String desiredLocation, IMount mount, String driveName ); + + /** + * Mount a mount onto the computers' file system in a writable mode.
+ * @param desiredLocation The location on the computercraft's file system where you would like the mount to be mounted. + * @param mount The mount object to mount on the computercraft. These can be obtained by calling ComputerCraftAPI.createSaveDirMount() or by creating your own objects that implement the IWritableMount interface. + * @return The location on the computercraft's file system where you the mount mounted, or null if there was already a file in the desired location. Store this value if you wish to unmount the mount later. + * @see dan200.computercraft.api.ComputerCraftAPI#createSaveDirMount(World, String) + * @see dan200.computercraft.api.ComputerCraftAPI#createResourceMount(Class, String, String) + * @see #mount(String, IMount) + * @see #unmount(String) + * @see IMount + */ + public String mountWritable( String desiredLocation, IWritableMount mount ); + + /** + * TODO: Document me + */ + public String mountWritable( String desiredLocation, IWritableMount mount, String driveName ); + + /** + * Unmounts a directory previously mounted onto the computers file system by mount() or mountWritable().
+ * When a directory is unmounted, it will disappear from the computers file system, and the user will no longer be able to + * access it. All directories mounted by a mount or mountWritable are automatically unmounted when the peripheral + * is attached if they have not been explicitly unmounted. + * @param location The desired location in the computers file system of the directory to unmount. + * This must be the location of a directory previously mounted by mount() or mountWritable(), as + * indicated by their return value. + * @see #mount(String, IMount) + * @see #mountWritable(String, IWritableMount) + */ + public void unmount( String location ); + + /** + * Returns the numerical ID of this computercraft.
+ * This is the same number obtained by calling os.getComputerID() or running the "id" program from lua, + * and is guarunteed unique. This number will be positive. + * @return The identifier. + */ + public int getID(); + + /** + * Causes an event to be raised on this computercraft, which the computercraft can respond to by calling + * os.pullEvent(). This can be used to notify the computercraft when things happen in the world or to + * this peripheral. + * @param event A string identifying the type of event that has occurred, this will be + * returned as the first value from os.pullEvent(). It is recommended that you + * you choose a name that is unique, and recognisable as originating from your + * peripheral. eg: If your peripheral type is "button", a suitable event would be + * "button_pressed". + * @param arguments In addition to a name, you may pass an array of extra arguments to the event, that will + * be supplied as extra return values to os.pullEvent(). Objects in the array will be converted + * to lua data types in the same fashion as the return values of IPeripheral.callMethod().
+ * You may supply null to indicate that no arguments are to be supplied. + * @see dan200.computercraft.api.peripheral.IPeripheral#callMethod + */ + public void queueEvent( String event, Object[] arguments ); + + /** + * Get a string, unique to the computercraft, by which the computercraft refers to this peripheral. + * For directly attached peripherals this will be "left","right","front","back",etc, but + * for peripherals attached remotely it will be different. It is good practice to supply + * this string when raising events to the computercraft, so that the computercraft knows from + * which peripheral the event came. + * @return A string unique to the computercraft, but not globally. + */ + public String getAttachmentName(); +} diff --git a/src/main/java/dan200/computercraft/api/peripheral/IPeripheral.java b/src/main/java/dan200/computercraft/api/peripheral/IPeripheral.java new file mode 100755 index 0000000..a28d656 --- /dev/null +++ b/src/main/java/dan200/computercraft/api/peripheral/IPeripheral.java @@ -0,0 +1,100 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2015. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +package dan200.computercraft.api.peripheral; + +import dan200.computercraft.api.lua.ILuaContext; +import dan200.computercraft.api.lua.LuaException; + +/** + * The interface that defines a peripheral. This should be implemented by the + * TileEntity of any common that you wish to be interacted with by + * computercraft or turtle. + */ +public interface IPeripheral +{ + /** + * Should return a string that uniquely identifies this type of peripheral. + * This can be queried from lua by calling peripheral.getType() + * @return A string identifying the type of peripheral. + */ + public String getType(); + + /** + * Should return an array of strings that identify the methods that this + * peripheral exposes to Lua. This will be called once before each attachment, + * and should not change when called multiple times. + * @return An array of strings representing method names. + * @see #callMethod + */ + public String[] getMethodNames(); + + /** + * This is called when a lua program on an attached computercraft calls peripheral.call() with + * one of the methods exposed by getMethodNames().
+ *
+ * Be aware that this will be called from the ComputerCraft Lua thread, and must be thread-safe + * when interacting with minecraft objects. + * @param computer The interface to the computercraft that is making the call. Remember that multiple + * computers can be attached to a peripheral at once. + * @param context The context of the currently running lua thread. This can be used to wait for events + * or otherwise yield. + * @param method An integer identifying which of the methods from getMethodNames() the computercraft + * wishes to call. The integer indicates the index into the getMethodNames() table + * that corresponds to the string passed into peripheral.call() + * @param arguments An array of objects, representing the arguments passed into peripheral.call().
+ * Lua values of type "string" will be represented by Object type String.
+ * Lua values of type "number" will be represented by Object type Double.
+ * Lua values of type "boolean" will be represented by Object type Boolean.
+ * Lua values of any other type will be represented by a null object.
+ * This array will be empty if no arguments are passed. + * @return An array of objects, representing values you wish to return to the lua program.
+ * Integers, Doubles, Floats, Strings, Booleans and null be converted to their corresponding lua type.
+ * All other types will be converted to nil.
+ * You may return null to indicate no values should be returned. + * @throws Exception If you throw any exception from this function, a lua error will be raised with the + * same message as your exception. Use this to throw appropriate errors if the wrong + * arguments are supplied to your method. + * @see #getMethodNames + */ + public Object[] callMethod( IComputerAccess computer, ILuaContext context, int method, Object[] arguments ) throws LuaException, InterruptedException; + + /** + * Is called when canAttachToSide has returned true, and a computercraft is attaching to the peripheral. + * This will occur when a peripheral is placed next to an active computercraft, when a computercraft is turned on next to a peripheral, + * or when a turtle travels into a square next to a peripheral. + * Between calls to attach() and detach(), the attached computercraft can make method calls on the peripheral using peripheral.call(). + * This method can be used to keep track of which computers are attached to the peripheral, or to take action when attachment + * occurs.
+ *
+ * Be aware that this will be called from the ComputerCraft Lua thread, and must be thread-safe + * when interacting with minecraft objects. + * @param computer The interface to the computercraft that is being attached. Remember that multiple + * computers can be attached to a peripheral at once. + * @see #detach + */ + public void attach( IComputerAccess computer ); + + /** + * Is called when a computercraft is detaching from the peripheral. + * This will occur when a computercraft shuts down, when the peripheral is removed while attached to computers, + * or when a turtle moves away from a square attached to a peripheral. + * This method can be used to keep track of which computers are attached to the peripheral, or to take action when detachment + * occurs.
+ *
+ * Be aware that this will be called from the ComputerCraft Lua thread, and must be thread-safe + * when interacting with minecraft objects. + * @param computer The interface to the computercraft that is being detached. Remember that multiple + * computers can be attached to a peripheral at once. + * @see #detach + */ + public void detach( IComputerAccess computer ); + + /** + * TODO: Document me + */ + public boolean equals( IPeripheral other ); +} diff --git a/src/main/java/dan200/computercraft/api/peripheral/IPeripheralProvider.java b/src/main/java/dan200/computercraft/api/peripheral/IPeripheralProvider.java new file mode 100755 index 0000000..a2775f9 --- /dev/null +++ b/src/main/java/dan200/computercraft/api/peripheral/IPeripheralProvider.java @@ -0,0 +1,23 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2015. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +package dan200.computercraft.api.peripheral; + +import net.minecraft.world.World; + +/** + * This interface is used to create peripheral implementations for blocks + * @see dan200.computercraft.api.ComputerCraftAPI#registerPeripheralProvider(IPeripheralProvider) + */ +public interface IPeripheralProvider +{ + /** + * Produce an peripheral implementation from a block location. + * @see dan200.computercraft.api.ComputerCraftAPI#registerPeripheralProvider(IPeripheralProvider) + * @return a peripheral, or null if there is not a peripheral here you'd like to handle. + */ + public IPeripheral getPeripheral( World world, int x, int y, int z, int side ); +} diff --git a/src/main/java/dan200/computercraft/api/peripheral/package-info.java b/src/main/java/dan200/computercraft/api/peripheral/package-info.java new file mode 100755 index 0000000..10ea4da --- /dev/null +++ b/src/main/java/dan200/computercraft/api/peripheral/package-info.java @@ -0,0 +1,10 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2015. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +@API( owner="ComputerCraft", provides="ComputerCraft|API|Peripheral", apiVersion="1.75" ) +package dan200.computercraft.api.peripheral; + +import cpw.mods.fml.common.API; diff --git a/src/main/java/dan200/computercraft/api/permissions/ITurtlePermissionProvider.java b/src/main/java/dan200/computercraft/api/permissions/ITurtlePermissionProvider.java new file mode 100644 index 0000000..476b4fc --- /dev/null +++ b/src/main/java/dan200/computercraft/api/permissions/ITurtlePermissionProvider.java @@ -0,0 +1,19 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2015. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +package dan200.computercraft.api.permissions; + +import net.minecraft.world.World; + +/** + * This interface is used to restrict where turtles can move or build + * @see dan200.computercraft.api.ComputerCraftAPI#registerPermissionProvider(ITurtlePermissionProvider) + */ +public interface ITurtlePermissionProvider +{ + public boolean isBlockEnterable( World world, int x, int y, int z ); + public boolean isBlockEditable( World world, int x, int y, int z ); +} diff --git a/src/main/java/dan200/computercraft/api/permissions/package-info.java b/src/main/java/dan200/computercraft/api/permissions/package-info.java new file mode 100644 index 0000000..a51e7ec --- /dev/null +++ b/src/main/java/dan200/computercraft/api/permissions/package-info.java @@ -0,0 +1,10 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2015. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +@API( owner="ComputerCraft", provides="ComputerCraft|API|Permissions", apiVersion="1.75" ) +package dan200.computercraft.api.permissions; + +import cpw.mods.fml.common.API; \ No newline at end of file diff --git a/src/main/java/dan200/computercraft/api/redstone/IBundledRedstoneProvider.java b/src/main/java/dan200/computercraft/api/redstone/IBundledRedstoneProvider.java new file mode 100755 index 0000000..b85f2ef --- /dev/null +++ b/src/main/java/dan200/computercraft/api/redstone/IBundledRedstoneProvider.java @@ -0,0 +1,23 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2015. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +package dan200.computercraft.api.redstone; + +import net.minecraft.world.World; + +/** + * This interface is used to provide bundled redstone output for blocks + * @see dan200.computercraft.api.ComputerCraftAPI#registerBundledRedstoneProvider(IBundledRedstoneProvider) + */ +public interface IBundledRedstoneProvider +{ + /** + * Produce an bundled redstone output from a block location. + * @see dan200.computercraft.api.ComputerCraftAPI#registerBundledRedstoneProvider(IBundledRedstoneProvider) + * @return a number in the range 0-65535 to indicate this block is providing output, or -1 if you do not wish to handle this block + */ + public int getBundledRedstoneOutput( World world, int x, int y, int z, int side ); +} diff --git a/src/main/java/dan200/computercraft/api/redstone/package-info.java b/src/main/java/dan200/computercraft/api/redstone/package-info.java new file mode 100755 index 0000000..e01c623 --- /dev/null +++ b/src/main/java/dan200/computercraft/api/redstone/package-info.java @@ -0,0 +1,10 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2015. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +@API( owner="ComputerCraft", provides="ComputerCraft|API|Redstone", apiVersion="1.75" ) +package dan200.computercraft.api.redstone; + +import cpw.mods.fml.common.API; diff --git a/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java b/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java new file mode 100755 index 0000000..96c6159 --- /dev/null +++ b/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java @@ -0,0 +1,168 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2015. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +package dan200.computercraft.api.turtle; + +import dan200.computercraft.api.lua.ILuaContext; +import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.peripheral.IPeripheral; +import net.minecraft.inventory.IInventory; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.ChunkCoordinates; +import net.minecraft.util.Vec3; +import net.minecraft.world.World; + +/** + * The interface passed to turtle by turtles, providing methods that they can call. + * This should not be implemented by your classes. Do not interact with turtles except via this interface and ITurtleUpgrade. + */ +public interface ITurtleAccess +{ + /** + * Returns the world in which the turtle resides. + * @return the world in which the turtle resides. + */ + public World getWorld(); + + /** + * Returns a vector containing the integer co-ordinates at which the turtle resides. + * @return a vector containing the integer co-ordinates at which the turtle resides. + */ + public ChunkCoordinates getPosition(); + + /** + * TODO: Document me + */ + public boolean teleportTo( World world, int x, int y, int z ); + + /** + * Returns a vector containing the floating point co-ordinates at which the turtle is rendered. + * This will shift when the turtle is moving. + * @param f The subframe fraction + * @return a vector containing the floating point co-ordinates at which the turtle resides. + */ + public Vec3 getVisualPosition( float f ); + + /** + * TODO: Document me + */ + public float getVisualYaw( float f ); + + /** + * Returns the world direction the turtle is currently facing. + * @return the world direction the turtle is currently facing. + */ + public int getDirection(); + + /** + * TODO: Document me + */ + public void setDirection( int dir ); + + /** + * TODO: Document me + */ + public int getSelectedSlot(); + + /** + * TODO: Document me + */ + public void setSelectedSlot( int slot ); + + /** + * Sets the colour of the turtle, as if the player had dyed it with a dye item. + * @param dyeColour 0-15 to dye the turtle one of the 16 standard minecraft colours, or -1 to remove the dye from the turtle. + */ + public void setDyeColour( int dyeColour ); + + /** + * Gets the colour the turtle has been dyed. + * @return 0-15 if the turtle has been dyed one of the 16 standard minecraft colours, -1 if the turtle is clean. + */ + public int getDyeColour(); + + /** + * TODO: Document me + */ + public IInventory getInventory(); + + /** + * TODO: Document me + */ + public boolean isFuelNeeded(); + + /** + * TODO: Document me + */ + public int getFuelLevel(); + + /** + * TODO: Document me + */ + public void setFuelLevel( int fuel ); + + /** + * TODO: Document me + */ + public int getFuelLimit(); + + /** + * Removes some fuel from the turtles fuel supply. Negative numbers can be passed in to INCREASE the fuel level of the turtle. + * @return Whether the turtle was able to consume the ammount of fuel specified. Will return false if you supply a number + * greater than the current fuel level of the turtle. + */ + public boolean consumeFuel( int fuel ); + + /** + * TODO: Document me + */ + public void addFuel( int fuel ); + + /** + * Adds a custom command to the turtles command queue. Unlike peripheral methods, these custom commands will be executed + * on the main thread, so are guaranteed to be able to access Minecraft objects safely, and will be queued up + * with the turtles standard movement and tool commands. An issued command will return an unique integer, which will + * be supplied as a parameter to a "turtle_response" event issued to the turtle after the command has completed. Look at the + * lua source code for "rom/apis/turtle" for how to build a lua wrapper around this functionality. + * @param command an object which will execute the custom command when its point in the queue is reached + * @return the objects the command returned when executed. you should probably return these to the player + * unchanged if called from a peripheral method. + * @see ITurtleCommand + */ + public Object[] executeCommand( ILuaContext context, ITurtleCommand command ) throws LuaException, InterruptedException; + + /** + * TODO: Document me + */ + public void playAnimation( TurtleAnimation animation ); + + /** + * Returns the turtle on the specified side of the turtle, if there is one. + * @return the turtle on the specified side of the turtle, if there is one. + */ + public ITurtleUpgrade getUpgrade( TurtleSide side ); + + /** + * TODO: Document me + */ + public void setUpgrade( TurtleSide side, ITurtleUpgrade upgrade ); + + /** + * Returns the peripheral created by the upgrade on the specified side of the turtle, if there is one. + * @return the peripheral created by the upgrade on the specified side of the turtle, if there is one. + */ + public IPeripheral getPeripheral( TurtleSide side ); + + /** + * TODO: Document me + */ + public NBTTagCompound getUpgradeNBTData( TurtleSide side ); + + /** + * TODO: Document me + */ + public void updateUpgradeNBTData( TurtleSide side ); +} diff --git a/src/main/java/dan200/computercraft/api/turtle/ITurtleCommand.java b/src/main/java/dan200/computercraft/api/turtle/ITurtleCommand.java new file mode 100755 index 0000000..17d113e --- /dev/null +++ b/src/main/java/dan200/computercraft/api/turtle/ITurtleCommand.java @@ -0,0 +1,25 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2015. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +package dan200.computercraft.api.turtle; + +/** + * An interface for objects executing custom turtle commands, used with ITurtleAccess.issueCommand + * @see ITurtleAccess#executeCommand(dan200.computercraft.api.lua.ILuaContext,ITurtleCommand) + */ +public interface ITurtleCommand +{ + /** + * Will be called by the turtle on the main thread when it is time to execute the custom command. + * The handler should either perform the work of the command, and return success, or return + * failure with an error message to indicate the command cannot be executed at this time. + * @param turtle access to the turtle for whom the command was issued + * @return TurtleCommandResult.success() or TurtleCommandResult.failure( errorMessage ) + * @see ITurtleAccess#executeCommand(dan200.computercraft.api.lua.ILuaContext,ITurtleCommand) + * @see dan200.computercraft.api.turtle.TurtleCommandResult + */ + public TurtleCommandResult execute( ITurtleAccess turtle ); +} diff --git a/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java b/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java new file mode 100755 index 0000000..0dcc6e6 --- /dev/null +++ b/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java @@ -0,0 +1,94 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2015. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +package dan200.computercraft.api.turtle; + +import dan200.computercraft.api.peripheral.IPeripheral; +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; + +/** + * The primary interface for defining an turtle for Turtles. A turtle turtle + * can either be a new tool, or a new peripheral. + * @see dan200.computercraft.api.ComputerCraftAPI#registerTurtleUpgrade( dan200.computercraft.api.turtle.ITurtleUpgrade ) + */ +public interface ITurtleUpgrade +{ + /** + * Gets a unique numerical identifier representing this type of turtle turtle. + * Like Minecraft common and item IDs, you should strive to make this number unique + * among all turtle turtle that have been released for ComputerCraft. + * The ID must be in the range 64 to 255, as the ID is stored as an 8-bit value, + * and 0-64 is reserved for future use by ComputerCraft. The turtle will + * fail registration if an already used ID is specified. + * @see dan200.computercraft.api.ComputerCraftAPI#registerTurtleUpgrade( dan200.computercraft.api.turtle.ITurtleUpgrade ) + */ + public int getUpgradeID(); + + /** + * Return a String to describe this type of turtle in turtle item names. + * Examples of built-in adjectives are "Wireless", "Mining" and "Crafty". + */ + public String getUnlocalisedAdjective(); + + /** + * Return whether this turtle adds a tool or a peripheral to the turtle. + * Currently, turtle crafting is restricted to one tool & one peripheral per turtle. + * @see TurtleUpgradeType for the differences between the two. + */ + public TurtleUpgradeType getType(); + + /** + * Return an item stack representing the type of item that a turtle must be crafted + * with to create a turtle which holds this turtle. + * Currently, turtle crafting is restricted to one tool & one peripheral per turtle. + */ + public ItemStack getCraftingItem(); + + /** + * Will only be called for Peripheral turtle. Creates a peripheral for a turtle + * being placed using this turtle. The peripheral created will be stored + * for the lifetime of the turtle, will have update() called once-per-tick, and will be + * attach'd detach'd and have methods called in the same manner as a Computer peripheral. + * + * @param turtle Access to the turtle that the peripheral is being created for. + * @param side Which side of the turtle (left or right) that the turtle resides on. + * @return The newly created peripheral. You may return null if this turtle is a Tool + * and this method is not expected to be called. + */ + public IPeripheral createPeripheral( ITurtleAccess turtle, TurtleSide side ); + + /** + * Will only be called for Tool turtle. Called when turtle.dig() or turtle.attack() is called + * by the turtle, and the tool is required to do some work. + * @param turtle Access to the turtle that the tool resides on. + * @param side Which side of the turtle (left or right) the tool resides on. + * @param verb Which action (dig or attack) the turtle is being called on to perform. + * @param direction Which world direction the action should be performed in, relative to the turtles + * position. This will either be up, down, or the direction the turtle is facing, depending on + * whether dig, digUp or digDown was called. + * @return Whether the turtle was able to perform the action, and hence whether the turtle.dig() + * or turtle.attack() lua method should return true. If true is returned, the tool will perform + * a swinging animation. You may return null if this turtle is a Peripheral + * and this method is not expected to be called. + */ + public TurtleCommandResult useTool( ITurtleAccess turtle, TurtleSide side, TurtleVerb verb, int direction ); + + /** + * Called to obtain the IIcon to be used when rendering a turtle peripheral. Needs to be a "common" + * type IIcon for now, as there is no way to determine which texture sheet an IIcon is from by the + * IIcon itself. + * @param turtle Access to the turtle that the peripheral resides on. + * @param side Which side of the turtle (left or right) the peripheral resides on. + * @return The IIcon that you wish to be used to render your turtle peripheral. + */ + public IIcon getIcon( ITurtleAccess turtle, TurtleSide side ); + + /** + * TODO: Document me + */ + public void update( ITurtleAccess turtle, TurtleSide side ); +} diff --git a/src/main/java/dan200/computercraft/api/turtle/TurtleAnimation.java b/src/main/java/dan200/computercraft/api/turtle/TurtleAnimation.java new file mode 100755 index 0000000..abb4134 --- /dev/null +++ b/src/main/java/dan200/computercraft/api/turtle/TurtleAnimation.java @@ -0,0 +1,22 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2015. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +package dan200.computercraft.api.turtle; + +public enum TurtleAnimation +{ + None, + MoveForward, + MoveBack, + MoveUp, + MoveDown, + TurnLeft, + TurnRight, + SwingLeftTool, + SwingRightTool, + Wait, + ShortWait, +} diff --git a/src/main/java/dan200/computercraft/api/turtle/TurtleCommandResult.java b/src/main/java/dan200/computercraft/api/turtle/TurtleCommandResult.java new file mode 100755 index 0000000..67046bd --- /dev/null +++ b/src/main/java/dan200/computercraft/api/turtle/TurtleCommandResult.java @@ -0,0 +1,73 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2015. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +package dan200.computercraft.api.turtle; + +public final class TurtleCommandResult +{ + private static final TurtleCommandResult s_success = new TurtleCommandResult( true, null, null ); + private static final TurtleCommandResult s_emptyFailure = new TurtleCommandResult( false, null, null ); + + public static TurtleCommandResult success() + { + return success( null ); + } + + public static TurtleCommandResult success( Object[] results ) + { + if( results == null || results.length == 0 ) + { + return s_success; + } + else + { + return new TurtleCommandResult( true, null, results ); + } + } + + public static TurtleCommandResult failure() + { + return failure( null ); + } + + public static TurtleCommandResult failure( String errorMessage ) + { + if( errorMessage == null ) + { + return s_emptyFailure; + } + else + { + return new TurtleCommandResult( false, errorMessage, null ); + } + } + + private final boolean m_success; + private final String m_errorMessage; + private final Object[] m_results; + + private TurtleCommandResult( boolean success, String errorMessage, Object[] results ) + { + m_success = success; + m_errorMessage = errorMessage; + m_results = results; + } + + public boolean isSuccess() + { + return m_success; + } + + public String getErrorMessage() + { + return m_errorMessage; + } + + public Object[] getResults() + { + return m_results; + } +} diff --git a/src/main/java/dan200/computercraft/api/turtle/TurtleSide.java b/src/main/java/dan200/computercraft/api/turtle/TurtleSide.java new file mode 100755 index 0000000..5fc7c61 --- /dev/null +++ b/src/main/java/dan200/computercraft/api/turtle/TurtleSide.java @@ -0,0 +1,23 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2015. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +package dan200.computercraft.api.turtle; + +/** + * An enum representing the two sides of the turtle that a turtle turtle might reside. + */ +public enum TurtleSide +{ + /** + * The turtles left side (where the pickaxe usually is on a Wireless Mining Turtle) + */ + Left, + + /** + * The turtles right side (where the modem usually is on a Wireless Mining Turtle) + */ + Right, +} diff --git a/src/main/java/dan200/computercraft/api/turtle/TurtleUpgradeType.java b/src/main/java/dan200/computercraft/api/turtle/TurtleUpgradeType.java new file mode 100755 index 0000000..e5fd1af --- /dev/null +++ b/src/main/java/dan200/computercraft/api/turtle/TurtleUpgradeType.java @@ -0,0 +1,27 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2015. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +package dan200.computercraft.api.turtle; + +/** + * An enum representing the two different types of turtle that an ITurtleUpgrade + * implementation can add to a turtle. + * @see ITurtleUpgrade + */ +public enum TurtleUpgradeType +{ + /** + * A tool is rendered as an item on the side of the turtle, and responds to the turtle.dig() + * and turtle.attack() methods (Such as pickaxe or sword on Mining and Melee turtles). + */ + Tool, + + /** + * A peripheral adds a special peripheral which is attached to the side of the turtle, + * and can be interacted with the peripheral API (Such as the modem on Wireless Turtles). + */ + Peripheral, +} diff --git a/src/main/java/dan200/computercraft/api/turtle/TurtleVerb.java b/src/main/java/dan200/computercraft/api/turtle/TurtleVerb.java new file mode 100755 index 0000000..566fa48 --- /dev/null +++ b/src/main/java/dan200/computercraft/api/turtle/TurtleVerb.java @@ -0,0 +1,26 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2015. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +package dan200.computercraft.api.turtle; + +/** + * An enum representing the two different actions that an ITurtleUpgrade of type + * Tool may be called on to perform by a turtle. + * @see ITurtleUpgrade + * @see ITurtleUpgrade#useTool + */ +public enum TurtleVerb +{ + /** + * The turtle called turtle.dig(), turtle.digUp() or turtle.digDown() + */ + Dig, + + /** + * The turtle called turtle.attack(), turtle.attackUp() or turtle.attackDown() + */ + Attack, +} diff --git a/src/main/java/dan200/computercraft/api/turtle/package-info.java b/src/main/java/dan200/computercraft/api/turtle/package-info.java new file mode 100755 index 0000000..7825971 --- /dev/null +++ b/src/main/java/dan200/computercraft/api/turtle/package-info.java @@ -0,0 +1,10 @@ +/** + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2015. This API may be redistributed unmodified and in full only. + * For help using the API, and posting your mods, visit the forums at computercraft.info. + */ + +@API( owner="ComputerCraft", provides="ComputerCraft|API|Turtle", apiVersion="1.75" ) +package dan200.computercraft.api.turtle; + +import cpw.mods.fml.common.API; diff --git a/src/main/java/icbm/api/IAmmunition.java b/src/main/java/icbm/api/IAmmunition.java new file mode 100644 index 0000000..34b3071 --- /dev/null +++ b/src/main/java/icbm/api/IAmmunition.java @@ -0,0 +1,10 @@ +package icbm.api; + +import net.minecraft.item.ItemStack; + +public interface IAmmunition { + + boolean hasAmmunition(ItemStack var1); + + boolean useAmmunition(ItemStack var1); +} diff --git a/src/main/java/icbm/api/IBlockFrequency.java b/src/main/java/icbm/api/IBlockFrequency.java new file mode 100644 index 0000000..d831270 --- /dev/null +++ b/src/main/java/icbm/api/IBlockFrequency.java @@ -0,0 +1,9 @@ +package icbm.api; + + +public interface IBlockFrequency { + + int getFrequency(); + + void setFrequency(int var1); +} diff --git a/src/main/java/icbm/api/ICBM.java b/src/main/java/icbm/api/ICBM.java new file mode 100644 index 0000000..5e8e014 --- /dev/null +++ b/src/main/java/icbm/api/ICBM.java @@ -0,0 +1,41 @@ +package icbm.api; + +import icbm.api.explosion.IExplosive; +import java.lang.reflect.Method; +import net.minecraft.entity.Entity; +import net.minecraft.world.World; + +public class ICBM { + + public static final String NAME = "ICBM"; + public static final String VERSION = "1.1.1"; + public static final int BLOCK_ID_PREFIX = 3880; + public static final int ITEM_ID_PREFIX = 3900; + public static Class explosionManager; + + + public static void createExplosion(World worldObj, double x, double y, double z, Entity entity, int explosiveID) { + try { + Method e = explosionManager.getMethod("createExplosion", new Class[]{World.class, Double.class, Double.class, Double.class, Entity.class, Integer.class}); + e.invoke((Object)null, new Object[]{worldObj, Double.valueOf(x), Double.valueOf(y), Double.valueOf(z), entity, Integer.valueOf(explosiveID)}); + } catch (Exception var10) { + System.out.println("ICBM: Failed to create an ICBM explosion with the ID: " + explosiveID); + var10.printStackTrace(); + } + + } + + public static IExplosive getExplosive(String name) { + if(name != null) { + try { + Method e = explosionManager.getMethod("getExplosiveByName", new Class[]{String.class}); + return (IExplosive)e.invoke((Object)null, new Object[]{name}); + } catch (Exception var2) { + System.out.println("ICBM: Failed to get explosive with the name: " + name); + var2.printStackTrace(); + } + } + + return null; + } +} diff --git a/src/main/java/icbm/api/ICBMFlags.java b/src/main/java/icbm/api/ICBMFlags.java new file mode 100644 index 0000000..03ab58c --- /dev/null +++ b/src/main/java/icbm/api/ICBMFlags.java @@ -0,0 +1,15 @@ +package icbm.api; + +public class ICBMFlags { + // TODO: WTF + // public static final String FLAG_BAN_GLOBAL = + // FlagRegistry.registerFlag("ban_icbm"); + // public static final String FLAG_BAN_EXPLOSIVE = + // FlagRegistry.registerFlag("ban_explosive"); + // public static final String FLAG_BAN_GRENADE = + // FlagRegistry.registerFlag("ban_grenade"); + // public static final String FLAG_BAN_MISSILE = + // FlagRegistry.registerFlag("ban_missile"); + // public static final String FLAG_BAN_MINECART = + // FlagRegistry.registerFlag("ban_minecart"); +} diff --git a/src/main/java/icbm/api/ICamouflageMaterial.java b/src/main/java/icbm/api/ICamouflageMaterial.java new file mode 100644 index 0000000..d47aebb --- /dev/null +++ b/src/main/java/icbm/api/ICamouflageMaterial.java @@ -0,0 +1,5 @@ +package icbm.api; + + +public interface ICamouflageMaterial { +} diff --git a/src/main/java/icbm/api/IHackable.java b/src/main/java/icbm/api/IHackable.java new file mode 100644 index 0000000..63d4909 --- /dev/null +++ b/src/main/java/icbm/api/IHackable.java @@ -0,0 +1,10 @@ +package icbm.api; + +import net.minecraft.entity.player.EntityPlayer; + +public interface IHackable { + + void generateNewKey(); + + boolean tryForAccess(EntityPlayer var1, String var2); +} diff --git a/src/main/java/icbm/api/IItemFrequency.java b/src/main/java/icbm/api/IItemFrequency.java new file mode 100644 index 0000000..3ac4618 --- /dev/null +++ b/src/main/java/icbm/api/IItemFrequency.java @@ -0,0 +1,10 @@ +package icbm.api; + +import net.minecraft.item.ItemStack; + +public interface IItemFrequency { + + int getFrequency(ItemStack var1); + + void setFrequency(int var1, ItemStack var2); +} diff --git a/src/main/java/icbm/api/ILauncherContainer.java b/src/main/java/icbm/api/ILauncherContainer.java new file mode 100644 index 0000000..a462a3b --- /dev/null +++ b/src/main/java/icbm/api/ILauncherContainer.java @@ -0,0 +1,13 @@ +package icbm.api; + +import icbm.api.ILauncherController; +import icbm.api.IMissile; + +public interface ILauncherContainer { + + IMissile getContainingMissile(); + + void setContainingMissile(IMissile var1); + + ILauncherController getController(); +} diff --git a/src/main/java/icbm/api/ILauncherController.java b/src/main/java/icbm/api/ILauncherController.java new file mode 100644 index 0000000..cdb9bb0 --- /dev/null +++ b/src/main/java/icbm/api/ILauncherController.java @@ -0,0 +1,28 @@ +package icbm.api; + +import icbm.api.IBlockFrequency; +import icbm.api.IMissile; +import icbm.api.LauncherType; +import net.minecraft.item.ItemStack; +import universalelectricity.core.block.IElectricityStorage; +import universalelectricity.core.vector.Vector3; +import universalelectricity.prefab.implement.IRedstoneReceptor; + +public interface ILauncherController extends IElectricityStorage, IRedstoneReceptor, IBlockFrequency { + + LauncherType getLauncherType(); + + void launch(); + + boolean canLaunch(); + + String getStatus(); + + Vector3 getTarget(); + + void setTarget(Vector3 var1); + + void placeMissile(ItemStack var1); + + IMissile getMissile(); +} diff --git a/src/main/java/icbm/api/IMissile.java b/src/main/java/icbm/api/IMissile.java new file mode 100644 index 0000000..6ea09cd --- /dev/null +++ b/src/main/java/icbm/api/IMissile.java @@ -0,0 +1,26 @@ +package icbm.api; + +import icbm.api.ILauncherContainer; +import icbm.api.explosion.IExplosiveContainer; +import universalelectricity.core.vector.Vector3; + +public interface IMissile extends IExplosiveContainer { + + void explode(); + + void setExplode(); + + void normalExplode(); + + void setNormalExplode(); + + void dropMissileAsItem(); + + int getTicksInAir(); + + ILauncherContainer getLauncher(); + + void launch(Vector3 var1); + + void launch(Vector3 var1, int var2); +} diff --git a/src/main/java/icbm/api/IMissileLockable.java b/src/main/java/icbm/api/IMissileLockable.java new file mode 100644 index 0000000..4474c02 --- /dev/null +++ b/src/main/java/icbm/api/IMissileLockable.java @@ -0,0 +1,11 @@ +package icbm.api; + +import icbm.api.IMissile; +import universalelectricity.core.vector.Vector3; + +public interface IMissileLockable { + + boolean canLock(IMissile var1); + + Vector3 getPredictedPosition(int var1); +} diff --git a/src/main/java/icbm/api/LauncherType.java b/src/main/java/icbm/api/LauncherType.java new file mode 100644 index 0000000..1c8d1c3 --- /dev/null +++ b/src/main/java/icbm/api/LauncherType.java @@ -0,0 +1,14 @@ +package icbm.api; + + +public enum LauncherType { + + TRADITIONAL("TRADITIONAL", 0), + CRUISE("CRUISE", 1); + // $FF: synthetic field + private static final LauncherType[] $VALUES = new LauncherType[]{TRADITIONAL, CRUISE}; + + + private LauncherType(String var1, int var2) {} + +} diff --git a/src/main/java/icbm/api/RadarRegistry.java b/src/main/java/icbm/api/RadarRegistry.java new file mode 100644 index 0000000..83b2bb9 --- /dev/null +++ b/src/main/java/icbm/api/RadarRegistry.java @@ -0,0 +1,110 @@ +package icbm.api; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import net.minecraft.entity.Entity; +import net.minecraft.tileentity.TileEntity; +import universalelectricity.core.vector.Vector2; +import universalelectricity.core.vector.Vector3; +import universalelectricity.prefab.vector.Region2; + +public class RadarRegistry { + private static Set detectableTileEntities = new HashSet<>(); + private static Set detectableEntities = new HashSet<>(); + + public static void register(TileEntity tileEntity) { + if (!detectableTileEntities.contains(tileEntity)) { + detectableTileEntities.add(tileEntity); + } + } + + public static void unregister(TileEntity tileEntity) { + if (detectableTileEntities.contains(tileEntity)) { + detectableTileEntities.remove(tileEntity); + } + } + + public static void register(Entity entity) { + if (!detectableEntities.contains(entity)) { + detectableEntities.add(entity); + } + } + + public static void unregister(Entity entity) { + if (detectableEntities.contains(entity)) { + detectableEntities.remove(entity); + } + } + + public static List getTileEntitiesInArea(Vector2 minVector, + Vector2 maxVector) { + ArrayList returnArray = new ArrayList<>(); + cleanUpArray(); + for (TileEntity tileEntity : detectableTileEntities) { + if ((new Region2(minVector, maxVector)) + .isIn((new Vector3(tileEntity)).toVector2())) { + returnArray.add(tileEntity); + } + } + + return returnArray; + } + + public static List getEntitiesWithinRadius(Vector2 vector, + int radius) { + cleanUpArray(); + ArrayList returnArray = new ArrayList<>(); + for (Entity entity : detectableEntities) { + if (Vector2.distance(vector, (new Vector3(entity)).toVector2()) <= + (double)radius) { + returnArray.add(entity); + } + } + + return returnArray; + } + + public static Set getTileEntities() { + cleanUpArray(); + return detectableTileEntities; + } + + public static Set getEntities() { + cleanUpArray(); + return detectableEntities; + } + + public static void cleanUpArray() { + try { + Iterator e = detectableTileEntities.iterator(); + + while (e.hasNext()) { + TileEntity it2 = e.next(); + if (it2 == null) { + e.remove(); + } else if (it2.isInvalid()) { + e.remove(); + } else if (it2.getWorldObj().getTileEntity(it2.xCoord, it2.yCoord, + it2.zCoord) != it2) { + e.remove(); + } + } + + Iterator it21 = detectableEntities.iterator(); + while (it21.hasNext()) { + Entity entity = (Entity)it21.next(); + if (entity == null) { + it21.remove(); + } else if (entity.isDead) { + it21.remove(); + } + } + } catch (Exception var3) { + System.out.println("Failed to clean up radar list properly."); + var3.printStackTrace(); + } + } +} diff --git a/src/main/java/icbm/api/explosion/ExplosionEvent.java b/src/main/java/icbm/api/explosion/ExplosionEvent.java new file mode 100644 index 0000000..b3fd936 --- /dev/null +++ b/src/main/java/icbm/api/explosion/ExplosionEvent.java @@ -0,0 +1,36 @@ +package icbm.api.explosion; + +import cpw.mods.fml.common.eventhandler.Event; +import net.minecraft.world.World; + +public class ExplosionEvent extends Event { + + public final World world; + public final double x; + public final double y; + public final double z; + public IExplosive explosive; + + + public ExplosionEvent(World world, double x, double y, double z, IExplosive explosive) { + this.world = world; + this.x = x; + this.y = y; + this.z = z; + this.explosive = explosive; + } + + public static class PostExplosionEvent extends ExplosionEvent { + + public PostExplosionEvent(World world, double x, double y, double z, IExplosive explosive) { + super(world, x, y, z, explosive); + } + } + + public static class PreExplosionEvent extends ExplosionEvent { + + public PreExplosionEvent(World world, double x, double y, double z, IExplosive explosive) { + super(world, x, y, z, explosive); + } + } +} diff --git a/src/main/java/icbm/api/explosion/IEMPBlock.java b/src/main/java/icbm/api/explosion/IEMPBlock.java new file mode 100644 index 0000000..c74d838 --- /dev/null +++ b/src/main/java/icbm/api/explosion/IEMPBlock.java @@ -0,0 +1,10 @@ +package icbm.api.explosion; + +import icbm.api.explosion.IExplosive; +import net.minecraft.world.World; +import universalelectricity.core.vector.Vector3; + +public interface IEMPBlock { + + void onEMP(World var1, Vector3 var2, IExplosive var3); +} diff --git a/src/main/java/icbm/api/explosion/IEMPItem.java b/src/main/java/icbm/api/explosion/IEMPItem.java new file mode 100644 index 0000000..32b4e4a --- /dev/null +++ b/src/main/java/icbm/api/explosion/IEMPItem.java @@ -0,0 +1,11 @@ +package icbm.api.explosion; + +import icbm.api.explosion.IExplosive; +import net.minecraft.entity.Entity; +import net.minecraft.item.ItemStack; +import universalelectricity.core.item.IItemElectric; + +public interface IEMPItem extends IItemElectric { + + void onEMP(ItemStack var1, Entity var2, IExplosive var3); +} diff --git a/src/main/java/icbm/api/explosion/IExplosive.java b/src/main/java/icbm/api/explosion/IExplosive.java new file mode 100644 index 0000000..d923615 --- /dev/null +++ b/src/main/java/icbm/api/explosion/IExplosive.java @@ -0,0 +1,23 @@ +package icbm.api.explosion; + + +public interface IExplosive { + + int getID(); + + String getUnlocalizedName(); + + String getExplosiveName(); + + String getGrenadeName(); + + String getMissileName(); + + String getMinecartName(); + + float getRadius(); + + int getTier(); + + double getEnergy(); +} diff --git a/src/main/java/icbm/api/explosion/IExplosiveContainer.java b/src/main/java/icbm/api/explosion/IExplosiveContainer.java new file mode 100644 index 0000000..72f54b6 --- /dev/null +++ b/src/main/java/icbm/api/explosion/IExplosiveContainer.java @@ -0,0 +1,8 @@ +package icbm.api.explosion; + +import icbm.api.explosion.IExplosive; + +public interface IExplosiveContainer { + + IExplosive getExplosiveType(); +} diff --git a/src/main/java/icbm/api/explosion/IExplosiveIgnore.java b/src/main/java/icbm/api/explosion/IExplosiveIgnore.java new file mode 100644 index 0000000..093a592 --- /dev/null +++ b/src/main/java/icbm/api/explosion/IExplosiveIgnore.java @@ -0,0 +1,8 @@ +package icbm.api.explosion; + +import icbm.api.explosion.ExplosionEvent; + +public interface IExplosiveIgnore { + + boolean canIgnore(ExplosionEvent var1); +} diff --git a/src/main/java/mffs/ClientProxy.java b/src/main/java/mffs/ClientProxy.java new file mode 100644 index 0000000..ac81aa7 --- /dev/null +++ b/src/main/java/mffs/ClientProxy.java @@ -0,0 +1,131 @@ +package mffs; + +import cpw.mods.fml.client.FMLClientHandler; +import cpw.mods.fml.client.registry.ClientRegistry; +import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler; +import cpw.mods.fml.client.registry.RenderingRegistry; +import mffs.gui.GuiBiometricIdentifier; +import mffs.gui.GuiCoercionDeriver; +import mffs.gui.GuiForceFieldProjector; +import mffs.gui.GuiForceManipulator; +import mffs.gui.GuiFortronCapacitor; +import mffs.gui.GuiInterdictionMatrix; +import mffs.render.FXBeam; +import mffs.render.FXHologram; +import mffs.render.FXHologramMoving; +import mffs.render.RenderBlockHandler; +import mffs.render.RenderCoercionDeriver; +import mffs.render.RenderForceField; +import mffs.render.RenderForceFieldProjector; +import mffs.render.RenderForceManipulator; +import mffs.render.RenderFortronCapacitor; +import mffs.render.RenderIDCard; +import mffs.tileentity.TileEntityBiometricIdentifier; +import mffs.tileentity.TileEntityCoercionDeriver; +import mffs.tileentity.TileEntityForceFieldProjector; +import mffs.tileentity.TileEntityForceManipulator; +import mffs.tileentity.TileEntityFortronCapacitor; +import mffs.tileentity.TileEntityInterdictionMatrix; +import net.minecraft.client.particle.EntityFX; +import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; +import net.minecraftforge.client.IItemRenderer; +import net.minecraftforge.client.MinecraftForgeClient; +import universalelectricity.core.vector.Vector3; + +public class ClientProxy extends CommonProxy { + @Override + public void init() { + super.init(); + RenderingRegistry.registerBlockHandler( + (ISimpleBlockRenderingHandler) new RenderBlockHandler()); + RenderingRegistry.registerBlockHandler( + (ISimpleBlockRenderingHandler) new RenderForceField()); + MinecraftForgeClient.registerItemRenderer( + ModularForceFieldSystem.itemCardID, (IItemRenderer) new RenderIDCard()); + ClientRegistry.bindTileEntitySpecialRenderer( + TileEntityFortronCapacitor.class, + (TileEntitySpecialRenderer) new RenderFortronCapacitor()); + ClientRegistry.bindTileEntitySpecialRenderer( + TileEntityCoercionDeriver.class, + (TileEntitySpecialRenderer) new RenderCoercionDeriver()); + ClientRegistry.bindTileEntitySpecialRenderer( + TileEntityForceManipulator.class, + (TileEntitySpecialRenderer) new RenderForceManipulator()); + ClientRegistry.bindTileEntitySpecialRenderer( + TileEntityForceFieldProjector.class, + (TileEntitySpecialRenderer) new RenderForceFieldProjector()); + } + + @Override + public World getClientWorld() { + return (World)FMLClientHandler.instance().getClient().theWorld; + } + + @Override + public Object getClientGuiElement(final int ID, final EntityPlayer player, + final World world, final int x, final int y, + final int z) { + final TileEntity tileEntity = world.getTileEntity(x, y, z); + if (tileEntity != null) { + if (tileEntity.getClass() == TileEntityFortronCapacitor.class) { + return new GuiFortronCapacitor(player, + (TileEntityFortronCapacitor)tileEntity); + } + if (tileEntity.getClass() == TileEntityForceFieldProjector.class) { + return new GuiForceFieldProjector( + player, (TileEntityForceFieldProjector)tileEntity); + } + if (tileEntity.getClass() == TileEntityCoercionDeriver.class) { + return new GuiCoercionDeriver(player, + (TileEntityCoercionDeriver)tileEntity); + } + if (tileEntity.getClass() == TileEntityBiometricIdentifier.class) { + return new GuiBiometricIdentifier( + player, (TileEntityBiometricIdentifier)tileEntity); + } + if (tileEntity.getClass() == TileEntityInterdictionMatrix.class) { + return new GuiInterdictionMatrix( + player, (TileEntityInterdictionMatrix)tileEntity); + } + if (tileEntity.getClass() == TileEntityForceManipulator.class) { + return new GuiForceManipulator(player, + (TileEntityForceManipulator)tileEntity); + } + } + return null; + } + + @Override + public boolean isOp(final String username) { + return false; + } + + @Override + public void renderBeam(final World world, final Vector3 position, + final Vector3 target, final float red, + final float green, final float blue, final int age) { + FMLClientHandler.instance().getClient().effectRenderer.addEffect( + (EntityFX) new FXBeam(world, position, target, red, green, blue, age)); + } + + @Override + public void renderHologram(final World world, final Vector3 position, + final float red, final float green, + final float blue, final int age, + final Vector3 targetPosition) { + FMLClientHandler.instance().getClient().effectRenderer.addEffect( + (EntityFX) new FXHologram(world, position, red, green, blue, age) + .setTarget(targetPosition)); + } + + @Override + public void renderHologramMoving(final World world, final Vector3 position, + final float red, final float green, + final float blue, final int age) { + FMLClientHandler.instance().getClient().effectRenderer.addEffect(( + EntityFX) new FXHologramMoving(world, position, red, green, blue, age)); + } +} diff --git a/src/main/java/mffs/CommonProxy.java b/src/main/java/mffs/CommonProxy.java new file mode 100644 index 0000000..14dda3a --- /dev/null +++ b/src/main/java/mffs/CommonProxy.java @@ -0,0 +1,94 @@ +package mffs; + +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.common.network.IGuiHandler; +import mffs.container.ContainerBiometricIdentifier; +import mffs.container.ContainerCoercionDeriver; +import mffs.container.ContainerForceFieldProjector; +import mffs.container.ContainerForceManipulator; +import mffs.container.ContainerFortronCapacitor; +import mffs.container.ContainerInterdictionMatrix; +import mffs.tileentity.TileEntityBiometricIdentifier; +import mffs.tileentity.TileEntityCoercionDeriver; +import mffs.tileentity.TileEntityForceFieldProjector; +import mffs.tileentity.TileEntityForceManipulator; +import mffs.tileentity.TileEntityFortronCapacitor; +import mffs.tileentity.TileEntityInterdictionMatrix; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.server.MinecraftServer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; +import universalelectricity.core.vector.Vector3; + +public class CommonProxy implements IGuiHandler { + public void preInit() {} + + public void init() {} + + public Object getClientGuiElement(final int ID, final EntityPlayer player, + final World world, final int x, final int y, + final int z) { + return null; + } + + public Object getServerGuiElement(final int ID, final EntityPlayer player, + final World world, final int x, final int y, + final int z) { + final TileEntity tileEntity = world.getTileEntity(x, y, z); + if (tileEntity != null) { + if (tileEntity.getClass() == TileEntityFortronCapacitor.class) { + return new ContainerFortronCapacitor( + player, (TileEntityFortronCapacitor)tileEntity); + } + if (tileEntity.getClass() == TileEntityForceFieldProjector.class) { + return new ContainerForceFieldProjector( + player, (TileEntityForceFieldProjector)tileEntity); + } + if (tileEntity.getClass() == TileEntityCoercionDeriver.class) { + return new ContainerCoercionDeriver( + player, (TileEntityCoercionDeriver)tileEntity); + } + if (tileEntity.getClass() == TileEntityBiometricIdentifier.class) { + return new ContainerBiometricIdentifier( + player, (TileEntityBiometricIdentifier)tileEntity); + } + if (tileEntity.getClass() == TileEntityInterdictionMatrix.class) { + return new ContainerInterdictionMatrix( + player, (TileEntityInterdictionMatrix)tileEntity); + } + if (tileEntity.getClass() == TileEntityForceManipulator.class) { + return new ContainerForceManipulator( + player, (TileEntityForceManipulator)tileEntity); + } + } + return null; + } + + public World getClientWorld() { return null; } + + public boolean isOp(final String username) { + final MinecraftServer theServer = + FMLCommonHandler.instance().getMinecraftServerInstance(); + if (theServer == null) + return false; + + for (String op : theServer.getConfigurationManager().func_152606_n()) + if (username.trim().equalsIgnoreCase(op)) + return true; + + return false; + } + + public void renderBeam(final World world, final Vector3 position, + final Vector3 target, final float red, + final float green, final float blue, final int age) {} + + public void renderHologram(final World world, final Vector3 position, + final float red, final float green, + final float blue, final int age, + final Vector3 targetPosition) {} + + public void renderHologramMoving(final World world, final Vector3 position, + final float red, final float green, + final float blue, final int age) {} +} diff --git a/src/main/java/mffs/DelayedEvent.java b/src/main/java/mffs/DelayedEvent.java new file mode 100644 index 0000000..811bf6b --- /dev/null +++ b/src/main/java/mffs/DelayedEvent.java @@ -0,0 +1,23 @@ +package mffs; + +public abstract class DelayedEvent { + public int ticks; + protected IDelayedEventHandler handler; + + public DelayedEvent(final IDelayedEventHandler handler, final int ticks) { + this.ticks = 0; + this.handler = handler; + this.ticks = ticks; + } + + protected abstract void onEvent(); + + public void update() { + --this.ticks; + if (this.ticks <= 0) { + this.onEvent(); + } + } + + public int getPriority() { return 0; } +} diff --git a/src/main/java/mffs/IDelayedEventHandler.java b/src/main/java/mffs/IDelayedEventHandler.java new file mode 100644 index 0000000..eafa6c0 --- /dev/null +++ b/src/main/java/mffs/IDelayedEventHandler.java @@ -0,0 +1,10 @@ +package mffs; + +import java.util.List; + +public interface IDelayedEventHandler +{ + List getDelayedEvents(); + + List getQuedDelayedEvents(); +} diff --git a/src/main/java/mffs/MFFSCreativeTab.java b/src/main/java/mffs/MFFSCreativeTab.java new file mode 100644 index 0000000..e5ea716 --- /dev/null +++ b/src/main/java/mffs/MFFSCreativeTab.java @@ -0,0 +1,23 @@ +package mffs; + +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.item.Item; + +public class MFFSCreativeTab extends CreativeTabs { + public static CreativeTabs INSTANCE; + + public MFFSCreativeTab(final int par1, final String par2Str) { + super(par1, par2Str); + } + + @Override + public Item getTabIconItem() { + return Item.getItemFromBlock( + ModularForceFieldSystem.blockForceFieldProjector); + } + + static { + MFFSCreativeTab.INSTANCE = + new MFFSCreativeTab(CreativeTabs.getNextID(), "MFFS"); + } +} diff --git a/src/main/java/mffs/MFFSHelper.java b/src/main/java/mffs/MFFSHelper.java new file mode 100644 index 0000000..f351785 --- /dev/null +++ b/src/main/java/mffs/MFFSHelper.java @@ -0,0 +1,370 @@ +package mffs; + +import calclavia.lib.CalculationHelper; +import icbm.api.IBlockFrequency; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Set; +import mffs.api.IProjector; +import mffs.api.fortron.IFortronFrequency; +import mffs.api.modules.IModuleAcceptor; +import mffs.api.security.IInterdictionMatrix; +import mffs.api.security.Permission; +import mffs.fortron.FrequencyGrid; +import mffs.item.module.projector.ItemModeCustom; +import net.minecraft.block.Block; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemBlock; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.event.entity.player.PlayerInteractEvent; +import universalelectricity.core.vector.Vector3; + +public class MFFSHelper { + public static void + transferFortron(final IFortronFrequency transferer, + final Set frequencyTiles, + final TransferMode transferMode, final int limit) { + if (transferer != null && frequencyTiles.size() > 1) { + int totalFortron = 0; + int totalCapacity = 0; + for (final IFortronFrequency machine : frequencyTiles) { + if (machine != null) { + totalFortron += machine.getFortronEnergy(); + totalCapacity += machine.getFortronCapacity(); + } + } + if (totalFortron > 0 && totalCapacity > 0) { + switch (transferMode) { + case EQUALIZE: { + for (final IFortronFrequency machine : frequencyTiles) { + if (machine != null) { + final double capacityPercentage = + machine.getFortronCapacity() / (double)totalCapacity; + final int amountToSet = (int)(totalFortron * capacityPercentage); + doTransferFortron(transferer, machine, + amountToSet - machine.getFortronEnergy(), + limit); + } + } + break; + } + case DISTRIBUTE: { + final int amountToSet2 = totalFortron / frequencyTiles.size(); + for (final IFortronFrequency machine2 : frequencyTiles) { + if (machine2 != null) { + doTransferFortron(transferer, machine2, + amountToSet2 - machine2.getFortronEnergy(), + limit); + } + } + break; + } + case DRAIN: { + frequencyTiles.remove(transferer); + for (final IFortronFrequency machine : frequencyTiles) { + if (machine != null) { + final double capacityPercentage = + machine.getFortronCapacity() / (double)totalCapacity; + final int amountToSet = (int)(totalFortron * capacityPercentage); + if (amountToSet - machine.getFortronEnergy() <= 0) { + continue; + } + doTransferFortron(transferer, machine, + amountToSet - machine.getFortronEnergy(), + limit); + } + } + break; + } + case FILL: { + if (transferer.getFortronEnergy() < transferer.getFortronCapacity()) { + frequencyTiles.remove(transferer); + final int requiredFortron = + transferer.getFortronCapacity() - transferer.getFortronEnergy(); + for (final IFortronFrequency machine2 : frequencyTiles) { + if (machine2 != null) { + final int amountToConsume = + Math.min(requiredFortron, machine2.getFortronEnergy()); + final int amountToSet = + -machine2.getFortronEnergy() - amountToConsume; + if (amountToConsume <= 0) { + continue; + } + doTransferFortron(transferer, machine2, + amountToSet - machine2.getFortronEnergy(), + limit); + } + } + break; + } + break; + } + } + } + } + } + + public static void doTransferFortron(final IFortronFrequency transferer, + final IFortronFrequency receiver, + int joules, final int limit) { + if (transferer != null && receiver != null) { + final TileEntity tileEntity = (TileEntity)transferer; + final World world = tileEntity.getWorldObj(); + boolean isCamo = false; + if (transferer instanceof IModuleAcceptor) { + isCamo = + (((IModuleAcceptor)transferer) + .getModuleCount(ModularForceFieldSystem.itemModuleCamouflage, + new int[0]) > 0); + } + if (joules > 0) { + joules = Math.min(joules, limit); + int toBeInjected = receiver.provideFortron( + transferer.requestFortron(joules, false), false); + toBeInjected = transferer.requestFortron( + receiver.provideFortron(toBeInjected, true), true); + if (world.isRemote && toBeInjected > 0 && !isCamo) { + ModularForceFieldSystem.proxy.renderBeam( + world, Vector3.add(new Vector3(tileEntity), 0.5), + Vector3.add(new Vector3((TileEntity)receiver), 0.5), 0.6f, 0.6f, + 1.0f, 20); + } + } else { + joules = Math.min(Math.abs(joules), limit); + int toBeEjected = transferer.provideFortron( + receiver.requestFortron(joules, false), false); + toBeEjected = receiver.requestFortron( + transferer.provideFortron(toBeEjected, true), true); + if (world.isRemote && toBeEjected > 0 && !isCamo) { + ModularForceFieldSystem.proxy.renderBeam( + world, Vector3.add(new Vector3((TileEntity)receiver), 0.5), + Vector3.add(new Vector3(tileEntity), 0.5), 0.6f, 0.6f, 1.0f, 20); + } + } + } + } + + public static IInterdictionMatrix + getNearestInterdictionMatrix(final World world, final Vector3 position) { + for (final IBlockFrequency frequencyTile : FrequencyGrid.instance().get()) { + if (((TileEntity)frequencyTile).getWorldObj() == world && + frequencyTile instanceof IInterdictionMatrix) { + final IInterdictionMatrix interdictionMatrix = + (IInterdictionMatrix)frequencyTile; + if (interdictionMatrix.isActive() && + position.distanceTo(new Vector3((TileEntity)interdictionMatrix)) <= + interdictionMatrix.getActionRange()) { + return interdictionMatrix; + } + continue; + } + } + return null; + } + + public static boolean + isPermittedByInterdictionMatrix(final IInterdictionMatrix interdictionMatrix, + final String username, + final Permission... permissions) { + if (interdictionMatrix != null && interdictionMatrix.isActive() && + interdictionMatrix.getBiometricIdentifier() != null) { + for (final Permission permission : permissions) { + if (!interdictionMatrix.getBiometricIdentifier().isAccessGranted( + username, permission)) { + return interdictionMatrix.getModuleCount( + ModularForceFieldSystem.itemModuleInvert, new int[0]) > 0; + } + } + } + return interdictionMatrix.getModuleCount( + ModularForceFieldSystem.itemModuleInvert, new int[0]) <= 0; + } + + public static List splitStringPerWord(final String string, + final int wordsPerLine) { + final String[] words = string.split(" "); + final List lines = new ArrayList<>(); + for (int lineCount = 0; + lineCount < Math.ceil(words.length / (float)wordsPerLine); + ++lineCount) { + String stringInLine = ""; + for (int i = lineCount * wordsPerLine; + i < Math.min(wordsPerLine + lineCount * wordsPerLine, words.length); + ++i) { + stringInLine = stringInLine + words[i] + " "; + } + lines.add(stringInLine.trim()); + } + return lines; + } + + public static ItemStack getFirstItemBlock(final TileEntity tileEntity, + final ItemStack itemStack) { + return getFirstItemBlock(tileEntity, itemStack, true); + } + + public static ItemStack getFirstItemBlock(final TileEntity tileEntity, + final ItemStack itemStack, + final boolean recur) { + if (tileEntity instanceof IProjector) { + for (final int i : ((IProjector)tileEntity).getModuleSlots()) { + final ItemStack checkStack = + getFirstItemBlock(i, (IInventory)tileEntity, itemStack); + if (checkStack != null) { + return checkStack; + } + } + } else if (tileEntity instanceof IInventory) { + final IInventory inventory = (IInventory)tileEntity; + for (int j = 0; j < inventory.getSizeInventory(); ++j) { + final ItemStack checkStack2 = + getFirstItemBlock(j, inventory, itemStack); + if (checkStack2 != null) { + return checkStack2; + } + } + } + if (recur) { + for (int k = 0; k < 6; ++k) { + final ForgeDirection direction = ForgeDirection.getOrientation(k); + final Vector3 vector = new Vector3(tileEntity); + vector.modifyPositionFromSide(direction); + final TileEntity checkTile = + vector.getTileEntity((IBlockAccess)tileEntity.getWorldObj()); + if (checkTile != null) { + final ItemStack checkStack = + getFirstItemBlock(checkTile, itemStack, false); + if (checkStack != null) { + return checkStack; + } + } + } + } + return null; + } + + public static ItemStack getFirstItemBlock(final int i, + final IInventory inventory, + final ItemStack itemStack) { + final ItemStack checkStack = inventory.getStackInSlot(i); + if (checkStack != null && checkStack.getItem() instanceof ItemBlock && + (itemStack == null || checkStack.isItemEqual(itemStack))) { + return checkStack; + } + return null; + } + + public static Block getFilterBlock(final ItemStack itemStack) { + if (itemStack != null && itemStack.getItem() instanceof ItemBlock) { + final Block block = Block.getBlockFromItem(itemStack.getItem()); + if (block.renderAsNormalBlock()) { + return block; + } + } + return null; + } + + public static ItemStack getCamoBlock(final IProjector projector, + final Vector3 position) { + if (projector != null && !((TileEntity)projector).getWorldObj().isRemote && + projector != null && + projector.getModuleCount(ModularForceFieldSystem.itemModuleCamouflage, + new int[0]) > 0) { + if (projector.getMode() instanceof ItemModeCustom) { + final HashMap fieldMap = + ((ItemModeCustom)projector.getMode()) + .getFieldBlockMap(projector, projector.getModeStack()); + if (fieldMap != null) { + final Vector3 fieldCenter = new Vector3((TileEntity)projector) + .add(projector.getTranslation()); + final Vector3 relativePosition = + position.clone().subtract(fieldCenter); + CalculationHelper.rotateByAngle(relativePosition, + -projector.getRotationYaw(), + -projector.getRotationPitch()); + final int[] blockInfo = fieldMap.get(relativePosition.round()); + if (blockInfo != null && blockInfo[0] > 0) { + return new ItemStack(Block.getBlockById(blockInfo[0]), 1, + blockInfo[1]); + } + } + } + for (final int i : projector.getModuleSlots()) { + final ItemStack checkStack = projector.getStackInSlot(i); + final Block block = getFilterBlock(checkStack); + if (block != null) { + return checkStack; + } + } + } + return null; + } + + public static NBTTagCompound getNBTTagCompound(final ItemStack itemStack) { + if (itemStack != null) { + if (itemStack.getTagCompound() == null) { + itemStack.setTagCompound(new NBTTagCompound()); + } + return itemStack.getTagCompound(); + } + return null; + } + + public static boolean hasPermission(final World world, final Vector3 position, + final Permission permission, + final EntityPlayer player) { + final IInterdictionMatrix interdictionMatrix = + getNearestInterdictionMatrix(world, position); + return interdictionMatrix == null || + isPermittedByInterdictionMatrix(interdictionMatrix, + player.getDisplayName(), permission); + } + + public static boolean hasPermission(final World world, final Vector3 position, + final PlayerInteractEvent.Action action, + final EntityPlayer player) { + final IInterdictionMatrix interdictionMatrix = + getNearestInterdictionMatrix(world, position); + return interdictionMatrix == null || + hasPermission(world, position, interdictionMatrix, action, player); + } + + public static boolean + hasPermission(final World world, final Vector3 position, + final IInterdictionMatrix interdictionMatrix, + final PlayerInteractEvent.Action action, + final EntityPlayer player) { + boolean hasPermission = true; + if (action == PlayerInteractEvent.Action.RIGHT_CLICK_BLOCK && + position.getTileEntity((IBlockAccess)world) != null && + interdictionMatrix.getModuleCount( + ModularForceFieldSystem.itemModuleBlockAccess, new int[0]) > 0) { + hasPermission = false; + if (isPermittedByInterdictionMatrix(interdictionMatrix, + player.getDisplayName(), + Permission.BLOCK_ACCESS)) { + hasPermission = true; + } + } + if (hasPermission && + interdictionMatrix.getModuleCount( + ModularForceFieldSystem.itemModuleBlockAlter, new int[0]) > 0 && + (player.getCurrentEquippedItem() != null || + action == PlayerInteractEvent.Action.LEFT_CLICK_BLOCK)) { + hasPermission = false; + if (isPermittedByInterdictionMatrix(interdictionMatrix, + player.getDisplayName(), + Permission.BLOCK_ALTER)) { + hasPermission = true; + } + } + return hasPermission; + } +} diff --git a/src/main/java/mffs/ManipulatorHelper.java b/src/main/java/mffs/ManipulatorHelper.java new file mode 100644 index 0000000..2ddd463 --- /dev/null +++ b/src/main/java/mffs/ManipulatorHelper.java @@ -0,0 +1,67 @@ +package mffs; + +import net.minecraft.block.Block; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; +import net.minecraft.world.chunk.storage.ExtendedBlockStorage; +import universalelectricity.core.vector.Vector3; + +public class ManipulatorHelper { + public static void setBlockSneaky(final World world, final Vector3 position, + final Block id, final int metadata, + final TileEntity tileEntity) { + final Chunk chunk = world.getChunkFromChunkCoords(position.intX() >> 4, + position.intZ() >> 4); + final Vector3 chunkPosition = new Vector3( + position.intX() & 0xF, position.intY() & 0xF, position.intZ() & 0xF); + final int heightMapIndex = chunkPosition.intZ() << 4 | chunkPosition.intX(); + if (position.intY() >= chunk.precipitationHeightMap[heightMapIndex] - 1) { + chunk.precipitationHeightMap[heightMapIndex] = -999; + } + final int heightMapValue = chunk.heightMap[heightMapIndex]; + world.removeTileEntity(position.intX(), position.intY(), position.intZ()); + ExtendedBlockStorage extendedBlockStorage = + chunk.getBlockStorageArray()[position.intY() >> 4]; + if (extendedBlockStorage == null) { + extendedBlockStorage = new ExtendedBlockStorage(position.intY() >> 4 << 4, + !world.provider.hasNoSky); + chunk.getBlockStorageArray()[position.intY() >> 4] = extendedBlockStorage; + } + extendedBlockStorage.func_150818_a( + chunkPosition.intX(), chunkPosition.intY(), chunkPosition.intZ(), id); + extendedBlockStorage.setExtBlockMetadata(chunkPosition.intX(), + chunkPosition.intY(), + chunkPosition.intZ(), metadata); + if (position.intY() >= heightMapValue) { + chunk.generateSkylightMap(); + } else { + if (chunk.func_150808_b(chunkPosition.intX(), position.intY(), + chunkPosition.intZ()) > 0) { + if (position.intY() >= heightMapValue) { + relightBlock(chunk, + Vector3.add(chunkPosition, new Vector3(0.0, 1.0, 0.0))); + } + } else if (position.intY() == heightMapValue - 1) { + relightBlock(chunk, chunkPosition); + } + propagateSkylightOcclusion(chunk, chunkPosition); + } + chunk.isModified = true; + world.func_147451_t(position.intX(), position.intY(), position.intZ()); + if (tileEntity != null) { + world.setTileEntity(position.intX(), position.intY(), position.intZ(), + tileEntity); + } + world.markBlockForUpdate(position.intX(), position.intY(), position.intZ()); + } + + public static void relightBlock(final Chunk chunk, final Vector3 position) { + chunk.relightBlock(position.intX(), position.intY(), position.intZ()); + } + + public static void propagateSkylightOcclusion(final Chunk chunk, + final Vector3 position) { + chunk.propagateSkylightOcclusion(position.intX(), position.intZ()); + } +} diff --git a/src/main/java/mffs/ModularForceFieldSystem.java b/src/main/java/mffs/ModularForceFieldSystem.java new file mode 100644 index 0000000..8937802 --- /dev/null +++ b/src/main/java/mffs/ModularForceFieldSystem.java @@ -0,0 +1,355 @@ +package mffs; + +import calclavia.lib.UniversalRecipes; +import cpw.mods.fml.common.Mod; +import cpw.mods.fml.common.Mod.EventHandler; +import cpw.mods.fml.common.ModMetadata; +import cpw.mods.fml.common.SidedProxy; +import cpw.mods.fml.common.event.FMLInitializationEvent; +import cpw.mods.fml.common.event.FMLPostInitializationEvent; +import cpw.mods.fml.common.event.FMLPreInitializationEvent; +import cpw.mods.fml.common.event.FMLServerStartingEvent; +import cpw.mods.fml.common.network.IGuiHandler; +import cpw.mods.fml.common.network.NetworkRegistry; +import cpw.mods.fml.common.network.simpleimpl.SimpleNetworkWrapper; +import cpw.mods.fml.common.registry.GameRegistry; +import cpw.mods.fml.relauncher.Side; +import java.util.Arrays; +import java.util.logging.Logger; +import mffs.base.BlockBase; +import mffs.base.BlockMachine; +import mffs.base.ItemBase; +import mffs.base.PacketFxs; +import mffs.base.PacketFxsHandler; +import mffs.base.PacketTile; +import mffs.base.PacketTileHandler; +import mffs.block.BlockBiometricIdentifier; +import mffs.block.BlockCoercionDeriver; +import mffs.block.BlockForceField; +import mffs.block.BlockForceFieldProjector; +import mffs.block.BlockForceManipulator; +import mffs.block.BlockFortronCapacitor; +import mffs.block.BlockInterdictionMatrix; +import mffs.card.ItemCard; +import mffs.fortron.FortronHelper; +import mffs.fortron.FrequencyGrid; +import mffs.item.ItemRemoteController; +import mffs.item.card.ItemCardFrequency; +import mffs.item.card.ItemCardID; +import mffs.item.card.ItemCardInfinite; +import mffs.item.card.ItemCardLink; +import mffs.item.mode.ItemMode; +import mffs.item.mode.ItemModeCube; +import mffs.item.mode.ItemModeSphere; +import mffs.item.mode.ItemModeTube; +import mffs.item.module.ItemModule; +import mffs.item.module.interdiction.ItemModuleAntiFriendly; +import mffs.item.module.interdiction.ItemModuleAntiHostile; +import mffs.item.module.interdiction.ItemModuleAntiPersonnel; +import mffs.item.module.interdiction.ItemModuleConfiscate; +import mffs.item.module.interdiction.ItemModuleInterdictionMatrix; +import mffs.item.module.interdiction.ItemModuleWarn; +import mffs.item.module.projector.ItemModeCustom; +import mffs.item.module.projector.ItemModeCylinder; +import mffs.item.module.projector.ItemModePyramid; +import mffs.item.module.projector.ItemModuleDisintegration; +import mffs.item.module.projector.ItemModuleFusion; +import mffs.item.module.projector.ItemModuleManipulator; +import mffs.item.module.projector.ItemModuleShock; +import mffs.item.module.projector.ItemModuleSponge; +import mffs.item.module.projector.ItemModuleStablize; +import mffs.tileentity.TileEntityBiometricIdentifier; +import mffs.tileentity.TileEntityCoercionDeriver; +import mffs.tileentity.TileEntityForceField; +import mffs.tileentity.TileEntityForceFieldProjector; +import mffs.tileentity.TileEntityForceManipulator; +import mffs.tileentity.TileEntityFortronCapacitor; +import mffs.tileentity.TileEntityInterdictionMatrix; +import net.minecraft.block.Block; +import net.minecraft.item.Item; +import net.minecraft.util.DamageSource; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidRegistry; +import universalelectricity.prefab.CustomDamageSource; +import universalelectricity.prefab.TranslationHelper; + +@Mod(modid = "MFFS", name = "Modular Force Field System", version = "3.1.0", + useMetadata = true) +public class ModularForceFieldSystem { + public static final String CHANNEL = "MFFS"; + public static final String ID = "MFFS"; + public static final String NAME = "Modular Force Field System"; + public static final String PREFIX = "mffs:"; + public static final String MAJOR_VERSION = "3"; + public static final String MINOR_VERSION = "1"; + public static final String REVISION_VERSION = "0"; + public static final String VERSION = "3.1.0"; + public static final String BUILD_VERSION = "175"; + @Mod.Instance("MFFS") public static ModularForceFieldSystem instance; + @Mod.Metadata("MFFS") public static ModMetadata metadata; + @SidedProxy(clientSide = "mffs.ClientProxy", serverSide = "mffs.CommonProxy") + public static CommonProxy proxy; + public static final Logger LOGGER; + public static final String RESOURCE_DIRECTORY = "/mods/mffs/"; + public static final String LANGUAGE_DIRECTORY = "/mods/mffs/languages/"; + public static final String TEXTURE_DIRECTORY = "/mods/mffs/textures/"; + public static final String BLOCK_DIRECTORY = "/mods/mffs/textures/blocks/"; + public static final String ITEM_DIRECTORY = "/mods/mffs/textures/items/"; + public static final String MODEL_DIRECTORY = "/mods/mffs/textures/models/"; + public static final String GUI_DIRECTORY = "/mods/mffs/textures/gui/"; + public static final String GUI_BASE_DIRECTORY = + "/mods/mffs/textures/gui/gui_base.png"; + public static final String GUI_COMPONENTS = + "/mods/mffs/textures/gui/gui_components.png"; + public static final String GUI_BUTTON = + "/mods/mffs/textures/gui/gui_button.png"; + public static BlockMachine blockCoercionDeriver; + public static BlockMachine blockFortronCapacitor; + public static BlockMachine blockForceFieldProjector; + public static BlockMachine blockBiometricIdentifier; + public static BlockMachine blockInterdictionMatrix; + public static BlockMachine blockForceManipulator; + public static BlockBase blockForceField; + public static Item itemRemoteController; + public static Item itemFocusMatrix; + public static ItemCard itemCardBlank; + public static ItemCard itemCardInfinite; + public static ItemCard itemCardFrequency; + public static ItemCard itemCardID; + public static ItemCard itemCardLink; + public static ItemMode itemModeCube; + public static ItemMode itemModeSphere; + public static ItemMode itemModeTube; + public static ItemMode itemModeCylinder; + public static ItemMode itemModePyramid; + public static ItemMode itemModeCustom; + public static ItemModule itemModuleSpeed; + public static ItemModule itemModuleCapacity; + public static ItemModule itemModuleTranslate; + public static ItemModule itemModuleScale; + public static ItemModule itemModuleRotate; + public static ItemModule itemModuleCollection; + public static ItemModule itemModuleInvert; + public static ItemModule itemModuleSilence; + public static ItemModule itemModuleFusion; + public static ItemModule itemModuleManipulator; + public static ItemModule itemModuleCamouflage; + public static ItemModule itemModuleDisintegration; + public static ItemModule itemModuleShock; + public static ItemModule itemModuleGlow; + public static ItemModule itemModuleSponge; + public static ItemModule itemModuleStablize; + public static ItemModule itemModuleAntiHostile; + public static ItemModule itemModuleAntiFriendly; + public static ItemModule itemModuleAntiPersonnel; + public static ItemModule itemModuleConfiscate; + public static ItemModule itemModuleWarn; + public static ItemModule itemModuleBlockAccess; + public static ItemModule itemModuleBlockAlter; + public static ItemModule itemModuleAntiSpawn; + public static DamageSource damagefieldShock; + + public static SimpleNetworkWrapper channel; + + @EventHandler + public void preInit(final FMLPreInitializationEvent event) { + NetworkRegistry.INSTANCE.registerGuiHandler( + (Object)this, (IGuiHandler)ModularForceFieldSystem.proxy); + MinecraftForge.EVENT_BUS.register((Object) new SubscribeEventHandler()); + Settings.load(); + Settings.CONFIGURATION.load(); + ModularForceFieldSystem.blockForceField = new BlockForceField(); + ModularForceFieldSystem.blockCoercionDeriver = new BlockCoercionDeriver(); + ModularForceFieldSystem.blockFortronCapacitor = new BlockFortronCapacitor(); + ModularForceFieldSystem.blockForceFieldProjector = + new BlockForceFieldProjector(); + ModularForceFieldSystem.blockBiometricIdentifier = + new BlockBiometricIdentifier(); + ModularForceFieldSystem.blockInterdictionMatrix = + new BlockInterdictionMatrix(); + ModularForceFieldSystem.blockForceManipulator = new BlockForceManipulator(); + ModularForceFieldSystem.itemRemoteController = new ItemRemoteController(); + ModularForceFieldSystem.itemFocusMatrix = new ItemBase("focusMatrix"); + ModularForceFieldSystem.itemModeCube = + new ItemModeCube(Settings.getNextItemID()); + ModularForceFieldSystem.itemModeSphere = + new ItemModeSphere(Settings.getNextItemID()); + ModularForceFieldSystem.itemModeTube = new ItemModeTube(); + ModularForceFieldSystem.itemModePyramid = new ItemModePyramid(); + ModularForceFieldSystem.itemModeCylinder = new ItemModeCylinder(); + ModularForceFieldSystem.itemModeCustom = new ItemModeCustom(); + ModularForceFieldSystem.itemModuleTranslate = + new ItemModule("moduleTranslate").setCost(1.6f); + ModularForceFieldSystem.itemModuleScale = + new ItemModule("moduleScale").setCost(1.2f); + ModularForceFieldSystem.itemModuleRotate = + new ItemModule("moduleRotate").setCost(0.1f); + ModularForceFieldSystem.itemModuleSpeed = + new ItemModule("moduleSpeed").setCost(1.0f); + ModularForceFieldSystem.itemModuleCapacity = + new ItemModule("moduleCapacity").setCost(0.5f); + ModularForceFieldSystem.itemModuleFusion = new ItemModuleFusion(); + ModularForceFieldSystem.itemModuleManipulator = new ItemModuleManipulator(); + ModularForceFieldSystem.itemModuleCamouflage = + new ItemModule("moduleCamouflage").setCost(1.5f).setMaxStackSize(1); + ModularForceFieldSystem.itemModuleDisintegration = + new ItemModuleDisintegration(); + ModularForceFieldSystem.itemModuleShock = new ItemModuleShock(); + ModularForceFieldSystem.itemModuleGlow = new ItemModule("moduleGlow"); + ModularForceFieldSystem.itemModuleSponge = new ItemModuleSponge(); + ModularForceFieldSystem.itemModuleStablize = new ItemModuleStablize(); + ModularForceFieldSystem.itemModuleAntiFriendly = + new ItemModuleAntiFriendly(); + ModularForceFieldSystem.itemModuleAntiHostile = new ItemModuleAntiHostile(); + ModularForceFieldSystem.itemModuleAntiPersonnel = + new ItemModuleAntiPersonnel(); + ModularForceFieldSystem.itemModuleConfiscate = new ItemModuleConfiscate(); + ModularForceFieldSystem.itemModuleWarn = new ItemModuleWarn(); + ModularForceFieldSystem.itemModuleBlockAccess = + new ItemModuleInterdictionMatrix("moduleBlockAccess").setCost(10.0f); + ModularForceFieldSystem.itemModuleBlockAlter = + new ItemModuleInterdictionMatrix("moduleBlockAlter").setCost(15.0f); + ModularForceFieldSystem.itemModuleAntiSpawn = + new ItemModuleInterdictionMatrix("moduleAntiSpawn").setCost(10.0f); + ModularForceFieldSystem.itemCardBlank = new ItemCard("cardBlank"); + ModularForceFieldSystem.itemCardFrequency = new ItemCardFrequency(); + ModularForceFieldSystem.itemCardLink = new ItemCardLink(); + ModularForceFieldSystem.itemCardID = new ItemCardID(); + ModularForceFieldSystem.itemCardInfinite = new ItemCardInfinite(); + FortronHelper.FLUID_FORTRON = new Fluid("fortron"); + ModularForceFieldSystem.itemModuleCollection = + new ItemModule("moduleCollection").setMaxStackSize(1).setCost(15.0f); + ModularForceFieldSystem.itemModuleInvert = + new ItemModule("moduleInvert").setMaxStackSize(1).setCost(15.0f); + ModularForceFieldSystem.itemModuleSilence = + new ItemModule("moduleSilence").setMaxStackSize(1).setCost(1.0f); + Settings.CONFIGURATION.save(); + GameRegistry.registerBlock((Block)ModularForceFieldSystem.blockForceField, + "blockForceField"); + GameRegistry.registerBlock( + (Block)ModularForceFieldSystem.blockCoercionDeriver, + + "blockCoercionDeriver"); + GameRegistry.registerBlock( + (Block)ModularForceFieldSystem.blockFortronCapacitor, + "blockFortronCapacitor"); + GameRegistry.registerBlock( + (Block)ModularForceFieldSystem.blockForceFieldProjector, + "blockForceFieldProjector"); + GameRegistry.registerBlock( + (Block)ModularForceFieldSystem.blockBiometricIdentifier, + "blockBiometricIdentifier"); + GameRegistry.registerBlock( + (Block)ModularForceFieldSystem.blockInterdictionMatrix, + "blockInterdictionMatrix"); + GameRegistry.registerBlock( + (Block)ModularForceFieldSystem.blockForceManipulator, + "blockForceManipulator" + + ); + GameRegistry.registerTileEntity(TileEntityForceField.class, + "tileForceField"); + GameRegistry.registerTileEntity(TileEntityCoercionDeriver.class, + "tileCoercionDeriver"); + GameRegistry.registerTileEntity(TileEntityFortronCapacitor.class, + "tileFortronCapacitor"); + GameRegistry.registerTileEntity(TileEntityForceFieldProjector.class, + "tileForceFieldProjector"); + GameRegistry.registerTileEntity(TileEntityBiometricIdentifier.class, + "tileBiometricIdentifier"); + GameRegistry.registerTileEntity(TileEntityInterdictionMatrix.class, + "tileInterdictionMatrix"); + GameRegistry.registerTileEntity(TileEntityForceManipulator.class, + "tileForceManipulator"); + ModularForceFieldSystem.proxy.preInit(); + + FluidRegistry.registerFluid(FortronHelper.FLUID_FORTRON); + + GameRegistry.registerItem(itemRemoteController, "itemRemoteController"); + GameRegistry.registerItem(itemFocusMatrix, "itemFocusMatix"); + GameRegistry.registerItem(itemCardBlank, "itemCardBlank"); + GameRegistry.registerItem(itemCardInfinite, "itemCardInfinite"); + GameRegistry.registerItem(itemCardFrequency, "itemCardFrequency"); + GameRegistry.registerItem(itemCardID, "itemCardID"); + GameRegistry.registerItem(itemCardLink, "itemCardLink"); + GameRegistry.registerItem(itemModeCube, "itemModeCube"); + GameRegistry.registerItem(itemModeSphere, "itemModeSphere"); + GameRegistry.registerItem(itemModeTube, "itemModeTube"); + GameRegistry.registerItem(itemModeCylinder, "itemModeCylinder"); + GameRegistry.registerItem(itemModePyramid, "itemModePyramid"); + GameRegistry.registerItem(itemModeCustom, "itemModeCustom"); + GameRegistry.registerItem(itemModuleSpeed, "itemModuleSpeed"); + GameRegistry.registerItem(itemModuleCapacity, "itemModuleCapacity"); + GameRegistry.registerItem(itemModuleTranslate, "itemModuleTranslate"); + GameRegistry.registerItem(itemModuleScale, "itemModuleScale"); + GameRegistry.registerItem(itemModuleRotate, "itemModuleRotate"); + GameRegistry.registerItem(itemModuleCollection, "itemModuleCollection"); + GameRegistry.registerItem(itemModuleInvert, "itemModuleInvert"); + GameRegistry.registerItem(itemModuleSilence, "itemModuleSilence"); + GameRegistry.registerItem(itemModuleFusion, "itemModuleFusion"); + GameRegistry.registerItem(itemModuleManipulator, "itemModuleManipulator"); + GameRegistry.registerItem(itemModuleCamouflage, "itemModuleCamouflage"); + GameRegistry.registerItem(itemModuleDisintegration, + "itemModuleDisintegration"); + GameRegistry.registerItem(itemModuleShock, "itemModuleShock"); + GameRegistry.registerItem(itemModuleGlow, "itemModuleGlow"); + GameRegistry.registerItem(itemModuleSponge, "itemModuleSponge"); + GameRegistry.registerItem(itemModuleStablize, "itemModuleStablize"); + GameRegistry.registerItem(itemModuleAntiHostile, "itemModuleAntiHostile"); + GameRegistry.registerItem(itemModuleAntiFriendly, "itemModuleAntiFriendly"); + GameRegistry.registerItem(itemModuleAntiPersonnel, + "itemModuleAntiPersonnel"); + GameRegistry.registerItem(itemModuleConfiscate, "itemModuleConfiscate"); + GameRegistry.registerItem(itemModuleWarn, "itemModuleWarn"); + GameRegistry.registerItem(itemModuleBlockAccess, "itemModuleBlockAccess"); + GameRegistry.registerItem(itemModuleBlockAlter, "itemModuleBlockAlter"); + GameRegistry.registerItem(itemModuleAntiSpawn, "itemModuleAntiSpawn"); + + channel = + NetworkRegistry.INSTANCE.newSimpleChannel("ModularForceFieldSystem"); + + int pkgDiscriminator = 0; + channel.registerMessage(PacketTileHandler.class, PacketTile.class, + pkgDiscriminator++, Side.SERVER); + channel.registerMessage(PacketFxsHandler.class, PacketFxs.class, + pkgDiscriminator++, Side.CLIENT); + } + + @EventHandler + public void load(final FMLInitializationEvent evt) { + ModularForceFieldSystem.LOGGER.fine( + "Language(s) Loaded: " + + TranslationHelper.loadLanguages( + "/assets/mffs/lang/", new String[] {"en_US", "zh_CN", "de_DE"})); + ModularForceFieldSystem.metadata.modId = "MFFS"; + ModularForceFieldSystem.metadata.name = "Modular Force Field System"; + ModularForceFieldSystem.metadata.description = + "Modular Force Field System is a mod that adds force fields, high tech machinery and defensive measures to Minecraft."; + ModularForceFieldSystem.metadata.url = + "http://www.universalelectricity.com/mffs/"; + ModularForceFieldSystem.metadata.logoFile = "/mffs_logo.png"; + ModularForceFieldSystem.metadata.version = "3.1.0.175"; + ModularForceFieldSystem.metadata.authorList = Arrays.asList("Calclavia"); + ModularForceFieldSystem.metadata.credits = "Please visit the website."; + ModularForceFieldSystem.metadata.autogenerated = false; + } + + @EventHandler + public void postInit(final FMLPostInitializationEvent evt) { + UniversalRecipes.init(); + Recipes.registerRecipes(); + ModularForceFieldSystem.proxy.init(); + } + + @EventHandler + public void serverStarting(final FMLServerStartingEvent evt) { + FrequencyGrid.reinitiate(); + } + + static { + LOGGER = Logger.getLogger("Modular Force Field System"); + ModularForceFieldSystem.damagefieldShock = + new CustomDamageSource("fieldShock").setDamageBypassesArmor(); + } +} diff --git a/src/main/java/mffs/Recipes.java b/src/main/java/mffs/Recipes.java new file mode 100644 index 0000000..fde741e --- /dev/null +++ b/src/main/java/mffs/Recipes.java @@ -0,0 +1,331 @@ +package mffs; + +import basiccomponents.common.BasicComponents; +import mffs.recipe.RecipeBuilder; +import mffs.recipe.ShapedOreRecipeAdapter; +import mffs.recipe.ShapelessOreRecipeAdapter; +import net.minecraft.init.Blocks; +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; + +public class Recipes { + public static void registerRecipes() { + new RecipeBuilder(new ShapedOreRecipeAdapter()) + .output(ModularForceFieldSystem.itemFocusMatrix, 9) + .pattern("RMR", "MDM", "RMR") + .ingredient('M', "ingotSteel") + .ingredient('D', Items.diamond) + .ingredient('R', Items.redstone) + .register(); + + new RecipeBuilder(new ShapedOreRecipeAdapter()) + .output(ModularForceFieldSystem.itemRemoteController) + .pattern("WWW", "MCM", "MCM") + .ingredient('W', BasicComponents.blockCopperWire) + .ingredient('M', "ingotSteel") + .ingredient('C', BasicComponents.itemBattery) + .register(); + + new RecipeBuilder(new ShapedOreRecipeAdapter()) + .output(ModularForceFieldSystem.blockCoercionDeriver) + .pattern("M M", "MFM", "MCM") + .ingredient('C', BasicComponents.itemBattery) + .ingredient('M', "ingotSteel") + .ingredient('F', ModularForceFieldSystem.itemFocusMatrix) + .register(); + + new RecipeBuilder(new ShapedOreRecipeAdapter()) + .output(ModularForceFieldSystem.blockFortronCapacitor) + .pattern("MFM", "FCF", "MFM") + .ingredient('C', BasicComponents.itemBattery) + .ingredient('F', ModularForceFieldSystem.itemFocusMatrix) + .ingredient('M', "ingotSteel") + .register(); + + new RecipeBuilder(new ShapedOreRecipeAdapter()) + .output(ModularForceFieldSystem.blockForceFieldProjector) + .pattern(" D ", "FFF", "MCM") + .ingredient('D', Items.diamond) + .ingredient('C', BasicComponents.itemBattery) + .ingredient('F', ModularForceFieldSystem.itemFocusMatrix) + .ingredient('M', "ingotSteel") + .register(); + + new RecipeBuilder(new ShapedOreRecipeAdapter()) + .output(ModularForceFieldSystem.blockBiometricIdentifier) + .pattern("FMF", "MCM", "FMF") + .ingredient('C', ModularForceFieldSystem.itemCardBlank) + .ingredient('M', "ingotSteel") + .ingredient('F', ModularForceFieldSystem.itemFocusMatrix) + .register(); + + new RecipeBuilder(new ShapedOreRecipeAdapter()) + .output(ModularForceFieldSystem.blockInterdictionMatrix) + .pattern("SSS", "FFF", "FEF") + .ingredient('S', ModularForceFieldSystem.itemModuleShock) + .ingredient('E', Blocks.ender_chest) + .ingredient('F', ModularForceFieldSystem.itemFocusMatrix) + .register(); + + new RecipeBuilder(new ShapedOreRecipeAdapter()) + .output(ModularForceFieldSystem.blockForceManipulator) + .pattern("F F", "FMF", "F F") + .ingredient('F', ModularForceFieldSystem.itemFocusMatrix) + .ingredient('M', BasicComponents.itemMotor) + .register(); + + new RecipeBuilder(new ShapedOreRecipeAdapter()) + .output(ModularForceFieldSystem.itemCardBlank) + .pattern("PPP", "PMP", "PPP") + .ingredient('M', "ingotSteel") + .ingredient('P', Items.paper) + .register(); + + new RecipeBuilder(new ShapedOreRecipeAdapter()) + .output(ModularForceFieldSystem.itemCardLink) + .pattern("BWB") + .ingredient('B', ModularForceFieldSystem.itemCardBlank) + .ingredient('W', BasicComponents.blockCopperWire) + .register(); + + new RecipeBuilder(new ShapedOreRecipeAdapter()) + .output(ModularForceFieldSystem.itemCardLink) + .pattern("WBW") + .ingredient('B', ModularForceFieldSystem.itemCardFrequency) + .ingredient('W', BasicComponents.blockCopperWire) + .register(); + + new RecipeBuilder(new ShapedOreRecipeAdapter()) + .output(ModularForceFieldSystem.itemCardID) + .pattern("RBR") + .ingredient('B', ModularForceFieldSystem.itemCardBlank) + .ingredient('R', Items.redstone) + .register(); + + new RecipeBuilder(new ShapedOreRecipeAdapter()) + .output(ModularForceFieldSystem.itemModeSphere) + .pattern(" F ", "FFF", " F ") + .ingredient('F', ModularForceFieldSystem.itemFocusMatrix) + .register(); + + new RecipeBuilder(new ShapedOreRecipeAdapter()) + .output(ModularForceFieldSystem.itemModeCube) + .pattern("FFF", "FFF", "FFF") + .ingredient('F', ModularForceFieldSystem.itemFocusMatrix) + .register(); + + new RecipeBuilder(new ShapedOreRecipeAdapter()) + .output(ModularForceFieldSystem.itemModeTube) + .pattern("FFF", " ", "FFF") + .ingredient('F', ModularForceFieldSystem.itemFocusMatrix) + .register(); + + new RecipeBuilder(new ShapedOreRecipeAdapter()) + .output(ModularForceFieldSystem.itemModePyramid) + .pattern("F ", "FF ", "FFF") + .ingredient('F', ModularForceFieldSystem.itemFocusMatrix) + .register(); + + new RecipeBuilder(new ShapedOreRecipeAdapter()) + .output(ModularForceFieldSystem.itemModeCylinder) + .pattern("S", "S", "S") + .ingredient('S', ModularForceFieldSystem.itemModeSphere) + .register(); + + new RecipeBuilder(new ShapedOreRecipeAdapter()) + .output(ModularForceFieldSystem.itemModeCustom) + .pattern(" C ", "TFP", " S ") + .ingredient('S', ModularForceFieldSystem.itemModeSphere) + .ingredient('C', ModularForceFieldSystem.itemModeCube) + .ingredient('T', ModularForceFieldSystem.itemModeTube) + .ingredient('P', ModularForceFieldSystem.itemModePyramid) + .ingredient('F', ModularForceFieldSystem.itemFocusMatrix) + .register(); + + new RecipeBuilder(new ShapelessOreRecipeAdapter()) + .output(ModularForceFieldSystem.itemModeCustom) + .ingredient(ModularForceFieldSystem.itemModeCustom) + .register(); + + new RecipeBuilder(new ShapedOreRecipeAdapter()) + .output(ModularForceFieldSystem.itemModuleSpeed) + .pattern("FFF", "RRR", "FFF") + .ingredient('F', ModularForceFieldSystem.itemFocusMatrix) + .ingredient('R', Items.redstone) + .register(); + + new RecipeBuilder(new ShapedOreRecipeAdapter()) + .output(ModularForceFieldSystem.itemModuleCapacity) + .pattern("FCF") + .ingredient('F', ModularForceFieldSystem.itemFocusMatrix) + .ingredient('C', BasicComponents.itemBattery) + .register(); + + new RecipeBuilder(new ShapedOreRecipeAdapter()) + .output(ModularForceFieldSystem.itemModuleShock) + .pattern("FWF") + .ingredient('F', ModularForceFieldSystem.itemFocusMatrix) + .ingredient('W', BasicComponents.blockCopperWire) + .register(); + + new RecipeBuilder(new ShapedOreRecipeAdapter()) + .output(ModularForceFieldSystem.itemModuleSponge) + .pattern("BBB", "BFB", "BBB") + .ingredient('F', ModularForceFieldSystem.itemFocusMatrix) + .ingredient('B', Items.water_bucket) + .register(); + + new RecipeBuilder(new ShapedOreRecipeAdapter()) + .output(ModularForceFieldSystem.itemModuleDisintegration) + .pattern(" W ", "FBF", " W ") + .ingredient('F', ModularForceFieldSystem.itemFocusMatrix) + .ingredient('W', BasicComponents.blockCopperWire) + .ingredient('B', BasicComponents.itemBattery) + .register(); + + new RecipeBuilder(new ShapedOreRecipeAdapter()) + .output(ModularForceFieldSystem.itemModuleManipulator) + .pattern("F", " ", "F") + .ingredient('F', ModularForceFieldSystem.itemFocusMatrix) + .register(); + + new RecipeBuilder(new ShapedOreRecipeAdapter()) + .output(ModularForceFieldSystem.itemModuleCamouflage) + .pattern("WFW", "FWF", "WFW") + .ingredient('F', ModularForceFieldSystem.itemFocusMatrix) + .ingredient('W', new ItemStack(Blocks.wool, 1, 32767)) + .register(); + + new RecipeBuilder(new ShapedOreRecipeAdapter()) + .output(ModularForceFieldSystem.itemModuleFusion) + .pattern("FJF") + .ingredient('F', ModularForceFieldSystem.itemFocusMatrix) + .ingredient('J', ModularForceFieldSystem.itemModuleShock) + .register(); + + new RecipeBuilder(new ShapedOreRecipeAdapter()) + .output(ModularForceFieldSystem.itemModuleScale, 2) + .pattern("FRF") + .ingredient('F', ModularForceFieldSystem.itemFocusMatrix) + .ingredient( + 'R', + Items.redstone) // this is a guess, R isnt defined in the original + .register(); + + new RecipeBuilder(new ShapedOreRecipeAdapter()) + .output(ModularForceFieldSystem.itemModuleTranslate, 2) + .pattern("FSF") + .ingredient('F', ModularForceFieldSystem.itemFocusMatrix) + .ingredient('S', ModularForceFieldSystem.itemModuleScale) + .register(); + + new RecipeBuilder(new ShapedOreRecipeAdapter()) + .output(ModularForceFieldSystem.itemModuleRotate) + .pattern("F ", " F", " F") + .ingredient('F', ModularForceFieldSystem.itemFocusMatrix) + .register(); + + new RecipeBuilder(new ShapedOreRecipeAdapter()) + .output(ModularForceFieldSystem.itemModuleGlow) + .pattern("GGG", "GFG", "GGG") + .ingredient('F', ModularForceFieldSystem.itemFocusMatrix) + .ingredient('G', Blocks.glowstone) + .register(); + + new RecipeBuilder(new ShapedOreRecipeAdapter()) + .output(ModularForceFieldSystem.itemModuleStablize) + .pattern("FDF", "PSA", "FDF") + .ingredient('F', ModularForceFieldSystem.itemFocusMatrix) + .ingredient('P', Items.diamond_pickaxe) + .ingredient('S', Items.diamond_shovel) + .ingredient('A', Items.diamond_axe) + .register(); + + new RecipeBuilder(new ShapedOreRecipeAdapter()) + .output(ModularForceFieldSystem.itemModuleCollection) + .pattern("F F", " H ", "F F") + .ingredient('F', ModularForceFieldSystem.itemFocusMatrix) + .ingredient('H', Blocks.hopper) + .register(); + + new RecipeBuilder(new ShapedOreRecipeAdapter()) + .output(ModularForceFieldSystem.itemModuleInvert) + .pattern("L", "F", "L") + .ingredient('F', ModularForceFieldSystem.itemFocusMatrix) + .ingredient('L', Blocks.lapis_block) + .register(); + + new RecipeBuilder(new ShapedOreRecipeAdapter()) + .output(ModularForceFieldSystem.itemModuleSilence) + .pattern(" N ", "NFN", " N ") + .ingredient('F', ModularForceFieldSystem.itemFocusMatrix) + .ingredient('N', Blocks.noteblock) + .register(); + + new RecipeBuilder(new ShapedOreRecipeAdapter()) + .output(ModularForceFieldSystem.itemModuleAntiHostile) + .pattern(" R ", "GFB", " S ") + .ingredient('F', ModularForceFieldSystem.itemFocusMatrix) + .ingredient('G', Items.gunpowder) + .ingredient('R', Items.rotten_flesh) + .ingredient('B', Items.bone) + .ingredient('S', Items.ghast_tear) + .register(); + + new RecipeBuilder(new ShapedOreRecipeAdapter()) + .output(ModularForceFieldSystem.itemModuleAntiFriendly) + .pattern(" R ", "GFB", " S ") + .ingredient('F', ModularForceFieldSystem.itemFocusMatrix) + .ingredient('G', Items.cooked_porkchop) + .ingredient('R', new ItemStack(Blocks.wool, 1, 32767)) + .ingredient('B', Items.leather) + .ingredient('S', Items.slime_ball) + .register(); + + new RecipeBuilder(new ShapedOreRecipeAdapter()) + .output(ModularForceFieldSystem.itemModuleAntiPersonnel) + .pattern("BFG") + .ingredient('F', ModularForceFieldSystem.itemFocusMatrix) + .ingredient('B', ModularForceFieldSystem.itemModuleAntiHostile) + .ingredient('G', ModularForceFieldSystem.itemModuleAntiFriendly) + .register(); + + // TODO: config option for confiscate module + new RecipeBuilder(new ShapedOreRecipeAdapter()) + .output(ModularForceFieldSystem.itemModuleConfiscate) + .pattern("PEP", "EFE", "PEP") + .ingredient('F', ModularForceFieldSystem.itemFocusMatrix) + .ingredient('E', Items.ender_eye) + .ingredient('P', Items.ender_pearl) + .register(); + + new RecipeBuilder(new ShapedOreRecipeAdapter()) + .output(ModularForceFieldSystem.itemModuleWarn) + .pattern("NFN") + .ingredient('F', ModularForceFieldSystem.itemFocusMatrix) + .ingredient('N', Blocks.noteblock) + .register(); + + new RecipeBuilder(new ShapedOreRecipeAdapter()) + .output(ModularForceFieldSystem.itemModuleBlockAccess) + .pattern(" C ", "BFB", " C ") + .ingredient('F', ModularForceFieldSystem.itemFocusMatrix) + .ingredient('B', Blocks.iron_block) + .ingredient('C', Blocks.chest) + .register(); + + new RecipeBuilder(new ShapedOreRecipeAdapter()) + .output(ModularForceFieldSystem.itemModuleBlockAlter) + .pattern(" G ", "GFG", " G ") + .ingredient('F', ModularForceFieldSystem.itemFocusMatrix) + .ingredient('G', Blocks.gold_block) + .register(); + + new RecipeBuilder(new ShapedOreRecipeAdapter()) + .output(ModularForceFieldSystem.itemModuleAntiSpawn) + .pattern(" H ", "G G", " H ") + .ingredient('H', ModularForceFieldSystem.itemModuleAntiHostile) + .ingredient('G', ModularForceFieldSystem.itemModuleAntiFriendly) + .register(); + } +} diff --git a/src/main/java/mffs/Settings.java b/src/main/java/mffs/Settings.java new file mode 100644 index 0000000..4b19b6c --- /dev/null +++ b/src/main/java/mffs/Settings.java @@ -0,0 +1,176 @@ +package mffs; + +import cpw.mods.fml.common.Loader; +import java.io.File; +import mffs.api.Blacklist; +import net.minecraft.block.Block; +import net.minecraft.init.Blocks; +import net.minecraftforge.common.config.Configuration; +import net.minecraftforge.common.config.Property; + +public class Settings { + public static final Configuration CONFIGURATION; + public static final int BLOCK_ID_PREFIX = 1680; + public static final int ITEM_ID_PREFIX = 11130; + private static int NEXT_BLOCK_ID; + private static int NEXT_ITEM_ID; + public static int MAX_FORCE_FIELDS_PER_TICK; + public static int MAX_FORCE_FIELD_SCALE; + public static boolean INTERACT_CREATIVE; + public static boolean LOAD_CHUNKS; + public static boolean OP_OVERRIDE; + public static boolean USE_CACHE; + public static boolean ENABLE_ELECTRICITY; + public static boolean CONSERVE_PACKETS; + public static boolean HIGH_GRAPHICS; + public static int INTERDICTION_MURDER_ENERGY; + public static final int MAX_FREQUENCY_DIGITS = 6; + public static boolean ENABLE_MANIPULATOR; + + public static int getNextBlockID() { return ++Settings.NEXT_BLOCK_ID; } + + public static int getNextItemID() { return ++Settings.NEXT_ITEM_ID; } + + public static void load() { + Settings.CONFIGURATION.load(); + Settings.ENABLE_MANIPULATOR = + Settings.CONFIGURATION + .get("general", "Enable Force Manipulator", + Settings.ENABLE_MANIPULATOR) + .getBoolean(Settings.ENABLE_MANIPULATOR); + final Property propFieldScale = Settings.CONFIGURATION.get( + "general", "Max Force Field Scale", Settings.MAX_FORCE_FIELD_SCALE); + Settings.MAX_FORCE_FIELD_SCALE = + propFieldScale.getInt(Settings.MAX_FORCE_FIELD_SCALE); + final Property propInterdiction = Settings.CONFIGURATION.get( + "general", "Interdiction Murder Fortron Consumption", + Settings.INTERDICTION_MURDER_ENERGY); + Settings.INTERDICTION_MURDER_ENERGY = + propInterdiction.getInt(Settings.INTERDICTION_MURDER_ENERGY); + final Property propCreative = Settings.CONFIGURATION.get( + "general", "Effect Creative Players", Settings.INTERACT_CREATIVE); + propCreative.comment = + "Should the interdiction matrix interact with creative players?."; + Settings.INTERACT_CREATIVE = + propCreative.getBoolean(Settings.INTERACT_CREATIVE); + final Property propChunkLoading = Settings.CONFIGURATION.get( + "general", "Load Chunks", Settings.LOAD_CHUNKS); + propChunkLoading.comment = + "Set this to false to turn off the MFFS Chunkloading capabilities."; + Settings.LOAD_CHUNKS = propChunkLoading.getBoolean(Settings.LOAD_CHUNKS); + final Property propOpOverride = Settings.CONFIGURATION.get( + "general", "Op Override", Settings.OP_OVERRIDE); + propOpOverride.comment = + "Allow the operator(s) to override security measures created by MFFS?"; + Settings.OP_OVERRIDE = propOpOverride.getBoolean(Settings.OP_OVERRIDE); + final Property propUseCache = + Settings.CONFIGURATION.get("general", "Use Cache", Settings.USE_CACHE); + propUseCache.comment = + "Cache allows temporary data saving to decrease calculations required."; + Settings.USE_CACHE = propUseCache.getBoolean(Settings.USE_CACHE); + final Property maxFFGenPerTick = + Settings.CONFIGURATION.get("general", "Field Calculation Per Tick", + Settings.MAX_FORCE_FIELDS_PER_TICK); + maxFFGenPerTick.comment = + "How many force field blocks can be generated per tick? Less reduces lag."; + Settings.MAX_FORCE_FIELDS_PER_TICK = + maxFFGenPerTick.getInt(Settings.MAX_FORCE_FIELDS_PER_TICK); + final Property useElectricity = Settings.CONFIGURATION.get( + "general", "Require Electricity?", Settings.ENABLE_ELECTRICITY); + useElectricity.comment = + "Turning this to false will make MFFS run without electricity or energy systems required. Great for vanilla!"; + Settings.ENABLE_ELECTRICITY = + useElectricity.getBoolean(Settings.ENABLE_ELECTRICITY); + final Property conservePackets = Settings.CONFIGURATION.get( + "general", "Conserve Packets?", Settings.CONSERVE_PACKETS); + conservePackets.comment = + "Turning this to false will enable better client side packet and updates but in the cost of more packets sent."; + Settings.CONSERVE_PACKETS = + conservePackets.getBoolean(Settings.CONSERVE_PACKETS); + final Property highGraphics = Settings.CONFIGURATION.get( + "general", "High Graphics", Settings.HIGH_GRAPHICS); + highGraphics.comment = + "Turning this to false will reduce rendering and client side packet graphical packets."; + Settings.CONSERVE_PACKETS = highGraphics.getBoolean(Settings.HIGH_GRAPHICS); + final Property forceManipulatorBlacklist = Settings.CONFIGURATION.get( + "general", "Force Manipulator Blacklist", ""); + highGraphics.comment = + "Put a list of block IDs to be not-moved by the force manipulator. Separate by commas, no space."; + final String blackListString = forceManipulatorBlacklist.getString(); + if (blackListString != null) { + for (final String blockIDString : blackListString.split(",")) { + Block b = Block.getBlockFromName(blockIDString); + if (b == null) { + ModularForceFieldSystem.LOGGER.severe( + "Invalid block blacklist ID \'" + blockIDString + "\'!"); + continue; + } + + Blacklist.forceManipulationBlacklist.add(b); + } + } + + final Property blacklist1 = + Settings.CONFIGURATION.get("general", "Stabilization Blacklist", ""); + final String blackListString2 = blacklist1.getString(); + if (blackListString2 != null) { + for (final String blockIDString2 : blackListString2.split(",")) { + Block b = Block.getBlockFromName(blockIDString2); + if (b == null) { + ModularForceFieldSystem.LOGGER.severe( + "Invalid block blacklist ID \'" + blockIDString2 + "\'!"); + continue; + } + + Blacklist.stabilizationBlacklist.add(b); + } + } + final Property blacklist2 = + Settings.CONFIGURATION.get("general", "Disintegration Blacklist", ""); + final String blackListString3 = blacklist2.getString(); + if (blackListString3 != null) { + for (final String blockIDString3 : blackListString3.split(",")) { + if (blockIDString3 != null && !blockIDString3.isEmpty()) { + Block b = Block.getBlockFromName(blockIDString3); + if (b == null) { + ModularForceFieldSystem.LOGGER.severe( + "Invalid block blacklist ID \'" + blockIDString3 + "\'!"); + continue; + } + + Blacklist.disintegrationBlacklist.add(b); + } + } + } + Blacklist.stabilizationBlacklist.add(Blocks.water); + Blacklist.stabilizationBlacklist.add(Blocks.flowing_water); + Blacklist.stabilizationBlacklist.add(Blocks.lava); + Blacklist.stabilizationBlacklist.add(Blocks.flowing_lava); + Blacklist.disintegrationBlacklist.add(Blocks.water); + Blacklist.disintegrationBlacklist.add(Blocks.flowing_water); + Blacklist.disintegrationBlacklist.add(Blocks.lava); + Blacklist.stabilizationBlacklist.add(Blocks.flowing_lava); + Blacklist.forceManipulationBlacklist.add(Blocks.bedrock); + Blacklist.forceManipulationBlacklist.add( + ModularForceFieldSystem.blockForceField); + Settings.CONFIGURATION.save(); + } + + static { + CONFIGURATION = new Configuration(new File( + Loader.instance().getConfigDir(), "Modular Force Field System.cfg")); + Settings.NEXT_BLOCK_ID = 1680; + Settings.NEXT_ITEM_ID = 11130; + Settings.MAX_FORCE_FIELDS_PER_TICK = 1000; + Settings.MAX_FORCE_FIELD_SCALE = 200; + Settings.INTERACT_CREATIVE = true; + Settings.LOAD_CHUNKS = true; + Settings.OP_OVERRIDE = true; + Settings.USE_CACHE = true; + Settings.ENABLE_ELECTRICITY = true; + Settings.CONSERVE_PACKETS = true; + Settings.HIGH_GRAPHICS = true; + Settings.INTERDICTION_MURDER_ENERGY = 0; + Settings.ENABLE_MANIPULATOR = true; + } +} diff --git a/src/main/java/mffs/SubscribeEventHandler.java b/src/main/java/mffs/SubscribeEventHandler.java new file mode 100644 index 0000000..4f2994b --- /dev/null +++ b/src/main/java/mffs/SubscribeEventHandler.java @@ -0,0 +1,86 @@ +package mffs; + +import cpw.mods.fml.common.eventhandler.Event.Result; +import cpw.mods.fml.common.eventhandler.SubscribeEvent; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import mffs.api.security.IInterdictionMatrix; +import mffs.api.security.Permission; +import net.minecraft.block.Block; +import net.minecraft.entity.Entity; +import net.minecraft.util.ChatComponentText; +import net.minecraft.world.IBlockAccess; +import net.minecraftforge.client.event.TextureStitchEvent; +import net.minecraftforge.event.entity.living.LivingSpawnEvent; +import net.minecraftforge.event.entity.player.PlayerEvent; +import net.minecraftforge.event.entity.player.PlayerInteractEvent; +import net.minecraftforge.fluids.FluidRegistry; +import universalelectricity.core.vector.Vector3; + +public class SubscribeEventHandler { + @SubscribeEvent + @SideOnly(Side.CLIENT) + public void textureHook(final TextureStitchEvent.Pre event) { + if (event.map.getTextureType() == 1) { + FluidRegistry.getFluid("fortron").setIcons( + event.map.registerIcon("mffs:fortron")); + } + } + + @SubscribeEvent + public void playerInteractEvent(final PlayerInteractEvent evt) { + if (evt.action == PlayerInteractEvent.Action.RIGHT_CLICK_BLOCK || + evt.action == PlayerInteractEvent.Action.LEFT_CLICK_BLOCK) { + if (evt.action == PlayerInteractEvent.Action.LEFT_CLICK_BLOCK && + ((Entity)((PlayerEvent)evt).entityPlayer) + .worldObj.getBlock(evt.x, evt.y, evt.z) == + ModularForceFieldSystem.blockForceField) { + evt.setCanceled(true); + return; + } + if (((PlayerEvent)evt).entityPlayer.capabilities.isCreativeMode) { + return; + } + final Vector3 position = new Vector3(evt.x, evt.y, evt.z); + final IInterdictionMatrix interdictionMatrix = + MFFSHelper.getNearestInterdictionMatrix( + ((Entity)((PlayerEvent)evt).entityPlayer).worldObj, position); + if (interdictionMatrix != null) { + final Block block = position.getBlock( + (IBlockAccess)((Entity)((PlayerEvent)evt).entityPlayer).worldObj); + if (ModularForceFieldSystem.blockBiometricIdentifier == block && + MFFSHelper.isPermittedByInterdictionMatrix( + interdictionMatrix, + ((PlayerEvent)evt).entityPlayer.getDisplayName(), + Permission.SECURITY_CENTER_CONFIGURE)) { + return; + } + final boolean hasPermission = MFFSHelper.hasPermission( + ((Entity)((PlayerEvent)evt).entityPlayer).worldObj, + new Vector3(evt.x, evt.y, evt.z), interdictionMatrix, evt.action, + ((PlayerEvent)evt).entityPlayer); + if (!hasPermission) { + ((PlayerEvent)evt) + .entityPlayer.addChatMessage(new ChatComponentText( + "[" + + ModularForceFieldSystem.blockInterdictionMatrix + .getLocalizedName() + + "] You have no permission to do that!")); + evt.setCanceled(true); + } + } + } + } + + @SubscribeEvent + public void livingSpawnEvent(final LivingSpawnEvent evt) { + final IInterdictionMatrix interdictionMatrix = + MFFSHelper.getNearestInterdictionMatrix( + evt.world, new Vector3((Entity)evt.entityLiving)); + if (interdictionMatrix != null && + interdictionMatrix.getModuleCount( + ModularForceFieldSystem.itemModuleAntiSpawn, new int[0]) > 0) { + evt.setResult(Result.DENY); + } + } +} diff --git a/src/main/java/mffs/TransferMode.java b/src/main/java/mffs/TransferMode.java new file mode 100644 index 0000000..59995ce --- /dev/null +++ b/src/main/java/mffs/TransferMode.java @@ -0,0 +1,16 @@ +package mffs; + +public enum TransferMode { + EQUALIZE, + DISTRIBUTE, + DRAIN, + FILL; + + public TransferMode toggle() { + int newOrdinal = this.ordinal() + 1; + if (newOrdinal >= values().length) { + newOrdinal = 0; + } + return values()[newOrdinal]; + } +} diff --git a/src/main/java/mffs/api/Blacklist.java b/src/main/java/mffs/api/Blacklist.java new file mode 100644 index 0000000..01e2033 --- /dev/null +++ b/src/main/java/mffs/api/Blacklist.java @@ -0,0 +1,19 @@ +package mffs.api; + +import java.util.HashSet; +import java.util.Set; + +import net.minecraft.block.Block; + +public class Blacklist +{ + public static final Set stabilizationBlacklist; + public static final Set disintegrationBlacklist; + public static final Set forceManipulationBlacklist; + + static { + stabilizationBlacklist = new HashSet<>(); + disintegrationBlacklist = new HashSet<>(); + forceManipulationBlacklist = new HashSet<>(); + } +} diff --git a/src/main/java/mffs/api/IActivatable.java b/src/main/java/mffs/api/IActivatable.java new file mode 100644 index 0000000..c5e4068 --- /dev/null +++ b/src/main/java/mffs/api/IActivatable.java @@ -0,0 +1,8 @@ +package mffs.api; + +public interface IActivatable +{ + boolean isActive(); + + void setActive(final boolean p0); +} diff --git a/src/main/java/mffs/api/IBiometricIdentifierLink.java b/src/main/java/mffs/api/IBiometricIdentifierLink.java new file mode 100644 index 0000000..884e934 --- /dev/null +++ b/src/main/java/mffs/api/IBiometricIdentifierLink.java @@ -0,0 +1,11 @@ +package mffs.api; + +import java.util.Set; +import mffs.api.security.IBiometricIdentifier; + +public interface IBiometricIdentifierLink +{ + IBiometricIdentifier getBiometricIdentifier(); + + Set getBiometricIdentifiers(); +} diff --git a/src/main/java/mffs/api/ICache.java b/src/main/java/mffs/api/ICache.java new file mode 100644 index 0000000..06a06d5 --- /dev/null +++ b/src/main/java/mffs/api/ICache.java @@ -0,0 +1,10 @@ +package mffs.api; + +public interface ICache +{ + Object getCache(final String p0); + + void clearCache(final String p0); + + void clearCache(); +} diff --git a/src/main/java/mffs/api/IFieldInteraction.java b/src/main/java/mffs/api/IFieldInteraction.java new file mode 100644 index 0000000..e6c92a4 --- /dev/null +++ b/src/main/java/mffs/api/IFieldInteraction.java @@ -0,0 +1,41 @@ +package mffs.api; + +import java.util.Set; +import universalelectricity.core.vector.Vector3; +import mffs.api.modules.IModule; +import net.minecraft.item.ItemStack; +import net.minecraftforge.common.util.ForgeDirection; +import mffs.api.modules.IProjectorMode; +import universalelectricity.prefab.implement.IRotatable; +import mffs.api.modules.IModuleAcceptor; + +public interface IFieldInteraction extends IModuleAcceptor, IRotatable, IActivatable +{ + IProjectorMode getMode(); + + ItemStack getModeStack(); + + int[] getSlotsBasedOnDirection(final ForgeDirection p0); + + int[] getModuleSlots(); + + int getSidedModuleCount(final IModule p0, final ForgeDirection... p1); + + Vector3 getTranslation(); + + Vector3 getPositiveScale(); + + Vector3 getNegativeScale(); + + int getRotationYaw(); + + int getRotationPitch(); + + Set getCalculatedField(); + + Set getInteriorPoints(); + + void setCalculating(final boolean p0); + + void setCalculated(final boolean p0); +} diff --git a/src/main/java/mffs/api/IForceFieldBlock.java b/src/main/java/mffs/api/IForceFieldBlock.java new file mode 100644 index 0000000..d6965fa --- /dev/null +++ b/src/main/java/mffs/api/IForceFieldBlock.java @@ -0,0 +1,11 @@ +package mffs.api; + +import net.minecraft.world.World; +import net.minecraft.world.IBlockAccess; + +public interface IForceFieldBlock +{ + IProjector getProjector(final IBlockAccess p0, final int p1, final int p2, final int p3); + + void weakenForceField(final World p0, final int p1, final int p2, final int p3, final int p4); +} diff --git a/src/main/java/mffs/api/IProjector.java b/src/main/java/mffs/api/IProjector.java new file mode 100644 index 0000000..0199e80 --- /dev/null +++ b/src/main/java/mffs/api/IProjector.java @@ -0,0 +1,14 @@ +package mffs.api; + +import net.minecraft.inventory.IInventory; + +public interface IProjector extends IInventory, IBiometricIdentifierLink, IFieldInteraction +{ + void projectField(); + + void destroyField(); + + int getProjectionSpeed(); + + long getTicks(); +} diff --git a/src/main/java/mffs/api/ISpecialForceManipulation.java b/src/main/java/mffs/api/ISpecialForceManipulation.java new file mode 100644 index 0000000..3210b48 --- /dev/null +++ b/src/main/java/mffs/api/ISpecialForceManipulation.java @@ -0,0 +1,10 @@ +package mffs.api; + +public interface ISpecialForceManipulation +{ + boolean preMove(final int p0, final int p1, final int p2); + + void move(final int p0, final int p1, final int p2); + + void postMove(); +} diff --git a/src/main/java/mffs/api/card/ICard.java b/src/main/java/mffs/api/card/ICard.java new file mode 100644 index 0000000..4c47839 --- /dev/null +++ b/src/main/java/mffs/api/card/ICard.java @@ -0,0 +1,5 @@ +package mffs.api.card; + +public interface ICard +{ +} diff --git a/src/main/java/mffs/api/card/ICardIdentification.java b/src/main/java/mffs/api/card/ICardIdentification.java new file mode 100644 index 0000000..06c8d87 --- /dev/null +++ b/src/main/java/mffs/api/card/ICardIdentification.java @@ -0,0 +1,17 @@ +package mffs.api.card; + +import mffs.api.security.Permission; +import net.minecraft.item.ItemStack; + +public interface ICardIdentification extends ICard +{ + boolean hasPermission(final ItemStack p0, final Permission p1); + + boolean addPermission(final ItemStack p0, final Permission p1); + + boolean removePermission(final ItemStack p0, final Permission p1); + + String getUsername(final ItemStack p0); + + void setUsername(final ItemStack p0, final String p1); +} diff --git a/src/main/java/mffs/api/card/ICardInfinite.java b/src/main/java/mffs/api/card/ICardInfinite.java new file mode 100644 index 0000000..4f35a5a --- /dev/null +++ b/src/main/java/mffs/api/card/ICardInfinite.java @@ -0,0 +1,5 @@ +package mffs.api.card; + +public interface ICardInfinite +{ +} diff --git a/src/main/java/mffs/api/card/ICardLink.java b/src/main/java/mffs/api/card/ICardLink.java new file mode 100644 index 0000000..460c031 --- /dev/null +++ b/src/main/java/mffs/api/card/ICardLink.java @@ -0,0 +1,11 @@ +package mffs.api.card; + +import universalelectricity.core.vector.Vector3; +import net.minecraft.item.ItemStack; + +public interface ICardLink +{ + void setLink(final ItemStack p0, final Vector3 p1); + + Vector3 getLink(final ItemStack p0); +} diff --git a/src/main/java/mffs/api/fortron/IFortronCapacitor.java b/src/main/java/mffs/api/fortron/IFortronCapacitor.java new file mode 100644 index 0000000..65d7874 --- /dev/null +++ b/src/main/java/mffs/api/fortron/IFortronCapacitor.java @@ -0,0 +1,12 @@ +package mffs.api.fortron; + +import java.util.Set; + +public interface IFortronCapacitor +{ + Set getLinkedDevices(); + + int getTransmissionRange(); + + int getTransmissionRate(); +} diff --git a/src/main/java/mffs/api/fortron/IFortronFrequency.java b/src/main/java/mffs/api/fortron/IFortronFrequency.java new file mode 100644 index 0000000..1e4f9b4 --- /dev/null +++ b/src/main/java/mffs/api/fortron/IFortronFrequency.java @@ -0,0 +1,7 @@ +package mffs.api.fortron; + +import icbm.api.IBlockFrequency; + +public interface IFortronFrequency extends IFortronStorage, IBlockFrequency +{ +} diff --git a/src/main/java/mffs/api/fortron/IFortronStorage.java b/src/main/java/mffs/api/fortron/IFortronStorage.java new file mode 100644 index 0000000..fd7424f --- /dev/null +++ b/src/main/java/mffs/api/fortron/IFortronStorage.java @@ -0,0 +1,14 @@ +package mffs.api.fortron; + +public interface IFortronStorage +{ + void setFortronEnergy(final int p0); + + int getFortronEnergy(); + + int getFortronCapacity(); + + int requestFortron(final int p0, final boolean p1); + + int provideFortron(final int p0, final boolean p1); +} diff --git a/src/main/java/mffs/api/modules/IInterdictionMatrixModule.java b/src/main/java/mffs/api/modules/IInterdictionMatrixModule.java new file mode 100644 index 0000000..9916f8c --- /dev/null +++ b/src/main/java/mffs/api/modules/IInterdictionMatrixModule.java @@ -0,0 +1,9 @@ +package mffs.api.modules; + +import mffs.api.security.IInterdictionMatrix; +import net.minecraft.entity.EntityLivingBase; + +public interface IInterdictionMatrixModule extends IModule +{ + boolean onDefend(final IInterdictionMatrix p0, final EntityLivingBase p1); +} diff --git a/src/main/java/mffs/api/modules/IModule.java b/src/main/java/mffs/api/modules/IModule.java new file mode 100644 index 0000000..f01ab79 --- /dev/null +++ b/src/main/java/mffs/api/modules/IModule.java @@ -0,0 +1,22 @@ +package mffs.api.modules; + +import mffs.api.IFieldInteraction; +import net.minecraft.item.ItemStack; +import net.minecraft.entity.Entity; +import net.minecraft.world.World; +import universalelectricity.core.vector.Vector3; +import java.util.Set; +import mffs.api.IProjector; + +public interface IModule +{ + float getFortronCost(final float p0); + + boolean onProject(final IProjector p0, final Set fieldBlocks); + + int onProject(final IProjector p0, final Vector3 p1); + + boolean onCollideWithForceField(final World p0, final int p1, final int p2, final int p3, final Entity p4, final ItemStack p5); + + void onCalculate(final IFieldInteraction p0, final Set fieldBlocks); +} diff --git a/src/main/java/mffs/api/modules/IModuleAcceptor.java b/src/main/java/mffs/api/modules/IModuleAcceptor.java new file mode 100644 index 0000000..352b8e3 --- /dev/null +++ b/src/main/java/mffs/api/modules/IModuleAcceptor.java @@ -0,0 +1,17 @@ +package mffs.api.modules; + +import java.util.Set; +import net.minecraft.item.ItemStack; + +public interface IModuleAcceptor +{ + ItemStack getModule(final IModule p0); + + int getModuleCount(final IModule p0, final int... p1); + + Set getModuleStacks(final int... p0); + + Set getModules(final int... p0); + + int getFortronCost(); +} diff --git a/src/main/java/mffs/api/modules/IProjectorMode.java b/src/main/java/mffs/api/modules/IProjectorMode.java new file mode 100644 index 0000000..3ed4ec1 --- /dev/null +++ b/src/main/java/mffs/api/modules/IProjectorMode.java @@ -0,0 +1,17 @@ +package mffs.api.modules; + +import java.util.Set; +import mffs.api.IFieldInteraction; +import mffs.api.IProjector; +import universalelectricity.core.vector.Vector3; + +public interface IProjectorMode { + Set getExteriorPoints(final IFieldInteraction p0); + + Set getInteriorPoints(final IFieldInteraction p0); + + boolean isInField(final IFieldInteraction p0, final Vector3 p1); + + void render(final IProjector p0, final double p1, final double p2, + final double p3, final float p4, final long p5); +} diff --git a/src/main/java/mffs/api/security/IBiometricIdentifier.java b/src/main/java/mffs/api/security/IBiometricIdentifier.java new file mode 100644 index 0000000..eaa760b --- /dev/null +++ b/src/main/java/mffs/api/security/IBiometricIdentifier.java @@ -0,0 +1,12 @@ +package mffs.api.security; + +import net.minecraft.item.ItemStack; + +public interface IBiometricIdentifier +{ + boolean isAccessGranted(final String p0, final Permission p1); + + String getOwner(); + + ItemStack getManipulatingCard(); +} diff --git a/src/main/java/mffs/api/security/IInterdictionMatrix.java b/src/main/java/mffs/api/security/IInterdictionMatrix.java new file mode 100644 index 0000000..4c1aebb --- /dev/null +++ b/src/main/java/mffs/api/security/IInterdictionMatrix.java @@ -0,0 +1,24 @@ +package mffs.api.security; + +import java.util.Set; +import net.minecraft.item.ItemStack; +import mffs.api.IActivatable; +import mffs.api.IBiometricIdentifierLink; +import mffs.api.modules.IModuleAcceptor; +import mffs.api.fortron.IFortronFrequency; +import net.minecraft.inventory.IInventory; + +public interface IInterdictionMatrix extends IInventory, IFortronFrequency, IModuleAcceptor, IBiometricIdentifierLink, IActivatable +{ + int getWarningRange(); + + int getActionRange(); + + boolean mergeIntoInventory(final ItemStack p0); + + Set getFilteredItems(); + + boolean getFilterMode(); + + int getFortronCost(); +} diff --git a/src/main/java/mffs/api/security/Permission.java b/src/main/java/mffs/api/security/Permission.java new file mode 100644 index 0000000..03ea1f1 --- /dev/null +++ b/src/main/java/mffs/api/security/Permission.java @@ -0,0 +1,45 @@ +package mffs.api.security; + +public class Permission +{ + public static final Permission FORCE_FIELD_WARP; + public static final Permission BLOCK_ALTER; + public static final Permission BLOCK_ACCESS; + public static final Permission SECURITY_CENTER_CONFIGURE; + public static final Permission BYPASS_INTERDICTION_MATRIX; + public static final Permission DEFENSE_STATION_CONFISCATION; + public static final Permission REMOTE_CONTROL; + private static Permission[] LIST; + public final int id; + public final String name; + + public Permission(final int id, final String name) { + this.id = id; + this.name = name; + if (Permission.LIST == null) { + Permission.LIST = new Permission[7]; + } + Permission.LIST[this.id] = this; + } + + public static Permission getPermission(final int id) { + if (id < Permission.LIST.length && id >= 0) { + return Permission.LIST[id]; + } + return null; + } + + public static Permission[] getPermissions() { + return Permission.LIST; + } + + static { + FORCE_FIELD_WARP = new Permission(0, "warp"); + BLOCK_ALTER = new Permission(1, "blockPlaceAccess"); + BLOCK_ACCESS = new Permission(2, "blockAccess"); + SECURITY_CENTER_CONFIGURE = new Permission(3, "configure"); + BYPASS_INTERDICTION_MATRIX = new Permission(4, "bypassDefense"); + DEFENSE_STATION_CONFISCATION = new Permission(5, "bypassConfiscation"); + REMOTE_CONTROL = new Permission(6, "remoteControl"); + } +} diff --git a/src/main/java/mffs/base/BlockBase.java b/src/main/java/mffs/base/BlockBase.java new file mode 100644 index 0000000..6b2a79d --- /dev/null +++ b/src/main/java/mffs/base/BlockBase.java @@ -0,0 +1,21 @@ +package mffs.base; + +import mffs.MFFSCreativeTab; +import net.minecraft.block.material.Material; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; +import universalelectricity.prefab.block.BlockAdvanced; + +public abstract class BlockBase extends BlockAdvanced { + public BlockBase(final String name, final Material material) { + super(material); + this.setBlockName("mffs:" + name); + this.setCreativeTab(MFFSCreativeTab.INSTANCE); + } + + // anti-bullshit + @Override + public TileEntity createTileEntity(World world, int meta) { + return this.createNewTileEntity(world, meta); + } +} diff --git a/src/main/java/mffs/base/BlockMachine.java b/src/main/java/mffs/base/BlockMachine.java new file mode 100644 index 0000000..de6e840 --- /dev/null +++ b/src/main/java/mffs/base/BlockMachine.java @@ -0,0 +1,137 @@ +package mffs.base; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import icbm.api.ICamouflageMaterial; +import mffs.MFFSCreativeTab; +import mffs.ModularForceFieldSystem; +import mffs.api.IBiometricIdentifierLink; +import mffs.api.security.Permission; +import mffs.item.card.ItemCardLink; +import mffs.render.RenderBlockHandler; +import net.minecraft.block.Block; +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ChatComponentText; +import net.minecraft.world.World; +import universalelectricity.core.UniversalElectricity; +import universalelectricity.prefab.block.BlockRotatable; +import universalelectricity.prefab.implement.IRedstoneReceptor; + +public abstract class BlockMachine + extends BlockRotatable implements ICamouflageMaterial { + public BlockMachine(final String name) { + super(UniversalElectricity.machine); + this.setBlockName("mffs:" + name); + this.setHardness(Float.MAX_VALUE); + this.setResistance(100.0f); + this.setStepSound(BlockMachine.soundTypeMetal); + this.setCreativeTab(MFFSCreativeTab.INSTANCE); + } + + @Override + public boolean onMachineActivated(final World world, final int x, final int y, final int z, + final EntityPlayer entityPlayer, final int side, + final float hitX, final float hitY, final float hitZ) { + if (!world.isRemote) { + if (entityPlayer.getCurrentEquippedItem() != null && + entityPlayer.getCurrentEquippedItem().getItem() instanceof ItemCardLink) { + return false; + } + entityPlayer.openGui((Object) ModularForceFieldSystem.instance, 0, world, + x, y, z); + } + return true; + } + + @Override + public boolean onSneakMachineActivated(final World world, final int x, + final int y, final int z, + final EntityPlayer entityPlayer, + final int side, final float hitX, + final float hitY, final float hitZ) { + return this.onUseWrench(world, x, y, z, entityPlayer, side, hitX, hitY, + hitZ); + } + + @Override + public boolean onSneakUseWrench(final World world, final int x, final int y, + final int z, final EntityPlayer entityPlayer, + final int side, final float hitX, + final float hitY, final float hitZ) { + if (!world.isRemote) { + final TileEntity tileEntity = world.getTileEntity(x, y, z); + if (tileEntity instanceof IBiometricIdentifierLink) { + if (((IBiometricIdentifierLink) tileEntity).getBiometricIdentifier() == null) { + this.dropBlockAsItem(world, x, y, z, world.getBlockMetadata(x, y, z), + 0); + world.setBlockToAir(x, y, z); + return true; + } + if (((IBiometricIdentifierLink) tileEntity) + .getBiometricIdentifier() + .isAccessGranted(entityPlayer.getDisplayName(), + Permission.SECURITY_CENTER_CONFIGURE)) { + this.dropBlockAsItem(world, x, y, z, world.getBlockMetadata(x, y, z), + 0); + world.setBlockToAir(x, y, z); + return true; + } + entityPlayer.addChatMessage(new ChatComponentText( + "[" + + ModularForceFieldSystem.blockBiometricIdentifier + .getLocalizedName() + + + "]" + + " Cannot remove machine! Access denied!")); + } + } + return false; + } + + @Override + public void onNeighborBlockChange(final World world, final int x, final int y, + final int z, final Block block) { + if (!world.isRemote) { + final TileEntity tileEntity = world.getTileEntity(x, y, z); + if (tileEntity instanceof IRedstoneReceptor) { + if (world.isBlockIndirectlyGettingPowered(x, y, z)) { + ((IRedstoneReceptor) tileEntity).onPowerOn(); + } else { + ((IRedstoneReceptor) tileEntity).onPowerOff(); + } + } + } + } + + @Override + public float getExplosionResistance(final Entity entity, final World world, + final int i, final int j, final int k, + final double d, final double d1, + final double d2) { + return 100.0f; + } + + @Override + public void registerBlockIcons(final IIconRegister par1IconRegister) { + this.blockIcon = par1IconRegister.registerIcon("mffs:machine"); + } + + @Override + public boolean isOpaqueCube() { + return false; + } + + @Override + public boolean renderAsNormalBlock() { + return false; + } + + @SideOnly(Side.CLIENT) + @Override + public int getRenderType() { + return RenderBlockHandler.ID; + } +} diff --git a/src/main/java/mffs/base/ContainerBase.java b/src/main/java/mffs/base/ContainerBase.java new file mode 100644 index 0000000..d8d4c16 --- /dev/null +++ b/src/main/java/mffs/base/ContainerBase.java @@ -0,0 +1,95 @@ +package mffs.base; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.Container; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; + +public class ContainerBase extends Container { + protected int slotCount; + private IInventory inventory; + + public ContainerBase(final IInventory inventory) { + this.slotCount = 0; + this.inventory = inventory; + this.slotCount = inventory.getSizeInventory(); + } + + @Override + public void onContainerClosed(final EntityPlayer player) { + if (this.inventory instanceof TileEntityBase) { + ((TileEntityBase)this.inventory).playersUsing.remove(player); + } + } + + public void addPlayerInventory(final EntityPlayer player) { + if (this.inventory instanceof TileEntityBase) { + ((TileEntityBase)this.inventory).playersUsing.add(player); + } + for (int var3 = 0; var3 < 3; ++var3) { + for (int var4 = 0; var4 < 9; ++var4) { + this.addSlotToContainer(new Slot((IInventory)player.inventory, + var4 + var3 * 9 + 9, 8 + var4 * 18, + 135 + var3 * 18)); + } + } + for (int var3 = 0; var3 < 9; ++var3) { + this.addSlotToContainer( + new Slot((IInventory)player.inventory, var3, 8 + var3 * 18, 193)); + } + } + + @Override + public ItemStack transferStackInSlot(final EntityPlayer par1EntityPlayer, + final int slotID) { + ItemStack var2 = null; + final Slot var3 = (Slot)super.inventorySlots.get(slotID); + if (var3 != null && var3.getHasStack()) { + final ItemStack itemStack = var3.getStack(); + var2 = itemStack.copy(); + if (slotID >= this.slotCount) { + boolean didTry = false; + for (int i = 0; i < this.slotCount; ++i) { + if (this.getSlot(i).isItemValid(itemStack)) { + didTry = true; + if (this.mergeItemStack(itemStack, i, i + 1, false)) { + break; + } + } + } + if (!didTry) { + if (slotID < 27 + this.slotCount) { + if (!this.mergeItemStack(itemStack, 27 + this.slotCount, + 36 + this.slotCount, false)) { + return null; + } + } else if (slotID >= 27 + this.slotCount && + slotID < 36 + this.slotCount && + !this.mergeItemStack(itemStack, this.slotCount, + 27 + this.slotCount, false)) { + return null; + } + } + } else if (!this.mergeItemStack(itemStack, this.slotCount, + 36 + this.slotCount, false)) { + return null; + } + if (itemStack.stackSize == 0) { + var3.putStack((ItemStack)null); + } else { + var3.onSlotChanged(); + } + if (itemStack.stackSize == var2.stackSize) { + return null; + } + var3.onPickupFromSlot(par1EntityPlayer, itemStack); + } + return var2; + } + + @Override + public boolean canInteractWith(final EntityPlayer entityplayer) { + return this.inventory.isUseableByPlayer(entityplayer); + } +} diff --git a/src/main/java/mffs/base/GuiBase.java b/src/main/java/mffs/base/GuiBase.java new file mode 100644 index 0000000..5f1ec2a --- /dev/null +++ b/src/main/java/mffs/base/GuiBase.java @@ -0,0 +1,362 @@ +package mffs.base; + +import icbm.api.IBlockFrequency; +import java.util.HashMap; +import java.util.Map; +import mffs.MFFSHelper; +import mffs.ModularForceFieldSystem; +import mffs.api.IBiometricIdentifierLink; +import mffs.gui.button.GuiIcon; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.gui.GuiTextField; +import net.minecraft.client.gui.inventory.GuiContainer; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.init.Blocks; +import net.minecraft.inventory.Container; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ResourceLocation; +import org.lwjgl.input.Keyboard; +import org.lwjgl.opengl.GL11; +import universalelectricity.core.vector.Vector2; +import universalelectricity.core.vector.Vector3; +import universalelectricity.prefab.TranslationHelper; +import universalelectricity.prefab.vector.Region2; + +public class GuiBase extends GuiContainer { + public static final int METER_HEIGHT = 49; + public static final int METER_WIDTH = 14; + public static final int METER_END = 68; + protected GuiTextField textFieldFrequency; + protected Vector2 textFieldPos; + public String tooltip; + protected int containerWidth; + protected int containerHeight; + protected IBlockFrequency frequencyTile; + protected HashMap tooltips; + + public GuiBase(final Container container) { + super(container); + this.textFieldPos = new Vector2(); + this.tooltip = ""; + this.tooltips = new HashMap<>(); + this.ySize = 217; + } + + public GuiBase(final Container container, + final IBlockFrequency frequencyTile) { + this(container); + this.frequencyTile = frequencyTile; + } + + @Override + public void initGui() { + super.initGui(); + this.buttonList.clear(); + this.buttonList.add(new GuiIcon( + 0, this.width / 2 - 82, this.height / 2 - 104, + new ItemStack(Blocks.torch), new ItemStack(Blocks.redstone_torch))); + Keyboard.enableRepeatEvents(true); + if (this.frequencyTile != null) { + (this.textFieldFrequency = + new GuiTextField(this.fontRendererObj, this.textFieldPos.intX(), + this.textFieldPos.intY(), 50, 12)) + .setMaxStringLength(6); + this.textFieldFrequency.setText(this.frequencyTile.getFrequency() + ""); + } + } + + @Override + public void onGuiClosed() { + Keyboard.enableRepeatEvents(false); + super.onGuiClosed(); + } + + @Override + protected void keyTyped(final char par1, final int par2) { + super.keyTyped(par1, par2); + if (this.textFieldFrequency != null) { + this.textFieldFrequency.textboxKeyTyped(par1, par2); + try { + final int newFrequency = + Math.max(0, Integer.parseInt(this.textFieldFrequency.getText())); + this.frequencyTile.setFrequency(newFrequency); + this.textFieldFrequency.setText(this.frequencyTile.getFrequency() + ""); + NBTTagCompound nbt = new NBTTagCompound(); + nbt.setInteger("frequency", this.frequencyTile.getFrequency()); + ModularForceFieldSystem.channel.sendToServer( + new PacketTile(PacketTile.Type.FREQUENCY, + new Vector3((TileEntity)this.frequencyTile), nbt)); + } catch (final NumberFormatException ex) { + } + } + } + + @Override + protected void actionPerformed(final GuiButton guiButton) { + super.actionPerformed(guiButton); + if (this.frequencyTile != null && guiButton.id == 0) { + ModularForceFieldSystem.channel.sendToServer(new PacketTile( + PacketTile.Type.TOGGLE_ACTIVATION, + new Vector3((TileEntity)this.frequencyTile), new NBTTagCompound())); + } + } + + @Override + public void updateScreen() { + super.updateScreen(); + if (this.textFieldFrequency != null && + !this.textFieldFrequency.isFocused()) { + this.textFieldFrequency.setText(this.frequencyTile.getFrequency() + ""); + } + if (this.frequencyTile instanceof TileEntityBase && + this.buttonList.size() > 0 && this.buttonList.get(0) != null) { + ((GuiIcon)this.buttonList.get(0)) + .setIndex(((TileEntityBase)this.frequencyTile).isActive() ? 1 : 0); + } + } + + @Override + protected void mouseClicked(final int x, final int y, final int par3) { + super.mouseClicked(x, y, par3); + if (this.textFieldFrequency != null) { + this.textFieldFrequency.mouseClicked(x - this.containerWidth, + y - this.containerHeight, par3); + } + } + + @Override + protected void drawGuiContainerForegroundLayer(final int mouseX, + final int mouseY) { + if (this.textFieldFrequency != null && + this.func_146978_c(this.textFieldPos.intX(), this.textFieldPos.intY(), + this.textFieldFrequency.getWidth(), 12, mouseX, + mouseY)) { + this.tooltip = TranslationHelper.getLocal("gui.frequency.tooltip"); + } + for (final Map.Entry entry : this.tooltips.entrySet()) { + if (entry.getKey().isIn( + new Vector2(mouseX - this.guiLeft, mouseY - this.guiTop))) { + this.tooltip = entry.getValue(); + break; + } + } + if (this.tooltip != null && this.tooltip != "") { + this.drawTooltip(mouseX - this.guiLeft, mouseY - this.guiTop, + MFFSHelper.splitStringPerWord(this.tooltip, 5) + .toArray(new String[] {})); + } + this.tooltip = ""; + } + + @Override + protected void drawGuiContainerBackgroundLayer(final float var1, final int x, + final int y) { + this.containerWidth = (this.width - this.xSize) / 2; + this.containerHeight = (this.height - this.ySize) / 2; + this.mc.renderEngine.bindTexture( + new ResourceLocation("mffs", "textures/gui/gui_base.png")); + GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + this.drawTexturedModalRect(this.containerWidth, this.containerHeight, 0, 0, + this.xSize, this.ySize); + if (this.frequencyTile instanceof IBiometricIdentifierLink) { + this.drawBulb(167, 4, + ((IBiometricIdentifierLink)this.frequencyTile) + .getBiometricIdentifier() != null); + } + } + + protected void drawBulb(final int x, final int y, final boolean isOn) { + this.mc.renderEngine.bindTexture( + new ResourceLocation("mffs", "textures/gui/gui_components.png")); + GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + if (isOn) { + this.drawTexturedModalRect(this.containerWidth + x, + this.containerHeight + y, 161, 0, 6, 6); + } else { + this.drawTexturedModalRect(this.containerWidth + x, + this.containerHeight + y, 161, 4, 6, 6); + } + } + + protected void drawSlot(final int x, final int y, final ItemStack itemStack) { + this.mc.renderEngine.bindTexture( + new ResourceLocation("mffs", "textures/gui/gui_components.png")); + GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + this.drawTexturedModalRect(this.containerWidth + x, + this.containerHeight + y, 0, 0, 18, 18); + this.drawItemStack(itemStack, this.containerWidth + x, + this.containerHeight + y); + } + + protected void drawItemStack(final ItemStack itemStack, int x, int y) { + ++x; + ++y; + GL11.glTranslatef(0.0f, 0.0f, 32.0f); + GuiBase.itemRender.renderItemAndEffectIntoGUI( + this.fontRendererObj, this.mc.renderEngine, itemStack, x, y); + } + + protected void drawTextWithTooltip(final String textName, final String format, + final int x, final int y, final int mouseX, + final int mouseY) { + this.drawTextWithTooltip(textName, format, x, y, mouseX, mouseY, 4210752); + } + + protected void drawTextWithTooltip(final String textName, final String format, + final int x, final int y, final int mouseX, + final int mouseY, final int color) { + final String name = TranslationHelper.getLocal("gui." + textName + ".name"); + final String text = format.replaceAll("%1", name); + this.fontRendererObj.drawString(text, x, y, color); + final String tooltip = + TranslationHelper.getLocal("gui." + textName + ".tooltip"); + if (tooltip != null && tooltip != "" && + this.func_146978_c(x, y, (int)(text.length() * 4.8), 12, mouseX, + mouseY)) { + this.tooltip = tooltip; + } + } + + protected void drawTextWithTooltip(final String textName, final int x, + final int y, final int mouseX, + final int mouseY) { + this.drawTextWithTooltip(textName, "%1", x, y, mouseX, mouseY); + } + + protected void drawSlot(final int x, final int y, final SlotType type, + final float r, final float g, final float b) { + this.mc.renderEngine.bindTexture( + new ResourceLocation("mffs", "textures/gui/gui_components.png")); + GL11.glColor4f(r, g, b, 1.0f); + this.drawTexturedModalRect(this.containerWidth + x, + this.containerHeight + y, 0, 0, 18, 18); + if (type != SlotType.NONE) { + this.drawTexturedModalRect(this.containerWidth + x, + this.containerHeight + y, 0, + 18 * type.ordinal(), 18, 18); + } + } + + protected void drawSlot(final int x, final int y, final SlotType type) { + this.drawSlot(x, y, type, 1.0f, 1.0f, 1.0f); + } + + protected void drawSlot(final int x, final int y) { + this.drawSlot(x, y, SlotType.NONE); + } + + protected void drawBar(final int x, final int y, final float scale) { + this.mc.renderEngine.bindTexture( + new ResourceLocation("mffs", "textures/gui/gui_components.png")); + GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + this.drawTexturedModalRect(this.containerWidth + x, + this.containerHeight + y, 18, 0, 22, 15); + if (scale > 0.0f) { + this.drawTexturedModalRect(this.containerWidth + x, + this.containerHeight + y, 18, 15, + 22 - (int)(scale * 22.0f), 15); + } + } + + protected void drawForce(final int x, final int y, final float scale) { + this.mc.renderEngine.bindTexture( + new ResourceLocation("mffs", "textures/gui/gui_components.png")); + GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + this.drawTexturedModalRect(this.containerWidth + x, + this.containerHeight + y, 54, 0, 107, 11); + if (scale > 0.0f) { + this.drawTexturedModalRect(this.containerWidth + x, + this.containerHeight + y, 54, 11, + (int)(scale * 107.0f), 11); + } + } + + protected void drawElectricity(final int x, final int y, final float scale) { + this.mc.renderEngine.bindTexture( + new ResourceLocation("mffs", "textures/gui/gui_components.png")); + GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + this.drawTexturedModalRect(this.containerWidth + x, + this.containerHeight + y, 54, 0, 107, 11); + if (scale > 0.0f) { + this.drawTexturedModalRect(this.containerWidth + x, + this.containerHeight + y, 54, 22, + (int)(scale * 107.0f), 11); + } + } + + public void drawTooltip(final int x, final int y, final String... toolTips) { + if (!GuiScreen.isShiftKeyDown()) { + GL11.glDisable(32826); + RenderHelper.disableStandardItemLighting(); + GL11.glDisable(2896); + GL11.glDisable(2929); + if (toolTips != null) { + int var5 = 0; + for (int var6 = 0; var6 < toolTips.length; ++var6) { + final int var7 = this.fontRendererObj.getStringWidth(toolTips[var6]); + if (var7 > var5) { + var5 = var7; + } + } + int var6 = x + 12; + int var7 = y - 12; + int var8 = 8; + if (toolTips.length > 1) { + var8 += 2 + (toolTips.length - 1) * 10; + } + if (this.guiTop + var7 + var8 + 6 > this.height) { + var7 = this.height - var8 - this.guiTop - 6; + } + zLevel = 300.0f; + final int var9 = -267386864; + this.drawGradientRect(var6 - 3, var7 - 4, var6 + var5 + 3, var7 - 3, + var9, var9); + this.drawGradientRect(var6 - 3, var7 + var8 + 3, var6 + var5 + 3, + var7 + var8 + 4, var9, var9); + this.drawGradientRect(var6 - 3, var7 - 3, var6 + var5 + 3, + var7 + var8 + 3, var9, var9); + this.drawGradientRect(var6 - 4, var7 - 3, var6 - 3, var7 + var8 + 3, + var9, var9); + this.drawGradientRect(var6 + var5 + 3, var7 - 3, var6 + var5 + 4, + var7 + var8 + 3, var9, var9); + final int var10 = 1347420415; + final int var11 = (var10 & 0xFEFEFE) >> 1 | (var10 & 0xFF000000); + this.drawGradientRect(var6 - 3, var7 - 3 + 1, var6 - 3 + 1, + var7 + var8 + 3 - 1, var10, var11); + this.drawGradientRect(var6 + var5 + 2, var7 - 3 + 1, var6 + var5 + 3, + var7 + var8 + 3 - 1, var10, var11); + this.drawGradientRect(var6 - 3, var7 - 3, var6 + var5 + 3, var7 - 3 + 1, + var10, var10); + this.drawGradientRect(var6 - 3, var7 + var8 + 2, var6 + var5 + 3, + var7 + var8 + 3, var11, var11); + for (int var12 = 0; var12 < toolTips.length; ++var12) { + final String var13 = toolTips[var12]; + this.fontRendererObj.drawStringWithShadow(var13, var6, var7, -1); + var7 += 10; + } + this.zLevel = 0.0f; + GL11.glEnable(2929); + GL11.glEnable(2896); + RenderHelper.enableGUIStandardItemLighting(); + GL11.glEnable(32826); + } + } + } + + public enum SlotType { + NONE, + BATTERY, + LIQUID, + ARR_UP, + ARR_DOWN, + ARR_LEFT, + ARR_RIGHT, + ARR_UP_RIGHT, + ARR_UP_LEFT, + ARR_DOWN_LEFT, + ARR_DOWN_RIGHT; + } +} diff --git a/src/main/java/mffs/base/ItemBase.java b/src/main/java/mffs/base/ItemBase.java new file mode 100644 index 0000000..0bae7e7 --- /dev/null +++ b/src/main/java/mffs/base/ItemBase.java @@ -0,0 +1,30 @@ +package mffs.base; + +import java.util.List; +import mffs.MFFSCreativeTab; +import mffs.MFFSHelper; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import universalelectricity.prefab.TranslationHelper; + +public class ItemBase extends Item { + public ItemBase(final String name) { + super(); + this.setUnlocalizedName("mffs:" + name); + this.setCreativeTab(MFFSCreativeTab.INSTANCE); + this.setNoRepair(); + this.iconString = "mffs:" + name; + } + + @Override + public void addInformation(final ItemStack itemStack, + final EntityPlayer player, final List info, + final boolean b) { + final String tooltip = + TranslationHelper.getLocal(this.getUnlocalizedName() + ".tooltip"); + if (tooltip != null && tooltip.length() > 0) { + info.addAll(MFFSHelper.splitStringPerWord(tooltip, 5)); + } + } +} diff --git a/src/main/java/mffs/base/PacketFxs.java b/src/main/java/mffs/base/PacketFxs.java new file mode 100644 index 0000000..1395c93 --- /dev/null +++ b/src/main/java/mffs/base/PacketFxs.java @@ -0,0 +1,55 @@ +package mffs.base; + +import cpw.mods.fml.common.network.simpleimpl.IMessage; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufInputStream; +import io.netty.buffer.ByteBufOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import net.minecraft.nbt.CompressedStreamTools; +import net.minecraft.nbt.NBTTagCompound; +import universalelectricity.core.vector.Vector3; + +public class PacketFxs implements IMessage { + Vector3 pos; + NBTTagCompound data; + + public PacketFxs() { + this(null, null); + } + + public PacketFxs(Vector3 pos, NBTTagCompound data) { + this.pos = pos; + this.data = data; + } + + @Override + public void fromBytes(ByteBuf buf) { + NBTTagCompound nbt = null; + try { + nbt = CompressedStreamTools.read( + new DataInputStream(new ByteBufInputStream(buf))); + } catch (IOException e) { + e.printStackTrace(); + } + + this.pos = Vector3.readFromNBT(nbt); + this.data = nbt.getCompoundTag("data"); + } + + @Override + public void toBytes(ByteBuf buf) { + NBTTagCompound nbt = new NBTTagCompound(); + + this.pos.writeToNBT(nbt); + nbt.setTag("data", this.data); + + try { + CompressedStreamTools.write( + nbt, new DataOutputStream(new ByteBufOutputStream(buf))); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/mffs/base/PacketFxsHandler.java b/src/main/java/mffs/base/PacketFxsHandler.java new file mode 100644 index 0000000..5d1ecd7 --- /dev/null +++ b/src/main/java/mffs/base/PacketFxsHandler.java @@ -0,0 +1,24 @@ +package mffs.base; + +import cpw.mods.fml.client.FMLClientHandler; +import cpw.mods.fml.common.network.simpleimpl.IMessage; +import cpw.mods.fml.common.network.simpleimpl.IMessageHandler; +import cpw.mods.fml.common.network.simpleimpl.MessageContext; +import mffs.base.TileEntityBase; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; + +public class PacketFxsHandler implements IMessageHandler { + + @Override + public IMessage onMessage(PacketFxs message, MessageContext ctx) { + World world = FMLClientHandler.instance().getWorldClient(); + + TileEntity te = message.pos.getTileEntity(world); + if (te instanceof TileEntityBase) { + ((TileEntityBase) te).onFxsPacket(message.data); + } + + return null; + } +} diff --git a/src/main/java/mffs/base/PacketTile.java b/src/main/java/mffs/base/PacketTile.java new file mode 100644 index 0000000..60bac39 --- /dev/null +++ b/src/main/java/mffs/base/PacketTile.java @@ -0,0 +1,65 @@ +package mffs.base; + +import cpw.mods.fml.common.network.simpleimpl.IMessage; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufInputStream; +import io.netty.buffer.ByteBufOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import net.minecraft.nbt.CompressedStreamTools; +import net.minecraft.nbt.NBTTagCompound; +import universalelectricity.core.vector.Vector3; + +public class PacketTile implements IMessage { + Type type; + Vector3 pos; + NBTTagCompound data; + + public PacketTile(Type type, Vector3 pos, NBTTagCompound data) { + this.type = type; + this.pos = pos; + this.data = data; + } + + public PacketTile() {} + + @Override + public void fromBytes(ByteBuf buf) { + try { + NBTTagCompound nbt = CompressedStreamTools.read( + new DataInputStream(new ByteBufInputStream(buf))); + + this.type = Type.values()[nbt.getInteger("type")]; + this.pos = Vector3.readFromNBT(nbt); + this.data = nbt.getCompoundTag("data"); + } catch (IOException e) { + e.printStackTrace(); + } + } + + @Override + public void toBytes(ByteBuf buf) { + try { + NBTTagCompound nbt = new NBTTagCompound(); + + nbt.setInteger("type", this.type.ordinal()); + this.pos.writeToNBT(nbt); + nbt.setTag("data", this.data); + + CompressedStreamTools.write( + nbt, new DataOutputStream(new ByteBufOutputStream(buf))); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public enum Type { + NONE, + FREQUENCY, + TOGGLE_ACTIVATION, + TOGGLE_MODE, + INVENTORY, + STRING, + } +} diff --git a/src/main/java/mffs/base/PacketTileHandler.java b/src/main/java/mffs/base/PacketTileHandler.java new file mode 100644 index 0000000..2e077d4 --- /dev/null +++ b/src/main/java/mffs/base/PacketTileHandler.java @@ -0,0 +1,24 @@ +package mffs.base; + +import cpw.mods.fml.common.network.simpleimpl.IMessage; +import cpw.mods.fml.common.network.simpleimpl.IMessageHandler; +import cpw.mods.fml.common.network.simpleimpl.MessageContext; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; + +public class PacketTileHandler + implements IMessageHandler { + @Override + public IMessage onMessage(PacketTile arg0, MessageContext arg1) { + World w = arg1.getServerHandler().playerEntity.worldObj; + + TileEntity te = arg0.pos.getTileEntity(w); + + if (!(te instanceof TileEntityBase)) + return null; + + ((TileEntityBase)te).onReceivePacket(arg0.type, arg0.data); + + return null; + } +} diff --git a/src/main/java/mffs/base/TileEntityBase.java b/src/main/java/mffs/base/TileEntityBase.java new file mode 100644 index 0000000..586d066 --- /dev/null +++ b/src/main/java/mffs/base/TileEntityBase.java @@ -0,0 +1,133 @@ +package mffs.base; + +import dan200.computercraft.api.peripheral.IPeripheral; +import java.util.ArrayList; +import java.util.List; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import mffs.api.IActivatable; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.NetworkManager; +import net.minecraft.network.Packet; +import net.minecraft.network.play.server.S35PacketUpdateTileEntity; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; +import universalelectricity.core.vector.Vector3; +import universalelectricity.prefab.implement.IRedstoneReceptor; +import universalelectricity.prefab.implement.IRotatable; +import universalelectricity.prefab.tile.TileEntityDisableable; + +public abstract class TileEntityBase extends TileEntityDisableable + implements IRotatable, IRedstoneReceptor, IActivatable, IPeripheral { + public boolean isActive; + public boolean isRedstoneActive; + public final List playersUsing; + public float animation; + + public TileEntityBase() { + this.isActive = false; + this.isRedstoneActive = false; + this.playersUsing = new ArrayList<>(); + this.animation = 0.0f; + } + + @Override + public void updateEntity() { + super.updateEntity(); + if (super.ticks % 4L == 0L && this.playersUsing.size() > 0) { + this.worldObj.markBlockForUpdate(this.xCoord, this.yCoord, this.zCoord); + } + } + + @Override + public Packet getDescriptionPacket() { + NBTTagCompound nbt = new NBTTagCompound(); + + nbt.setBoolean("isActive", this.isActive); + + return new S35PacketUpdateTileEntity(this.xCoord, this.yCoord, this.zCoord, + this.getBlockMetadata(), nbt); + } + + @Override + public void onDataPacket(NetworkManager arg0, + S35PacketUpdateTileEntity arg1) { + NBTTagCompound nbt = arg1.func_148857_g(); + + this.isActive = nbt.getBoolean("isActive"); + } + + @SideOnly(Side.CLIENT) + public void onFxsPacket(NBTTagCompound data) {} + + public void onReceivePacket(final PacketTile.Type type, + final NBTTagCompound data) { + if (type == PacketTile.Type.TOGGLE_ACTIVATION) { + this.isRedstoneActive = !this.isRedstoneActive; + this.setActive(this.isRedstoneActive); + } + } + + public boolean isPoweredByRedstone() { + return this.worldObj.isBlockIndirectlyGettingPowered( + this.xCoord, this.yCoord, this.zCoord); + } + + @Override + public void readFromNBT(final NBTTagCompound nbt) { + super.readFromNBT(nbt); + this.isActive = nbt.getBoolean("isActive"); + this.isRedstoneActive = nbt.getBoolean("isRedstoneActive"); + } + + @Override + public void writeToNBT(final NBTTagCompound nbttagcompound) { + super.writeToNBT(nbttagcompound); + nbttagcompound.setBoolean("isActive", this.isActive); + nbttagcompound.setBoolean("isRedstoneActive", this.isRedstoneActive); + } + + @Override + public boolean isActive() { + return this.isActive; + } + + @Override + public void setActive(final boolean flag) { + this.isActive = flag; + this.worldObj.markBlockForUpdate(this.xCoord, this.yCoord, this.zCoord); + } + + @Override + public ForgeDirection getDirection(final IBlockAccess world, final int x, + final int y, final int z) { + return ForgeDirection.getOrientation(this.getBlockMetadata()); + } + + @Override + public void setDirection(final World world, final int x, final int y, + final int z, final ForgeDirection facingDirection) { + this.worldObj.setBlockMetadataWithNotify( + this.xCoord, this.yCoord, this.zCoord, facingDirection.ordinal(), 3); + } + + @Override + public void onPowerOn() { + this.setActive(true); + } + + @Override + public void onPowerOff() { + if (!this.isRedstoneActive && !this.worldObj.isRemote) { + this.setActive(false); + } + } + + @Override + public boolean equals(IPeripheral other) { + return this == other; + } +} diff --git a/src/main/java/mffs/base/TileEntityFortron.java b/src/main/java/mffs/base/TileEntityFortron.java new file mode 100644 index 0000000..3c72f1e --- /dev/null +++ b/src/main/java/mffs/base/TileEntityFortron.java @@ -0,0 +1,171 @@ +package mffs.base; + +import mffs.MFFSHelper; +import mffs.Settings; +import mffs.TransferMode; +import mffs.api.ISpecialForceManipulation; +import mffs.api.card.ICard; +import mffs.api.fortron.IFortronFrequency; +import mffs.fortron.FortronHelper; +import mffs.fortron.FrequencyGrid; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTBase; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.NetworkManager; +import net.minecraft.network.Packet; +import net.minecraft.network.play.server.S35PacketUpdateTileEntity; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.FluidTank; +import net.minecraftforge.fluids.FluidTankInfo; +import net.minecraftforge.fluids.IFluidHandler; +import universalelectricity.core.vector.Vector3; + +public abstract class TileEntityFortron extends TileEntityFrequency + implements IFluidHandler, IFortronFrequency, ISpecialForceManipulation { + protected FluidTank fortronTank; + private boolean markSendFortron; + + public TileEntityFortron() { + this.fortronTank = new FluidTank(FortronHelper.FLUID_FORTRON, 0, 1000); + this.markSendFortron = true; + } + + @Override + public void updateEntity() { + super.updateEntity(); + if (!Settings.CONSERVE_PACKETS && super.ticks % 60L == 0L) { + this.worldObj.markBlockForUpdate(this.xCoord, this.yCoord, this.zCoord); + } + } + + @Override + public void invalidate() { + if (this.markSendFortron) { + MFFSHelper.transferFortron( + this, + FrequencyGrid.instance().getFortronTiles( + this.worldObj, new Vector3(this), 100, this.getFrequency()), + TransferMode.DRAIN, Integer.MAX_VALUE); + } + super.invalidate(); + } + + @Override + public Packet getDescriptionPacket() { + NBTTagCompound nbt = new NBTTagCompound(); + + nbt.setInteger("fortron", this.fortronTank.getFluidAmount()); + nbt.setBoolean("isActive", this.isActive()); + + return new S35PacketUpdateTileEntity(this.xCoord, this.yCoord, this.zCoord, + this.getBlockMetadata(), nbt); + } + + @Override + public void onDataPacket(NetworkManager arg0, + S35PacketUpdateTileEntity arg1) { + NBTTagCompound nbt = arg1.func_148857_g(); + + this.fortronTank.setFluid( + new FluidStack(FortronHelper.FLUID_FORTRON, nbt.getInteger("fortron"))); + this.isActive = nbt.getBoolean("isActive"); + } + + @Override + public boolean preMove(final int x, final int y, final int z) { + return true; + } + + @Override + public void move(final int x, final int y, final int z) { + this.markSendFortron = false; + } + + @Override + public void postMove() {} + + @Override + public void readFromNBT(final NBTTagCompound nbt) { + super.readFromNBT(nbt); + this.fortronTank.setFluid( + FluidStack.loadFluidStackFromNBT(nbt.getCompoundTag("fortron"))); + } + + @Override + public void writeToNBT(final NBTTagCompound nbt) { + super.writeToNBT(nbt); + if (this.fortronTank.getFluid() != null) { + final NBTTagCompound fortronCompound = new NBTTagCompound(); + this.fortronTank.getFluid().writeToNBT(fortronCompound); + nbt.setTag("fortron", (NBTBase)fortronCompound); + } + } + + @Override + public int fill(final ForgeDirection from, final FluidStack resource, + final boolean doFill) { + if (resource.getFluid() == FortronHelper.FLUID_FORTRON) { + return this.fortronTank.fill(resource, doFill); + } + return 0; + } + + @Override + public boolean canFill(ForgeDirection arg0, Fluid arg1) { + return arg1 == FortronHelper.FLUID_FORTRON && + this.fortronTank.getFluidAmount() < this.fortronTank.getCapacity(); + } + + @Override + public FluidStack drain(final ForgeDirection from, final int maxDrain, + final boolean doDrain) { + return this.fortronTank.drain(maxDrain, doDrain); + } + + @Override + public FluidStack drain(ForgeDirection arg0, FluidStack arg1, boolean arg2) { + if (arg1.getFluid() != FortronHelper.FLUID_FORTRON) + return null; + + return this.fortronTank.drain(arg1.amount, arg2); + } + + @Override + public boolean canDrain(ForgeDirection arg0, Fluid arg1) { + return arg1 == FortronHelper.FLUID_FORTRON && + this.fortronTank.getFluidAmount() > 0; + } + + @Override + public FluidTankInfo[] getTankInfo(ForgeDirection arg0) { + return new FluidTankInfo[] {new FluidTankInfo(this.fortronTank)}; + } + + public void setFortronEnergy(final int joules) { + this.fortronTank.setFluid(FortronHelper.getFortron(joules)); + } + + public int getFortronEnergy() { + return FortronHelper.getAmount(this.fortronTank); + } + + public int getFortronCapacity() { return this.fortronTank.getCapacity(); } + + public int requestFortron(final int joules, final boolean doUse) { + return FortronHelper.getAmount(this.fortronTank.drain(joules, doUse)); + } + + public int provideFortron(final int joules, final boolean doUse) { + return this.fortronTank.fill(FortronHelper.getFortron(joules), doUse); + } + + public ItemStack getCard() { + final ItemStack itemStack = this.getStackInSlot(0); + if (itemStack != null && itemStack.getItem() instanceof ICard) { + return itemStack; + } + return null; + } +} diff --git a/src/main/java/mffs/base/TileEntityFrequency.java b/src/main/java/mffs/base/TileEntityFrequency.java new file mode 100644 index 0000000..91c915a --- /dev/null +++ b/src/main/java/mffs/base/TileEntityFrequency.java @@ -0,0 +1,95 @@ +package mffs.base; + +import icbm.api.IBlockFrequency; +import java.util.HashSet; +import java.util.Set; +import mffs.api.IBiometricIdentifierLink; +import mffs.api.card.ICardLink; +import mffs.api.security.IBiometricIdentifier; +import mffs.fortron.FrequencyGrid; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.IBlockAccess; +import universalelectricity.core.vector.Vector3; + +public abstract class TileEntityFrequency extends TileEntityInventory + implements IBlockFrequency, IBiometricIdentifierLink { + private int frequency; + + @Override + public void initiate() { + FrequencyGrid.instance().register(this); + super.initiate(); + } + + @Override + public void invalidate() { + FrequencyGrid.instance().unregister(this); + super.invalidate(); + } + + @Override + public void onReceivePacket(final PacketTile.Type type, + final NBTTagCompound data) { + super.onReceivePacket(type, data); + if (type == PacketTile.Type.FREQUENCY) { + this.setFrequency(data.getInteger("frequency")); + } + } + + @Override + public void readFromNBT(final NBTTagCompound nbt) { + super.readFromNBT(nbt); + this.setFrequency(nbt.getInteger("frequency")); + } + + @Override + public void writeToNBT(final NBTTagCompound nbt) { + super.writeToNBT(nbt); + nbt.setInteger("frequency", this.getFrequency()); + } + + @Override + public int getFrequency() { + return this.frequency; + } + + @Override + public void setFrequency(final int frequency) { + this.frequency = frequency; + } + + @Override + public IBiometricIdentifier getBiometricIdentifier() { + if (this.getBiometricIdentifiers().size() > 0) { + return (IBiometricIdentifier)this.getBiometricIdentifiers().toArray()[0]; + } + return null; + } + + @Override + public Set getBiometricIdentifiers() { + final Set list = new HashSet<>(); + for (final ItemStack itemStack : this.getCards()) { + if (itemStack != null && itemStack.getItem() instanceof ICardLink) { + final Vector3 linkedPosition = + ((ICardLink)itemStack.getItem()).getLink(itemStack); + final TileEntity tileEntity = + linkedPosition.getTileEntity((IBlockAccess)this.worldObj); + if (linkedPosition == null || + !(tileEntity instanceof IBiometricIdentifier)) { + continue; + } + list.add((IBiometricIdentifier)tileEntity); + } + } + for (final IBlockFrequency tileEntity2 : + FrequencyGrid.instance().get(this.getFrequency())) { + if (tileEntity2 instanceof IBiometricIdentifier) { + list.add((IBiometricIdentifier)tileEntity2); + } + } + return list; + } +} diff --git a/src/main/java/mffs/base/TileEntityInventory.java b/src/main/java/mffs/base/TileEntityInventory.java new file mode 100644 index 0000000..b8915f8 --- /dev/null +++ b/src/main/java/mffs/base/TileEntityInventory.java @@ -0,0 +1,345 @@ +package mffs.base; + +import dan200.computercraft.api.lua.ILuaContext; +import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.peripheral.IComputerAccess; +import java.util.HashSet; +import java.util.Set; +import net.minecraft.entity.Entity; +import net.minecraft.entity.item.EntityItem; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.ISidedInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTBase; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.network.NetworkManager; +import net.minecraft.network.play.server.S35PacketUpdateTileEntity; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.tileentity.TileEntityChest; +import net.minecraft.world.IBlockAccess; +import net.minecraftforge.common.util.ForgeDirection; +import universalelectricity.core.vector.Vector3; +import universalelectricity.prefab.multiblock.TileEntityMulti; + +public abstract class TileEntityInventory + extends TileEntityBase implements IInventory { + protected ItemStack[] inventory; + + public TileEntityInventory() { + this.inventory = new ItemStack[this.getSizeInventory()]; + } + + // TODO: WTF + // @Override + // public List getPacketUpdate() { + // final List objects = new ArrayList(); + // objects.addAll(super.getPacketUpdate()); + // final NBTTagCompound nbt = new NBTTagCompound(); + // this.writeToNBT(nbt); + // objects.add(nbt); + // return objects; + // } + + @Override + public void onDataPacket(NetworkManager arg0, + S35PacketUpdateTileEntity arg1) { + NBTTagCompound nbt = arg1.func_148857_g(); + + this.readFromNBT(nbt); + } + + // TODO: WTF + // @Override + // public void sendInventoryToClients() { + // final NBTTagCompound nbt = new NBTTagCompound(); + // this.writeToNBT(nbt); + // PacketManager.sendPacketToClients(PacketManager.getPacket("MFFS", this, + // TilePacketType.INVENTORY.ordinal(), nbt)); + // } + + @Override + public ItemStack getStackInSlot(final int i) { + return this.inventory[i]; + } + + @Override + public String getInventoryName() { + return this.getBlockType().getLocalizedName(); + } + + @Override + public boolean hasCustomInventoryName() { + return true; + } + + @Override + public void setInventorySlotContents(final int i, final ItemStack itemstack) { + this.inventory[i] = itemstack; + if (itemstack != null && + itemstack.stackSize > this.getInventoryStackLimit()) { + itemstack.stackSize = this.getInventoryStackLimit(); + } + } + + @Override + public ItemStack decrStackSize(final int i, final int j) { + if (this.inventory[i] == null) { + return null; + } + if (this.inventory[i].stackSize <= j) { + final ItemStack itemstack = this.inventory[i]; + this.inventory[i] = null; + return itemstack; + } + final ItemStack itemstack2 = this.inventory[i].splitStack(j); + if (this.inventory[i].stackSize == 0) { + this.inventory[i] = null; + } + return itemstack2; + } + + @Override + public void openInventory() { + } + + @Override + public void closeInventory() { + } + + @Override + public boolean isUseableByPlayer(final EntityPlayer entityplayer) { + return this.worldObj.getTileEntity(this.xCoord, this.yCoord, this.zCoord) == this; + } + + @Override + public ItemStack getStackInSlotOnClosing(final int slotID) { + if (this.inventory[slotID] != null) { + final ItemStack itemstack = this.inventory[slotID]; + this.inventory[slotID] = null; + return itemstack; + } + return null; + } + + @Override + public int getInventoryStackLimit() { + return 64; + } + + // TODO: what's the equivalent to isInvNameLocalized? + // @Override + // public boolean func_94042_c() { + // return true; + // } + + @Override + public boolean isItemValidForSlot(final int slotID, + final ItemStack itemStack) { + return true; + } + + public boolean canIncreaseStack(final int slotID, final ItemStack itemStack) { + return this.getStackInSlot(slotID) == null || + (this.getStackInSlot(slotID).stackSize + 1 <= 64 && + this.getStackInSlot(slotID).isItemEqual(itemStack)); + } + + public void incrStackSize(final int slot, final ItemStack itemStack) { + if (this.getStackInSlot(slot) == null) { + this.setInventorySlotContents(slot, itemStack.copy()); + } else if (this.getStackInSlot(slot).isItemEqual(itemStack)) { + final ItemStack stackInSlot = this.getStackInSlot(slot); + ++stackInSlot.stackSize; + } + } + + public Set getCards() { + final Set cards = new HashSet<>(); + cards.add(this.getStackInSlot(0)); + return cards; + } + + public ItemStack tryPlaceInPosition(ItemStack itemStack, + final Vector3 position, + final ForgeDirection dir) { + final TileEntity tileEntity = position.getTileEntity((IBlockAccess) this.worldObj); + final ForgeDirection direction = dir.getOpposite(); + if (tileEntity != null && itemStack != null) { + if (tileEntity instanceof TileEntityMulti) { + final Vector3 mainBlockPosition = ((TileEntityMulti) tileEntity).mainBlockPosition; + if (mainBlockPosition != null && + !(mainBlockPosition.getTileEntity((IBlockAccess) this.worldObj) instanceof TileEntityMulti)) { + return this.tryPlaceInPosition(itemStack, mainBlockPosition, + direction); + } + } else if (tileEntity instanceof TileEntityChest) { + final TileEntityChest[] chests = { (TileEntityChest) tileEntity, null }; + for (int i = 2; i < 6; ++i) { + final ForgeDirection searchDirection = ForgeDirection.getOrientation(i); + final Vector3 searchPosition = position.clone(); + searchPosition.modifyPositionFromSide(searchDirection); + if (searchPosition.getTileEntity((IBlockAccess) this.worldObj) != null && + searchPosition.getTileEntity((IBlockAccess) this.worldObj) + .getClass() == chests[0].getClass()) { + chests[1] = (TileEntityChest) searchPosition.getTileEntity( + (IBlockAccess) this.worldObj); + break; + } + } + for (final TileEntityChest chest : chests) { + if (chest != null) { + for (int j = 0; j < chest.getSizeInventory(); ++j) { + itemStack = this.addStackToInventory(j, (IInventory) chest, itemStack); + if (itemStack == null) { + return null; + } + } + } + } + } else if (tileEntity instanceof ISidedInventory) { + final ISidedInventory inventory = (ISidedInventory) tileEntity; + final int[] slots = inventory.getAccessibleSlotsFromSide(direction.ordinal()); + for (int k = 0; k < slots.length; ++k) { + if (inventory.canInsertItem(slots[k], itemStack, + direction.ordinal())) { + itemStack = this.addStackToInventory( + slots[k], (IInventory) inventory, itemStack); + } + if (itemStack == null) { + return null; + } + } + } else if (tileEntity instanceof IInventory) { + final IInventory inventory2 = (IInventory) tileEntity; + for (int i = 0; i < inventory2.getSizeInventory(); ++i) { + itemStack = this.addStackToInventory(i, inventory2, itemStack); + if (itemStack == null) { + return null; + } + } + } + } + if (itemStack.stackSize <= 0) { + return null; + } + return itemStack; + } + + public ItemStack addStackToInventory(final int slotIndex, + final IInventory inventory, + final ItemStack itemStack) { + if (inventory.getSizeInventory() > slotIndex) { + ItemStack stackInInventory = inventory.getStackInSlot(slotIndex); + if (stackInInventory == null) { + inventory.setInventorySlotContents(slotIndex, itemStack); + if (inventory.getStackInSlot(slotIndex) == null) { + return itemStack; + } + return null; + } else if (stackInInventory.isItemEqual(itemStack) && + stackInInventory.isStackable()) { + stackInInventory = stackInInventory.copy(); + final int stackLim = Math.min(inventory.getInventoryStackLimit(), + itemStack.getMaxStackSize()); + final int rejectedAmount = Math.max( + stackInInventory.stackSize + itemStack.stackSize - stackLim, 0); + stackInInventory.stackSize = Math.min(Math.max(stackInInventory.stackSize + itemStack.stackSize - + rejectedAmount, + 0), + inventory.getInventoryStackLimit()); + itemStack.stackSize = rejectedAmount; + inventory.setInventorySlotContents(slotIndex, stackInInventory); + } + } + if (itemStack.stackSize <= 0) { + return null; + } + return itemStack; + } + + public boolean mergeIntoInventory(ItemStack itemStack) { + if (!this.worldObj.isRemote) { + for (final ForgeDirection direction : ForgeDirection.VALID_DIRECTIONS) { + if (itemStack != null) { + itemStack = this.tryPlaceInPosition( + itemStack, new Vector3(this).modifyPositionFromSide(direction), + direction); + } + } + if (itemStack != null) { + this.worldObj.spawnEntityInWorld((Entity) new EntityItem( + this.worldObj, this.xCoord + 0.5, (double) (this.yCoord + 1), + this.zCoord + 0.5, itemStack)); + } + } + return false; + } + + @Override + public void readFromNBT(final NBTTagCompound nbttagcompound) { + super.readFromNBT(nbttagcompound); + final NBTTagList nbtTagList = nbttagcompound.getTagList("Items", 10); + this.inventory = new ItemStack[this.getSizeInventory()]; + for (int i = 0; i < nbtTagList.tagCount(); ++i) { + final NBTTagCompound nbttagcompound2 = (NBTTagCompound) nbtTagList.getCompoundTagAt(i); + final byte byte0 = nbttagcompound2.getByte("Slot"); + if (byte0 >= 0 && byte0 < this.inventory.length) { + this.inventory[byte0] = ItemStack.loadItemStackFromNBT(nbttagcompound2); + } + } + } + + @Override + public void writeToNBT(final NBTTagCompound nbttagcompound) { + super.writeToNBT(nbttagcompound); + final NBTTagList nbtTagList = new NBTTagList(); + for (int i = 0; i < this.inventory.length; ++i) { + if (this.inventory[i] != null) { + final NBTTagCompound nbttagcompound2 = new NBTTagCompound(); + nbttagcompound2.setByte("Slot", (byte) i); + this.inventory[i].writeToNBT(nbttagcompound2); + nbtTagList.appendTag((NBTBase) nbttagcompound2); + } + } + nbttagcompound.setTag("Items", (NBTBase) nbtTagList); + } + + @Override + public String getType() { + return this.getInventoryName(); + } + + @Override + public String[] getMethodNames() { + return new String[] { "isActivate", "setActivate" }; + } + + @Override + public Object[] callMethod(IComputerAccess computer, ILuaContext context, + int method, Object[] arguments) + throws LuaException, InterruptedException { + switch (method) { + case 0: { + return new Object[] { this.isActive() }; + } + case 1: { + this.setActive((boolean) arguments[0]); + return null; + } + default: { + throw new LuaException("Invalid method."); + } + } + } + + + @Override + public void attach(final IComputerAccess computer) { + } + + @Override + public void detach(final IComputerAccess computer) { + } +} diff --git a/src/main/java/mffs/base/TileEntityModuleAcceptor.java b/src/main/java/mffs/base/TileEntityModuleAcceptor.java new file mode 100644 index 0000000..137dff3 --- /dev/null +++ b/src/main/java/mffs/base/TileEntityModuleAcceptor.java @@ -0,0 +1,217 @@ +package mffs.base; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; + +import mffs.ModularForceFieldSystem; +import mffs.Settings; +import mffs.api.ICache; +import mffs.api.modules.IModule; +import mffs.api.modules.IModuleAcceptor; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; + +public abstract class TileEntityModuleAcceptor + extends TileEntityFortron implements IModuleAcceptor, ICache { + public final HashMap cache; + public int startModuleIndex; + public int endModuleIndex; + protected int capacityBase; + protected int capacityBoost; + + public TileEntityModuleAcceptor() { + this.cache = new HashMap<>(); + this.startModuleIndex = 0; + this.endModuleIndex = this.getSizeInventory() - 1; + this.capacityBase = 500; + this.capacityBoost = 5; + } + + @Override + public void initiate() { + super.initiate(); + super.fortronTank.setCapacity( + (this.getModuleCount(ModularForceFieldSystem.itemModuleCapacity, + new int[0]) * + this.capacityBoost + + this.capacityBase) * + 1000); + } + + public void consumeCost() { + if (this.getFortronCost() > 0) { + this.requestFortron(this.getFortronCost(), true); + } + } + + @Override + public ItemStack getModule(final IModule module) { + final String cacheID = "getModule_" + module.hashCode(); + if (Settings.USE_CACHE && this.cache.containsKey(cacheID) && + this.cache.get(cacheID) instanceof ItemStack) { + return (ItemStack) this.cache.get(cacheID); + } + final ItemStack returnStack = new ItemStack((Item) module, 0); + for (final ItemStack comparedModule : this.getModuleStacks(new int[0])) { + if (comparedModule.getItem() == module) { + final ItemStack itemStack = returnStack; + itemStack.stackSize += comparedModule.stackSize; + } + } + if (Settings.USE_CACHE) { + this.cache.put(cacheID, returnStack.copy()); + } + return returnStack; + } + + @Override + public int getModuleCount(final IModule module, final int... slots) { + int count = 0; + if (module != null) { + String cacheID = "getModuleCount_" + module.hashCode(); + if (slots != null) { + cacheID = cacheID + "_" + Arrays.hashCode(slots); + } + if (Settings.USE_CACHE && this.cache.containsKey(cacheID) && + this.cache.get(cacheID) instanceof Integer) { + return (int) this.cache.get(cacheID); + } + if (slots != null && slots.length > 0) { + for (final int slotID : slots) { + if (this.getStackInSlot(slotID) != null && + this.getStackInSlot(slotID).getItem() == module) { + count += this.getStackInSlot(slotID).stackSize; + } + } + } else { + for (final ItemStack itemStack : this.getModuleStacks(new int[0])) { + if (itemStack.getItem() == module) { + count += itemStack.stackSize; + } + } + } + if (Settings.USE_CACHE) { + this.cache.put(cacheID, count); + } + } + return count; + } + + @Override + public Set getModuleStacks(final int... slots) { + String cacheID = "getModuleStacks_"; + if (slots != null) { + cacheID += Arrays.hashCode(slots); + } + if (Settings.USE_CACHE && this.cache.containsKey(cacheID) && + this.cache.get(cacheID) instanceof Set) { + return (Set) this.cache.get(cacheID); + } + final Set modules = new HashSet<>(); + if (slots == null || slots.length <= 0) { + for (int slotID = this.startModuleIndex; slotID <= this.endModuleIndex; ++slotID) { + final ItemStack itemStack = this.getStackInSlot(slotID); + if (itemStack != null && itemStack.getItem() instanceof IModule) { + modules.add(itemStack); + } + } + } else { + for (final int slotID2 : slots) { + final ItemStack itemStack2 = this.getStackInSlot(slotID2); + if (itemStack2 != null && itemStack2.getItem() instanceof IModule) { + modules.add(itemStack2); + } + } + } + if (Settings.USE_CACHE) { + this.cache.put(cacheID, modules); + } + return modules; + } + + @Override + public Set getModules(final int... slots) { + String cacheID = "getModules_"; + if (slots != null) { + cacheID += Arrays.hashCode(slots); + } + if (Settings.USE_CACHE && this.cache.containsKey(cacheID) && + this.cache.get(cacheID) instanceof Set) { + return (Set) this.cache.get(cacheID); + } + final Set modules = new HashSet<>(); + if (slots == null || slots.length <= 0) { + for (int slotID = this.startModuleIndex; slotID <= this.endModuleIndex; ++slotID) { + final ItemStack itemStack = this.getStackInSlot(slotID); + if (itemStack != null && itemStack.getItem() instanceof IModule) { + modules.add((IModule) itemStack.getItem()); + } + } + } else { + for (final int slotID2 : slots) { + final ItemStack itemStack2 = this.getStackInSlot(slotID2); + if (itemStack2 != null && itemStack2.getItem() instanceof IModule) { + modules.add((IModule) itemStack2.getItem()); + } + } + } + if (Settings.USE_CACHE) { + this.cache.put(cacheID, modules); + } + return modules; + } + + @Override + public int getFortronCost() { + final String cacheID = "getFortronCost"; + if (Settings.USE_CACHE && this.cache.containsKey(cacheID) && + this.cache.get(cacheID) instanceof Integer) { + return (int) this.cache.get(cacheID); + } + float cost = 0.0f; + for (final ItemStack itemStack : this.getModuleStacks(new int[0])) { + if (itemStack != null) { + cost += itemStack.stackSize * + ((IModule) itemStack.getItem()).getFortronCost(this.getAmplifier()); + } + } + final int result = Math.round(cost); + if (Settings.USE_CACHE) { + this.cache.put(cacheID, result); + } + return result; + } + + protected float getAmplifier() { + return 1.0f; + } + + @Override + public void markDirty() { + super.markDirty(); + super.fortronTank.setCapacity( + (this.getModuleCount(ModularForceFieldSystem.itemModuleCapacity, + new int[0]) * + this.capacityBoost + + this.capacityBase) * + 1000); + this.clearCache(); + } + + @Override + public Object getCache(final String cacheID) { + return this.cache.get(cacheID); + } + + @Override + public void clearCache(final String cacheID) { + this.cache.remove(cacheID); + } + + @Override + public void clearCache() { + this.cache.clear(); + } +} diff --git a/src/main/java/mffs/base/TileEntityUniversalEnergy.java b/src/main/java/mffs/base/TileEntityUniversalEnergy.java new file mode 100644 index 0000000..d9da3e4 --- /dev/null +++ b/src/main/java/mffs/base/TileEntityUniversalEnergy.java @@ -0,0 +1,64 @@ +package mffs.base; + +import calclavia.lib.IUniversalEnergyTile; +import java.util.EnumSet; +import net.minecraftforge.common.util.ForgeDirection; +import universalelectricity.core.UniversalElectricity; +import universalelectricity.core.electricity.ElectricityNetworkHelper; +import universalelectricity.core.electricity.ElectricityPack; + +public abstract class TileEntityUniversalEnergy + extends TileEntityModuleAcceptor implements IUniversalEnergyTile { + public double prevWatts; + public double wattsReceived; + + public TileEntityUniversalEnergy() { this.wattsReceived = 0.0; } + + @Override + public void updateEntity() { + super.updateEntity(); + this.prevWatts = this.wattsReceived; + if (!this.worldObj.isRemote) { + if (!this.isDisabled()) { + final ElectricityPack electricityPack = + ElectricityNetworkHelper.consumeFromMultipleSides( + this, this.getConsumingSides(), this.getRequest()); + this.onReceive(electricityPack); + } else { + ElectricityNetworkHelper.consumeFromMultipleSides( + this, new ElectricityPack()); + } + } + } + + protected EnumSet getConsumingSides() { + return ElectricityNetworkHelper.getDirections(this); + } + + public ElectricityPack getRequest() { return new ElectricityPack(); } + + public void onReceive(final ElectricityPack electricityPack) { + if (UniversalElectricity.isVoltageSensitive && + electricityPack.voltage > this.getVoltage()) { + return; + } + this.wattsReceived = Math.min( + this.wattsReceived + electricityPack.getWatts(), this.getWattBuffer()); + } + + public double getWattBuffer() { return this.getRequest().getWatts() * 2.0; } + + @Override + public double getVoltage() { + return 120.0; + } + + public ElectricityPack produce(double watts) { + ElectricityPack pack = + new ElectricityPack(watts / this.getVoltage(), this.getVoltage()); + ElectricityPack remaining = + ElectricityNetworkHelper.produceFromMultipleSides(this, pack); + + return remaining; + } +} diff --git a/src/main/java/mffs/block/BlockBiometricIdentifier.java b/src/main/java/mffs/block/BlockBiometricIdentifier.java new file mode 100644 index 0000000..7de5e46 --- /dev/null +++ b/src/main/java/mffs/block/BlockBiometricIdentifier.java @@ -0,0 +1,16 @@ +package mffs.block; + +import mffs.tileentity.TileEntityBiometricIdentifier; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; + +public class BlockBiometricIdentifier extends BlockMachineBlock { + public BlockBiometricIdentifier() { + super("biometricIdentifier"); + } + + @Override + public TileEntity createNewTileEntity(final World world, int meta) { + return new TileEntityBiometricIdentifier(); + } +} diff --git a/src/main/java/mffs/block/BlockCoercionDeriver.java b/src/main/java/mffs/block/BlockCoercionDeriver.java new file mode 100644 index 0000000..0699d5d --- /dev/null +++ b/src/main/java/mffs/block/BlockCoercionDeriver.java @@ -0,0 +1,18 @@ +package mffs.block; + +import mffs.base.BlockMachine; +import mffs.tileentity.TileEntityCoercionDeriver; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; + +public class BlockCoercionDeriver extends BlockMachine { + public BlockCoercionDeriver() { + super("coercionDeriver"); + this.setBlockBounds(0.0f, 0.0f, 0.0f, 1.0f, 0.8f, 1.0f); + } + + @Override + public TileEntity createNewTileEntity(final World world, int meta) { + return new TileEntityCoercionDeriver(); + } +} diff --git a/src/main/java/mffs/block/BlockForceField.java b/src/main/java/mffs/block/BlockForceField.java new file mode 100644 index 0000000..38ea235 --- /dev/null +++ b/src/main/java/mffs/block/BlockForceField.java @@ -0,0 +1,323 @@ +package mffs.block; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import java.util.Arrays; +import java.util.List; +import java.util.Random; +import mffs.ModularForceFieldSystem; +import mffs.api.IForceFieldBlock; +import mffs.api.IProjector; +import mffs.api.fortron.IFortronStorage; +import mffs.api.modules.IModule; +import mffs.api.security.IBiometricIdentifier; +import mffs.api.security.Permission; +import mffs.base.BlockBase; +import mffs.render.RenderForceField; +import mffs.tileentity.TileEntityForceField; +import micdoodle8.mods.galacticraft.api.block.IPartialSealableBlock; +import net.minecraft.block.Block; +import net.minecraft.block.material.Material; +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.potion.Potion; +import net.minecraft.potion.PotionEffect; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.util.DamageSource; +import net.minecraft.util.IIcon; +import net.minecraft.util.MovingObjectPosition; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; +import universalelectricity.core.vector.Vector3; +import universalelectricity.prefab.CustomDamageSource; + +public class BlockForceField + extends BlockBase implements IForceFieldBlock, IPartialSealableBlock { + public BlockForceField() { + super("forceField", Material.glass); + this.setBlockUnbreakable(); + this.setResistance(999.0f); + this.setCreativeTab((CreativeTabs)null); + } + + @Override + public boolean isOpaqueCube() { + return false; + } + + @Override + public boolean renderAsNormalBlock() { + return false; + } + + @Override + protected boolean canSilkHarvest() { + return false; + } + + @Override + public int quantityDropped(final Random random) { + return 0; + } + + @Override + @SideOnly(Side.CLIENT) + public int getRenderBlockPass() { + return 1; + } + + @Override + @SideOnly(Side.CLIENT) + public int getRenderType() { + return RenderForceField.ID; + } + + @Override + @SideOnly(Side.CLIENT) + public boolean shouldSideBeRendered(final IBlockAccess par1IBlockAccess, + final int par2, final int par3, + final int par4, final int par5) { + final Block i1 = par1IBlockAccess.getBlock(par2, par3, par4); + return i1 != this && + super.shouldSideBeRendered(par1IBlockAccess, par2, par3, par4, par5); + } + + @Override + public void onBlockClicked(final World world, final int x, final int y, + final int z, final EntityPlayer entityPlayer) { + final TileEntity tileEntity = world.getTileEntity(x, y, z); + if (tileEntity instanceof TileEntityForceField && + ((TileEntityForceField)tileEntity).getProjector() != null) { + for (final ItemStack moduleStack : + ((TileEntityForceField)tileEntity) + .getProjector() + .getModuleStacks(((TileEntityForceField)tileEntity) + .getProjector() + .getModuleSlots())) { + if (((IModule)moduleStack.getItem()) + .onCollideWithForceField(world, x, y, z, (Entity)entityPlayer, + moduleStack)) { + return; + } + } + } + } + + @Override + public AxisAlignedBB getCollisionBoundingBoxFromPool(final World world, + final int x, final int y, + final int z) { + if (this.getProjector((IBlockAccess)world, x, y, z) != null) { + final IBiometricIdentifier BiometricIdentifier = + this.getProjector((IBlockAccess)world, x, y, z) + .getBiometricIdentifier(); + final List entities = world.getEntitiesWithinAABB( + EntityPlayer.class, AxisAlignedBB.getBoundingBox( + (double)x, (double)y, (double)z, + (double)(x + 1), y + 0.9, (double)(z + 1))); + for (final EntityPlayer entityPlayer : (List)entities) { + if (entityPlayer != null && entityPlayer.isSneaking()) { + if (entityPlayer.capabilities.isCreativeMode) { + return null; + } + if (BiometricIdentifier != null && + BiometricIdentifier.isAccessGranted( + entityPlayer.getDisplayName(), Permission.FORCE_FIELD_WARP)) { + return null; + } + continue; + } + } + } + final float f = 0.0625f; + return AxisAlignedBB.getBoundingBox( + (double)(x + f), (double)(y + f), (double)(z + f), (double)(x + 1 - f), + (double)(y + 1 - f), (double)(z + 1 - f)); + } + + @Override + public void onEntityCollidedWithBlock(final World world, final int x, + final int y, final int z, + final Entity entity) { + final TileEntity tileEntity = world.getTileEntity(x, y, z); + if (tileEntity instanceof TileEntityForceField && + this.getProjector((IBlockAccess)world, x, y, z) != null) { + for (final ItemStack moduleStack : + ((TileEntityForceField)tileEntity) + .getProjector() + .getModuleStacks(((TileEntityForceField)tileEntity) + .getProjector() + .getModuleSlots())) { + if (((IModule)moduleStack.getItem()) + .onCollideWithForceField(world, x, y, z, entity, moduleStack)) { + return; + } + } + final IBiometricIdentifier biometricIdentifier = + this.getProjector((IBlockAccess)world, x, y, z) + .getBiometricIdentifier(); + if (new Vector3(entity).distanceTo(new Vector3(x, y, z).add(0.4)) < 0.5 && + entity instanceof EntityLiving && !world.isRemote) { + ((EntityLiving)entity) + .addPotionEffect(new PotionEffect(Potion.confusion.id, 80, 3)); + ((EntityLiving)entity) + .addPotionEffect(new PotionEffect(Potion.moveSlowdown.id, 20, 1)); + boolean hasPermission = false; + final List entities = world.getEntitiesWithinAABB( + EntityPlayer.class, AxisAlignedBB.getBoundingBox( + (double)x, (double)y, (double)z, + (double)(x + 1), y + 0.9, (double)(z + 1))); + for (final EntityPlayer entityPlayer : (List)entities) { + if (entityPlayer != null && entityPlayer.isSneaking()) { + if (entityPlayer.capabilities.isCreativeMode) { + hasPermission = true; + break; + } + if (biometricIdentifier == null || + !biometricIdentifier.isAccessGranted( + entityPlayer.getDisplayName(), + Permission.FORCE_FIELD_WARP)) { + continue; + } + hasPermission = true; + } + } + if (!hasPermission) { + entity.attackEntityFrom( + (DamageSource)CustomDamageSource.electrocution, + Integer.MAX_VALUE); + } + } + } + } + + @Override + public IIcon getIcon(final IBlockAccess iBlockAccess, final int x, + final int y, final int z, final int side) { + final TileEntity tileEntity = iBlockAccess.getTileEntity(x, y, z); + if (tileEntity instanceof TileEntityForceField) { + final ItemStack checkStack = ((TileEntityForceField)tileEntity).camoStack; + if (checkStack != null) { + try { + final Block block = Block.getBlockFromItem(checkStack.getItem()); + final Integer[] allowedRenderTypes = { + 0, 1, 4, 31, 20, 39, 5, 13, 23, 6, 8, 7, 12, 29, 30, 14, 16, 17}; + if (Arrays.asList(allowedRenderTypes) + .contains(block.getRenderType())) { + final IIcon icon = block.getIcon(side, checkStack.getItemDamage()); + if (icon != null) { + return icon; + } + } + } catch (final Exception e) { + e.printStackTrace(); + } + } + } + return this.getIcon(side, iBlockAccess.getBlockMetadata(x, y, z)); + } + + @Override + public int colorMultiplier(final IBlockAccess iBlockAccess, final int x, + final int y, final int z) { + try { + final TileEntity tileEntity = iBlockAccess.getTileEntity(x, y, z); + if (tileEntity instanceof TileEntityForceField) { + final ItemStack checkStack = + ((TileEntityForceField)tileEntity).camoStack; + if (checkStack != null) { + try { + return Block.getBlockFromItem(checkStack.getItem()) + .colorMultiplier(iBlockAccess, x, y, x); + } catch (final Exception e) { + e.printStackTrace(); + } + } + } + } catch (final Exception e2) { + e2.printStackTrace(); + } + return super.colorMultiplier(iBlockAccess, x, y, z); + } + + @Override + public int getLightValue(final IBlockAccess iBlockAccess, final int x, + final int y, final int z) { + try { + final TileEntity tileEntity = iBlockAccess.getTileEntity(x, y, z); + if (tileEntity instanceof TileEntityForceField) { + final IProjector zhuYao = + ((TileEntityForceField)tileEntity).getProjectorSafe(); + if (zhuYao instanceof IProjector) { + return (int)(Math.min(zhuYao.getModuleCount( + ModularForceFieldSystem.itemModuleGlow, + new int[0]), + 64) / + 64.0f * 15.0f); + } + } + } catch (final Exception e) { + e.printStackTrace(); + } + return 0; + } + + @Override + public float getExplosionResistance(final Entity entity, final World world, + final int x, final int y, final int z, + final double d, final double d1, + final double d2) { + return 2.1474836E9f; + } + + @Override + public TileEntity createNewTileEntity(final World world, int meta) { + return new TileEntityForceField(); + } + + @Override + public void weakenForceField(final World world, final int x, final int y, + final int z, final int joules) { + final IProjector projector = + this.getProjector((IBlockAccess)world, x, y, z); + if (projector != null) { + ((IFortronStorage)projector).provideFortron(joules, true); + } + world.setBlock(x, y, z, Blocks.air, 0, 3); + } + + @Override + public ItemStack getPickBlock(final MovingObjectPosition target, + final World world, final int x, final int y, + final int z) { + return null; + } + + @Override + public IProjector getProjector(final IBlockAccess iBlockAccess, final int x, + final int y, final int z) { + final TileEntity tileEntity = iBlockAccess.getTileEntity(x, y, z); + if (tileEntity instanceof TileEntityForceField) { + return ((TileEntityForceField)tileEntity).getProjector(); + } + return null; + } + + @Override + public boolean isSealed(World world, int x, int y, int z, + ForgeDirection direction) { + return true; + } + + @Override + public void registerBlockIcons(IIconRegister p_149651_1_) { + this.blockIcon = p_149651_1_.registerIcon("mffs:forceField"); + } +} diff --git a/src/main/java/mffs/block/BlockForceFieldProjector.java b/src/main/java/mffs/block/BlockForceFieldProjector.java new file mode 100644 index 0000000..f5482f3 --- /dev/null +++ b/src/main/java/mffs/block/BlockForceFieldProjector.java @@ -0,0 +1,40 @@ +package mffs.block; + +import mffs.base.BlockMachine; +import mffs.tileentity.TileEntityForceFieldProjector; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; + +public class BlockForceFieldProjector extends BlockMachine { + public BlockForceFieldProjector() { + super("projector"); + this.setBlockBounds(0.0f, 0.0f, 0.0f, 1.0f, 0.8f, 1.0f); + } + + @Override + public TileEntity createNewTileEntity(final World world, int meta) { + return new TileEntityForceFieldProjector(); + } + + @Override + public boolean onMachineActivated(final World world, final int i, final int j, final int k, + final EntityPlayer entityplayer, final int par6, + final float par7, final float par8, final float par9) { + final TileEntityForceFieldProjector tileentity = (TileEntityForceFieldProjector) world.getTileEntity(i, j, k); + return !tileentity.isDisabled() && + super.onMachineActivated(world, i, j, k, entityplayer, par6, par7, par8, + par9); + } + + public int getLightValue(final IBlockAccess iBlockAccess, final int x, + final int y, final int z) { + final TileEntity tileEntity = iBlockAccess.getTileEntity(x, y, z); + if (tileEntity instanceof TileEntityForceFieldProjector && + ((TileEntityForceFieldProjector) tileEntity).getMode() != null) { + return 10; + } + return super.getLightValue(iBlockAccess, x, y, z); + } +} diff --git a/src/main/java/mffs/block/BlockForceManipulator.java b/src/main/java/mffs/block/BlockForceManipulator.java new file mode 100644 index 0000000..5fb9d05 --- /dev/null +++ b/src/main/java/mffs/block/BlockForceManipulator.java @@ -0,0 +1,70 @@ +package mffs.block; + +import mffs.base.BlockMachine; +import mffs.tileentity.TileEntityForceManipulator; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.MathHelper; +import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; + +public class BlockForceManipulator extends BlockMachine { + public BlockForceManipulator() { + super("manipulator"); + } + + public static int determineOrientation(final World world, final int x, + final int y, final int z, + final EntityPlayer entityPlayer) { + if (MathHelper.abs((float) ((Entity) entityPlayer).posX - x) < 2.0f && + MathHelper.abs((float) ((Entity) entityPlayer).posZ - z) < 2.0f) { + final double var5 = ((Entity) entityPlayer).posY + 1.82 - ((Entity) entityPlayer).yOffset; + if (var5 - y > 2.0) { + return 1; + } + if (y - var5 > 0.0) { + return 0; + } + } + final int var6 = MathHelper.floor_double( + ((Entity) entityPlayer).rotationYaw * 4.0f / 360.0f + 0.5) & + 0x3; + return (var6 == 0) + ? 2 + : ((var6 == 1) ? 5 : ((var6 == 2) ? 3 : ((var6 == 3) ? 4 : 0))); + } + + @Override + public void onBlockPlacedBy(final World world, final int x, final int y, + final int z, + final EntityLivingBase par5EntityLiving, + final ItemStack stack) { + final int metadata = determineOrientation( + world, x, y, z, + (EntityPlayer) par5EntityLiving); // TODO: ClassCastException? + world.setBlockMetadataWithNotify(x, y, z, metadata, 2); + } + + @Override + public boolean onUseWrench(final World world, final int x, final int y, + final int z, final EntityPlayer par5EntityPlayer, + final int side, final float hitX, final float hitY, + final float hitZ) { + final int mask = 7; + final int rotMeta = world.getBlockMetadata(x, y, z); + final int masked = rotMeta & ~mask; + final ForgeDirection orientation = ForgeDirection.getOrientation(rotMeta & mask); + final ForgeDirection rotated = orientation.getRotation(ForgeDirection.getOrientation(side)); + world.setBlockMetadataWithNotify(x, y, z, + (rotated.ordinal() & mask) | masked, 3); + return true; + } + + @Override + public TileEntity createNewTileEntity(final World world, int meta) { + return new TileEntityForceManipulator(); + } +} diff --git a/src/main/java/mffs/block/BlockFortronCapacitor.java b/src/main/java/mffs/block/BlockFortronCapacitor.java new file mode 100644 index 0000000..be56daa --- /dev/null +++ b/src/main/java/mffs/block/BlockFortronCapacitor.java @@ -0,0 +1,17 @@ +package mffs.block; + +import mffs.base.BlockMachine; +import mffs.tileentity.TileEntityFortronCapacitor; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; + +public class BlockFortronCapacitor extends BlockMachine { + public BlockFortronCapacitor() { + super("fortronCapacitor"); + } + + @Override + public TileEntity createNewTileEntity(final World world, int meta) { + return new TileEntityFortronCapacitor(); + } +} diff --git a/src/main/java/mffs/block/BlockInterdictionMatrix.java b/src/main/java/mffs/block/BlockInterdictionMatrix.java new file mode 100644 index 0000000..767ebe4 --- /dev/null +++ b/src/main/java/mffs/block/BlockInterdictionMatrix.java @@ -0,0 +1,16 @@ +package mffs.block; + +import mffs.tileentity.TileEntityInterdictionMatrix; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; + +public class BlockInterdictionMatrix extends BlockMachineBlock { + public BlockInterdictionMatrix() { + super("interdictionMatrix"); + } + + @Override + public TileEntity createNewTileEntity(final World world, int meta) { + return new TileEntityInterdictionMatrix(); + } +} diff --git a/src/main/java/mffs/block/BlockMachineBlock.java b/src/main/java/mffs/block/BlockMachineBlock.java new file mode 100644 index 0000000..719e471 --- /dev/null +++ b/src/main/java/mffs/block/BlockMachineBlock.java @@ -0,0 +1,63 @@ +package mffs.block; + +import mffs.base.BlockMachine; +import mffs.base.TileEntityBase; +import net.minecraft.client.renderer.texture.IIconRegister; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.IIcon; +import net.minecraft.world.IBlockAccess; + +public abstract class BlockMachineBlock extends BlockMachine { + protected IIcon blockIconTop; + protected IIcon blockIconOn; + protected IIcon blockIconTopOn; + + public BlockMachineBlock(final String name) { + super(name); + } + + @Override + public IIcon getIcon(final IBlockAccess par1IBlockAccess, final int x, + final int y, final int z, final int side) { + final TileEntity tileEntity = par1IBlockAccess.getTileEntity(x, y, z); + if (tileEntity instanceof TileEntityBase && + ((TileEntityBase) tileEntity).isActive()) { + if (side == 0 || side == 1) { + return this.blockIconTopOn; + } + return this.blockIconOn; + } else { + if (side == 0 || side == 1) { + return this.blockIconTop; + } + return this.blockIcon; + } + } + + @Override + public void registerBlockIcons(final IIconRegister reg) { + this.blockIcon = reg.registerIcon( + this.getUnlocalizedName().replace("tile.", "")); + this.blockIconTop = reg.registerIcon( + this.getUnlocalizedName().replace("tile.", "") + "_top"); + this.blockIconOn = reg.registerIcon( + this.getUnlocalizedName().replace("tile.", "") + "_on"); + this.blockIconTopOn = reg.registerIcon( + this.getUnlocalizedName().replace("tile.", "") + "_top_on"); + } + + @Override + public boolean isOpaqueCube() { + return true; + } + + @Override + public boolean renderAsNormalBlock() { + return true; + } + + @Override + public int getRenderType() { + return 0; + } +} diff --git a/src/main/java/mffs/card/ItemCard.java b/src/main/java/mffs/card/ItemCard.java new file mode 100644 index 0000000..5a35d37 --- /dev/null +++ b/src/main/java/mffs/card/ItemCard.java @@ -0,0 +1,11 @@ +package mffs.card; + +import mffs.api.card.ICard; +import mffs.base.ItemBase; + +public class ItemCard extends ItemBase implements ICard { + public ItemCard(final String name) { + super(name); + this.setMaxStackSize(1); + } +} diff --git a/src/main/java/mffs/container/ContainerBiometricIdentifier.java b/src/main/java/mffs/container/ContainerBiometricIdentifier.java new file mode 100644 index 0000000..aa6adde --- /dev/null +++ b/src/main/java/mffs/container/ContainerBiometricIdentifier.java @@ -0,0 +1,25 @@ +package mffs.container; + +import mffs.base.ContainerBase; +import mffs.slot.SlotActive; +import mffs.slot.SlotBase; +import mffs.tileentity.TileEntityBiometricIdentifier; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.Slot; + +public class ContainerBiometricIdentifier extends ContainerBase { + public ContainerBiometricIdentifier(final EntityPlayer player, + final TileEntityBiometricIdentifier tileentity) { + super((IInventory) tileentity); + this.addSlotToContainer((Slot) new SlotActive(tileentity, 0, 88, 91)); + this.addSlotToContainer((Slot) new SlotBase(tileentity, 1, 8, 46)); + this.addSlotToContainer((Slot) new SlotActive(tileentity, 2, 8, 91)); + for (int var4 = 0; var4 < 9; ++var4) { + this.addSlotToContainer( + (Slot) new SlotActive(tileentity, 3 + var4, 8 + var4 * 18, 111)); + } + this.addSlotToContainer((Slot) new SlotBase(tileentity, 12, 8, 66)); + this.addPlayerInventory(player); + } +} diff --git a/src/main/java/mffs/container/ContainerCoercionDeriver.java b/src/main/java/mffs/container/ContainerCoercionDeriver.java new file mode 100644 index 0000000..ecc5797 --- /dev/null +++ b/src/main/java/mffs/container/ContainerCoercionDeriver.java @@ -0,0 +1,23 @@ +package mffs.container; + +import mffs.base.ContainerBase; +import mffs.slot.SlotBase; +import mffs.slot.SlotCard; +import mffs.tileentity.TileEntityCoercionDeriver; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.Slot; + +public class ContainerCoercionDeriver extends ContainerBase { + public ContainerCoercionDeriver(final EntityPlayer player, + final TileEntityCoercionDeriver tileEntity) { + super((IInventory) tileEntity); + this.addSlotToContainer((Slot) new SlotCard(tileEntity, 0, 9, 41)); + this.addSlotToContainer((Slot) new SlotBase(tileEntity, 1, 9, 83)); + this.addSlotToContainer((Slot) new SlotBase(tileEntity, 2, 29, 83)); + this.addSlotToContainer((Slot) new SlotBase(tileEntity, 3, 154, 67)); + this.addSlotToContainer((Slot) new SlotBase(tileEntity, 4, 154, 87)); + this.addSlotToContainer((Slot) new SlotBase(tileEntity, 5, 154, 47)); + this.addPlayerInventory(player); + } +} diff --git a/src/main/java/mffs/container/ContainerForceFieldProjector.java b/src/main/java/mffs/container/ContainerForceFieldProjector.java new file mode 100644 index 0000000..7edb2c3 --- /dev/null +++ b/src/main/java/mffs/container/ContainerForceFieldProjector.java @@ -0,0 +1,38 @@ +package mffs.container; + +import mffs.base.ContainerBase; +import mffs.slot.SlotBase; +import mffs.slot.SlotCard; +import mffs.tileentity.TileEntityForceFieldProjector; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.Slot; + +public class ContainerForceFieldProjector extends ContainerBase { + public ContainerForceFieldProjector(final EntityPlayer player, + final TileEntityForceFieldProjector tileEntity) { + super((IInventory) tileEntity); + this.addSlotToContainer((Slot) new SlotCard(tileEntity, 0, 10, 89)); + this.addSlotToContainer((Slot) new SlotCard(tileEntity, 1, 28, 89)); + this.addSlotToContainer((Slot) new SlotBase(tileEntity, 2, 118, 45)); + int i = 3; + for (int xSlot = 0; xSlot < 4; ++xSlot) { + for (int ySlot = 0; ySlot < 4; ++ySlot) { + if ((xSlot != 1 || ySlot != 1) && (xSlot != 2 || ySlot != 2) && + (xSlot != 1 || ySlot != 2) && (xSlot != 2 || ySlot != 1)) { + this.addSlotToContainer((Slot) new SlotBase( + tileEntity, i, 91 + 18 * xSlot, 18 + 18 * ySlot)); + ++i; + } + } + } + for (int xSlot = 0; xSlot < 3; ++xSlot) { + for (int ySlot = 0; ySlot < 2; ++ySlot) { + this.addSlotToContainer((Slot) new SlotBase( + tileEntity, i, 19 + 18 * xSlot, 36 + 18 * ySlot)); + ++i; + } + } + this.addPlayerInventory(player); + } +} diff --git a/src/main/java/mffs/container/ContainerForceManipulator.java b/src/main/java/mffs/container/ContainerForceManipulator.java new file mode 100644 index 0000000..2dfcd1a --- /dev/null +++ b/src/main/java/mffs/container/ContainerForceManipulator.java @@ -0,0 +1,38 @@ +package mffs.container; + +import mffs.base.ContainerBase; +import mffs.slot.SlotBase; +import mffs.slot.SlotCard; +import mffs.tileentity.TileEntityForceManipulator; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.Slot; + +public class ContainerForceManipulator extends ContainerBase { + public ContainerForceManipulator( + final EntityPlayer player, final TileEntityForceManipulator tileEntity) { + super((IInventory) tileEntity); + this.addSlotToContainer((Slot) new SlotCard(tileEntity, 0, 73, 91)); + this.addSlotToContainer((Slot) new SlotCard(tileEntity, 1, 91, 91)); + this.addSlotToContainer((Slot) new SlotBase(tileEntity, 2, 118, 45)); + int i = 3; + for (int xSlot = 0; xSlot < 4; ++xSlot) { + for (int ySlot = 0; ySlot < 4; ++ySlot) { + if ((xSlot != 1 || ySlot != 1) && (xSlot != 2 || ySlot != 2) && + (xSlot != 1 || ySlot != 2) && (xSlot != 2 || ySlot != 1)) { + this.addSlotToContainer((Slot) new SlotBase( + tileEntity, i, 91 + 18 * xSlot, 18 + 18 * ySlot)); + ++i; + } + } + } + for (int xSlot = 0; xSlot < 3; ++xSlot) { + for (int ySlot = 0; ySlot < 2; ++ySlot) { + this.addSlotToContainer((Slot) new SlotBase( + tileEntity, i, 31 + 18 * xSlot, 19 + 18 * ySlot)); + ++i; + } + } + this.addPlayerInventory(player); + } +} diff --git a/src/main/java/mffs/container/ContainerFortronCapacitor.java b/src/main/java/mffs/container/ContainerFortronCapacitor.java new file mode 100644 index 0000000..c566db5 --- /dev/null +++ b/src/main/java/mffs/container/ContainerFortronCapacitor.java @@ -0,0 +1,25 @@ +package mffs.container; + +import mffs.base.ContainerBase; +import mffs.slot.SlotBase; +import mffs.slot.SlotCard; +import mffs.tileentity.TileEntityFortronCapacitor; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.Slot; + +public class ContainerFortronCapacitor extends ContainerBase { + private TileEntityFortronCapacitor tileEntity; + + public ContainerFortronCapacitor( + final EntityPlayer player, final TileEntityFortronCapacitor tileEntity) { + super((IInventory) tileEntity); + this.tileEntity = tileEntity; + this.addSlotToContainer((Slot) new SlotCard(this.tileEntity, 0, 9, 74)); + this.addSlotToContainer((Slot) new SlotCard(this.tileEntity, 1, 27, 74)); + this.addSlotToContainer((Slot) new SlotBase(this.tileEntity, 2, 154, 47)); + this.addSlotToContainer((Slot) new SlotBase(this.tileEntity, 3, 154, 67)); + this.addSlotToContainer((Slot) new SlotBase(this.tileEntity, 4, 154, 87)); + this.addPlayerInventory(player); + } +} diff --git a/src/main/java/mffs/container/ContainerInterdictionMatrix.java b/src/main/java/mffs/container/ContainerInterdictionMatrix.java new file mode 100644 index 0000000..aba940f --- /dev/null +++ b/src/main/java/mffs/container/ContainerInterdictionMatrix.java @@ -0,0 +1,29 @@ +package mffs.container; + +import mffs.base.ContainerBase; +import mffs.slot.SlotBase; +import mffs.slot.SlotCard; +import mffs.tileentity.TileEntityInterdictionMatrix; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.Slot; + +public class ContainerInterdictionMatrix extends ContainerBase { + public ContainerInterdictionMatrix(final EntityPlayer player, + final TileEntityInterdictionMatrix tileEntity) { + super((IInventory) tileEntity); + this.addSlotToContainer((Slot) new SlotCard(tileEntity, 0, 87, 89)); + this.addSlotToContainer((Slot) new SlotBase(tileEntity, 1, 69, 89)); + for (int var3 = 0; var3 < 2; ++var3) { + for (int var4 = 0; var4 < 4; ++var4) { + this.addSlotToContainer((Slot) new SlotBase( + tileEntity, var4 + var3 * 4 + 2, 99 + var4 * 18, 31 + var3 * 18)); + } + } + for (int var5 = 0; var5 < 9; ++var5) { + this.addSlotToContainer( + (Slot) new SlotBase(tileEntity, var5 + 8 + 2, 9 + var5 * 18, 69)); + } + this.addPlayerInventory(player); + } +} diff --git a/src/main/java/mffs/event/BlockDropDelayedEvent.java b/src/main/java/mffs/event/BlockDropDelayedEvent.java new file mode 100644 index 0000000..4f44f64 --- /dev/null +++ b/src/main/java/mffs/event/BlockDropDelayedEvent.java @@ -0,0 +1,35 @@ +package mffs.event; + +import mffs.DelayedEvent; +import mffs.IDelayedEventHandler; +import net.minecraft.block.Block; +import net.minecraft.init.Blocks; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; +import universalelectricity.core.vector.Vector3; + +public class BlockDropDelayedEvent extends DelayedEvent { + protected Block block; + protected World world; + protected Vector3 position; + + public BlockDropDelayedEvent(final IDelayedEventHandler handler, + final int ticks, final Block block, + final World world, final Vector3 position) { + super(handler, ticks); + this.block = block; + this.world = world; + this.position = position; + } + + @Override + protected void onEvent() { + if (this.position.getBlock((IBlockAccess) this.world) == this.block) { + this.block.dropBlockAsItem( + this.world, this.position.intX(), this.position.intY(), + this.position.intZ(), + this.position.getBlockMetadata((IBlockAccess) this.world), 0); + this.position.setBlock(this.world, Blocks.air); + } + } +} diff --git a/src/main/java/mffs/event/BlockInventoryDropDelayedEvent.java b/src/main/java/mffs/event/BlockInventoryDropDelayedEvent.java new file mode 100644 index 0000000..2f3e08e --- /dev/null +++ b/src/main/java/mffs/event/BlockInventoryDropDelayedEvent.java @@ -0,0 +1,38 @@ +package mffs.event; + +import java.util.ArrayList; +import mffs.IDelayedEventHandler; +import mffs.base.TileEntityInventory; +import net.minecraft.block.Block; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; +import universalelectricity.core.vector.Vector3; + +public class BlockInventoryDropDelayedEvent extends BlockDropDelayedEvent { + private TileEntityInventory projector; + + public BlockInventoryDropDelayedEvent(final IDelayedEventHandler handler, + final int ticks, final Block block, + final World world, + final Vector3 position, + final TileEntityInventory projector) { + super(handler, ticks, block, world, position); + this.projector = projector; + } + + @Override + protected void onEvent() { + if (super.position.getBlock((IBlockAccess) super.world) == super.block) { + final ArrayList itemStacks = super.block.getDrops( + super.world, super.position.intX(), super.position.intY(), + super.position.intZ(), + super.position.getBlockMetadata((IBlockAccess) super.world), 0); + for (final ItemStack itemStack : itemStacks) { + this.projector.mergeIntoInventory(itemStack); + } + super.position.setBlock(super.world, Blocks.air); + } + } +} diff --git a/src/main/java/mffs/event/BlockNotifyDelayedEvent.java b/src/main/java/mffs/event/BlockNotifyDelayedEvent.java new file mode 100644 index 0000000..43aba54 --- /dev/null +++ b/src/main/java/mffs/event/BlockNotifyDelayedEvent.java @@ -0,0 +1,52 @@ +package mffs.event; + +import cpw.mods.fml.common.Loader; +import cpw.mods.fml.relauncher.ReflectionHelper; +import mffs.DelayedEvent; +import mffs.IDelayedEventHandler; +import mffs.api.ISpecialForceManipulation; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; +import universalelectricity.core.vector.Vector3; + +public class BlockNotifyDelayedEvent extends DelayedEvent { + private World world; + private Vector3 position; + + public BlockNotifyDelayedEvent(final IDelayedEventHandler handler, + final int ticks, final World world, + final Vector3 position) { + super(handler, ticks); + this.world = world; + this.position = position; + } + + @Override + protected void onEvent() { + if (!this.world.isRemote) { + this.world.notifyBlocksOfNeighborChange( + this.position.intX(), this.position.intY(), this.position.intZ(), + this.position.getBlock((IBlockAccess) this.world)); + final TileEntity newTile = this.position.getTileEntity((IBlockAccess) this.world); + if (newTile != null) { + if (newTile instanceof ISpecialForceManipulation) { + ((ISpecialForceManipulation) newTile).postMove(); + } + if (Loader.isModLoaded("BuildCraft|Factory")) { + try { + final Class clazz = Class.forName("buildcraft.factory.TileQuarry"); + if (clazz == newTile.getClass()) { + // TODO: W T F AAAAAAAAAAAAA + ReflectionHelper.setPrivateValue(clazz, (Object) newTile, + (Object) true, + new String[] { "isAlive" }); + } + } catch (final Exception e) { + e.printStackTrace(); + } + } + } + } + } +} diff --git a/src/main/java/mffs/event/BlockPostMoveDelayedEvent.java b/src/main/java/mffs/event/BlockPostMoveDelayedEvent.java new file mode 100644 index 0000000..0dc82b6 --- /dev/null +++ b/src/main/java/mffs/event/BlockPostMoveDelayedEvent.java @@ -0,0 +1,63 @@ +package mffs.event; + +import mffs.DelayedEvent; +import mffs.IDelayedEventHandler; +import mffs.ManipulatorHelper; +import net.minecraft.block.Block; +import net.minecraft.init.Blocks; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; +import universalelectricity.core.vector.Vector3; + +public class BlockPostMoveDelayedEvent extends DelayedEvent { + private World world; + private Vector3 originalPosition; + private Vector3 newPosition; + private Block blockID; + private int blockMetadata; + private TileEntity tileEntity; + private NBTTagCompound tileData; + + public BlockPostMoveDelayedEvent(final IDelayedEventHandler handler, + final int ticks, final World world, + final Vector3 originalPosition, + final Vector3 newPosition, final Block blockID, + final int blockMetadata, + final TileEntity tileEntity, + final NBTTagCompound tileData) { + super(handler, ticks); + this.blockID = Blocks.air; + this.blockMetadata = 0; + this.world = world; + this.originalPosition = originalPosition; + this.newPosition = newPosition; + this.blockID = blockID; + this.blockMetadata = blockMetadata; + this.tileEntity = tileEntity; + this.tileData = tileData; + } + + @Override + protected void onEvent() { + if (!this.world.isRemote && this.blockID != Blocks.air) { + try { + if (this.tileEntity != null && this.tileData != null) { + ManipulatorHelper.setBlockSneaky( + this.world, this.newPosition, this.blockID, this.blockMetadata, + TileEntity.createAndLoadEntity(this.tileData)); + } else { + ManipulatorHelper.setBlockSneaky(this.world, this.newPosition, + this.blockID, this.blockMetadata, + null); + } + super.handler.getQuedDelayedEvents().add(new BlockNotifyDelayedEvent( + super.handler, 0, this.world, this.originalPosition)); + super.handler.getQuedDelayedEvents().add(new BlockNotifyDelayedEvent( + super.handler, 0, this.world, this.newPosition)); + } catch (final Exception e) { + e.printStackTrace(); + } + } + } +} diff --git a/src/main/java/mffs/event/BlockPreMoveDelayedEvent.java b/src/main/java/mffs/event/BlockPreMoveDelayedEvent.java new file mode 100644 index 0000000..8324ac1 --- /dev/null +++ b/src/main/java/mffs/event/BlockPreMoveDelayedEvent.java @@ -0,0 +1,52 @@ +package mffs.event; + +import mffs.DelayedEvent; +import mffs.IDelayedEventHandler; +import mffs.ManipulatorHelper; +import mffs.api.ISpecialForceManipulation; +import net.minecraft.block.Block; +import net.minecraft.init.Blocks; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; +import universalelectricity.core.vector.Vector3; + +public class BlockPreMoveDelayedEvent extends DelayedEvent { + private World world; + private Vector3 position; + private Vector3 newPosition; + + public BlockPreMoveDelayedEvent(final IDelayedEventHandler handler, + final int ticks, final World world, + final Vector3 position, + final Vector3 newPosition) { + super(handler, ticks); + this.world = world; + this.position = position; + this.newPosition = newPosition; + } + + @Override + protected void onEvent() { + if (!this.world.isRemote) { + final TileEntity tileEntity = this.position.getTileEntity((IBlockAccess) this.world); + if (tileEntity instanceof ISpecialForceManipulation) { + ((ISpecialForceManipulation) tileEntity) + .move(this.newPosition.intX(), this.newPosition.intY(), + this.newPosition.intZ()); + } + final Block blockID = this.position.getBlock((IBlockAccess) this.world); + final int blockMetadata = this.position.getBlockMetadata((IBlockAccess) this.world); + final NBTTagCompound tileData = new NBTTagCompound(); + if (tileEntity != null) { + tileEntity.writeToNBT(tileData); + } + ManipulatorHelper.setBlockSneaky(this.world, this.position, Blocks.air, 0, + null); + super.handler.getQuedDelayedEvents().add(new BlockPostMoveDelayedEvent( + super.handler, 0, this.world, this.position, this.newPosition, + blockID, blockMetadata, tileEntity, tileData)); + } + } +} diff --git a/src/main/java/mffs/fortron/FortronHelper.java b/src/main/java/mffs/fortron/FortronHelper.java new file mode 100644 index 0000000..e3a8c43 --- /dev/null +++ b/src/main/java/mffs/fortron/FortronHelper.java @@ -0,0 +1,28 @@ +package mffs.fortron; + +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.FluidTank; + +public class FortronHelper +{ + public static Fluid FLUID_FORTRON; + + public static FluidStack getFortron(final int amount) { + return new FluidStack(FLUID_FORTRON, amount); + } + + public static int getAmount(final FluidStack fluidStack) { + if (fluidStack != null) { + return fluidStack.amount; + } + return 0; + } + + public static int getAmount(final FluidTank fortronTank) { + if (fortronTank != null) { + return fortronTank.getFluidAmount(); + } + return 0; + } +} diff --git a/src/main/java/mffs/fortron/FrequencyGrid.java b/src/main/java/mffs/fortron/FrequencyGrid.java new file mode 100644 index 0000000..fdafea5 --- /dev/null +++ b/src/main/java/mffs/fortron/FrequencyGrid.java @@ -0,0 +1,131 @@ +package mffs.fortron; + +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.relauncher.Side; +import icbm.api.IBlockFrequency; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import mffs.api.fortron.IFortronFrequency; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; +import universalelectricity.core.vector.Vector3; + +public class FrequencyGrid { + private static FrequencyGrid CLIENT_INSTANCE; + private static FrequencyGrid SERVER_INSTANCE; + private final Set frequencyGrid; + + public FrequencyGrid() { + this.frequencyGrid = new HashSet<>(); + } + + public void register(final IBlockFrequency tileEntity) { + try { + final Iterator it = this.frequencyGrid.iterator(); + while (it.hasNext()) { + final IBlockFrequency frequency = it.next(); + if (frequency == null) { + it.remove(); + } else if (((TileEntity) frequency).isInvalid()) { + it.remove(); + } else { + if (!new Vector3((TileEntity) frequency) + .equals(new Vector3((TileEntity) tileEntity))) { + continue; + } + it.remove(); + } + } + } catch (final Exception e) { + e.printStackTrace(); + } + this.frequencyGrid.add(tileEntity); + } + + public void unregister(final IBlockFrequency tileEntity) { + this.frequencyGrid.remove(tileEntity); + this.cleanUp(); + } + + public Set get() { + return this.frequencyGrid; + } + + public Set get(final int frequency) { + final Set set = new HashSet<>(); + for (final IBlockFrequency tile : this.get()) { + if (tile != null && !((TileEntity) tile).isInvalid() && + tile.getFrequency() == frequency) { + set.add(tile); + } + } + return set; + } + + public void cleanUp() { + try { + final Iterator it = this.frequencyGrid.iterator(); + while (it.hasNext()) { + final IBlockFrequency frequency = it.next(); + if (frequency == null) { + it.remove(); + } else if (((TileEntity) frequency).isInvalid()) { + it.remove(); + } else { + if (((TileEntity) frequency).getWorldObj().getTileEntity( + ((TileEntity) frequency).xCoord, + ((TileEntity) frequency).yCoord, + ((TileEntity) frequency).zCoord) == (TileEntity) frequency) { + continue; + } + it.remove(); + } + } + } catch (final Exception e) { + e.printStackTrace(); + } + } + + public Set get(final World world, final Vector3 position, final int radius, + final int frequency) { + final Set set = new HashSet(); + for (final IBlockFrequency tileEntity : this.get(frequency)) { + if (((TileEntity) tileEntity).getWorldObj() == world && + Vector3.distance(new Vector3((TileEntity) tileEntity), position) <= radius) { + set.add(tileEntity); + } + } + return set; + } + + public Set getFortronTiles(final World world, final Vector3 position, + final int radius, final int frequency) { + final Set set = new HashSet(); + for (final IBlockFrequency tileEntity : this.get(frequency)) { + if (((TileEntity) tileEntity).getWorldObj() == world && + tileEntity instanceof IFortronFrequency && + Vector3.distance(new Vector3((TileEntity) tileEntity), position) <= radius) { + set.add(tileEntity); + } + } + return set; + } + + public static void reinitiate() { + FrequencyGrid.CLIENT_INSTANCE = new FrequencyGrid(); + FrequencyGrid.SERVER_INSTANCE = new FrequencyGrid(); + } + + public static FrequencyGrid instance() { + if (FMLCommonHandler.instance().getEffectiveSide() == Side.SERVER) { + return FrequencyGrid.SERVER_INSTANCE; + } + return FrequencyGrid.CLIENT_INSTANCE; + } + + static { + FrequencyGrid.CLIENT_INSTANCE = new FrequencyGrid(); + FrequencyGrid.SERVER_INSTANCE = new FrequencyGrid(); + } +} diff --git a/src/main/java/mffs/gui/GuiBiometricIdentifier.java b/src/main/java/mffs/gui/GuiBiometricIdentifier.java new file mode 100644 index 0000000..5f49b6e --- /dev/null +++ b/src/main/java/mffs/gui/GuiBiometricIdentifier.java @@ -0,0 +1,147 @@ +package mffs.gui; + +import mffs.ModularForceFieldSystem; +import mffs.api.card.ICardIdentification; +import mffs.api.security.Permission; +import mffs.base.GuiBase; +import mffs.base.PacketTile; +import mffs.container.ContainerBiometricIdentifier; +import mffs.gui.button.GuiButtonPress; +import mffs.tileentity.TileEntityBiometricIdentifier; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.gui.GuiTextField; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.nbt.NBTTagCompound; +import universalelectricity.core.vector.Vector2; +import universalelectricity.core.vector.Vector3; + +public class GuiBiometricIdentifier extends GuiBase { + private TileEntityBiometricIdentifier tileEntity; + private GuiTextField textFieldUsername; + + public GuiBiometricIdentifier(final EntityPlayer player, + final TileEntityBiometricIdentifier tileEntity) { + super(new ContainerBiometricIdentifier(player, tileEntity), tileEntity); + this.tileEntity = tileEntity; + } + + @Override + public void initGui() { + super.textFieldPos = new Vector2(109.0, 92.0); + super.initGui(); + (this.textFieldUsername = new GuiTextField(this.fontRendererObj, 52, 18, 90, 12)) + .setMaxStringLength(30); + int x = 0; + int y = 0; + for (int i = 0; i < Permission.getPermissions().length; ++i) { + ++x; + this.buttonList.add(new GuiButtonPress( + i + 1, this.width / 2 - 50 + 20 * x, this.height / 2 - 75 + 20 * y, + new Vector2(18.0, 18 * i), this, + Permission.getPermissions()[i].name)); + if (i % 3 == 0 && i != 0) { + x = 0; + ++y; + } + } + } + + @Override + protected void drawGuiContainerForegroundLayer(final int x, final int y) { + this.fontRendererObj.drawString( + this.tileEntity.getInventoryName(), + this.xSize / 2 - this.fontRendererObj.getStringWidth( + this.tileEntity.getInventoryName()) / + 2, + 6, 4210752); + this.drawTextWithTooltip("rights", "%1", 8, 32, x, y, 0); + try { + if (this.tileEntity.getManipulatingCard() != null) { + final ICardIdentification idCard = (ICardIdentification) this.tileEntity.getManipulatingCard() + .getItem(); + this.textFieldUsername.drawTextBox(); + if (idCard.getUsername(this.tileEntity.getManipulatingCard()) != null) { + for (int i = 0; i < this.buttonList.size(); ++i) { + if (this.buttonList.get(i) instanceof GuiButtonPress) { + final GuiButtonPress button = (GuiButtonPress) this.buttonList.get(i); + button.visible = true; + final int permissionID = i - 1; + if (Permission.getPermission(permissionID) != null) { + if (idCard.hasPermission( + this.tileEntity.getManipulatingCard(), + Permission.getPermission(permissionID))) { + button.stuck = true; + } else { + button.stuck = false; + } + } + } + } + } + } else { + for (final Object button2 : this.buttonList) { + if (button2 instanceof GuiButtonPress) { + ((GuiButtonPress) button2).visible = false; + } + } + } + } catch (final Exception e) { + e.printStackTrace(); + } + super.textFieldFrequency.drawTextBox(); + this.drawTextWithTooltip("master", 28, + 90 + this.fontRendererObj.FONT_HEIGHT / 2, x, y); + super.drawGuiContainerForegroundLayer(x, y); + } + + @Override + public void updateScreen() { + super.updateScreen(); + if (!this.textFieldUsername.isFocused() && + this.tileEntity.getManipulatingCard() != null) { + final ICardIdentification idCard = (ICardIdentification) this.tileEntity.getManipulatingCard().getItem(); + if (idCard.getUsername(this.tileEntity.getManipulatingCard()) != null) { + this.textFieldUsername.setText( + idCard.getUsername(this.tileEntity.getManipulatingCard())); + } + } + } + + @Override + protected void drawGuiContainerBackgroundLayer(final float f, final int x, + final int y) { + super.drawGuiContainerBackgroundLayer(f, x, y); + this.drawSlot(87, 90); + this.drawSlot(7, 45); + this.drawSlot(7, 65); + this.drawSlot(7, 90); + for (int var4 = 0; var4 < 9; ++var4) { + this.drawSlot(8 + var4 * 18 - 1, 110); + } + } + + @Override + protected void keyTyped(final char par1, final int par2) { + if (par1 != 'e' && par1 != 'E') { + super.keyTyped(par1, par2); + } + this.textFieldUsername.textboxKeyTyped(par1, par2); + NBTTagCompound nbt = new NBTTagCompound(); + nbt.setString("username", this.textFieldUsername.getText()); + ModularForceFieldSystem.channel.sendToServer(new PacketTile( + PacketTile.Type.STRING, new Vector3(this.tileEntity), nbt)); + } + + @Override + protected void mouseClicked(final int x, final int y, final int par3) { + super.mouseClicked(x, y, par3); + this.textFieldUsername.mouseClicked(x - super.containerWidth, + y - super.containerHeight, par3); + } + + @Override + protected void actionPerformed(final GuiButton guiButton) { + ModularForceFieldSystem.channel.sendToServer(new PacketTile( + PacketTile.Type.TOGGLE_MODE, new Vector3(this.tileEntity), new NBTTagCompound())); + } +} diff --git a/src/main/java/mffs/gui/GuiCoercionDeriver.java b/src/main/java/mffs/gui/GuiCoercionDeriver.java new file mode 100644 index 0000000..f711794 --- /dev/null +++ b/src/main/java/mffs/gui/GuiCoercionDeriver.java @@ -0,0 +1,110 @@ +package mffs.gui; + +import mffs.ModularForceFieldSystem; +import mffs.base.GuiBase; +import mffs.base.PacketTile; +import mffs.container.ContainerCoercionDeriver; +import mffs.tileentity.TileEntityCoercionDeriver; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.nbt.NBTTagCompound; +import org.lwjgl.opengl.GL11; +import universalelectricity.core.UniversalElectricity; +import universalelectricity.core.electricity.ElectricityDisplay; +import universalelectricity.core.vector.Vector2; +import universalelectricity.core.vector.Vector3; + +public class GuiCoercionDeriver extends GuiBase { + private TileEntityCoercionDeriver tileEntity; + + public GuiCoercionDeriver(final EntityPlayer player, + final TileEntityCoercionDeriver tileentity) { + super(new ContainerCoercionDeriver(player, tileentity), tileentity); + this.tileEntity = tileentity; + } + + @Override + public void initGui() { + super.textFieldPos = new Vector2(30.0, 43.0); + super.initGui(); + this.buttonList.add(new GuiButton(1, this.width / 2 - 10, + this.height / 2 - 28, 58, 20, "Derive")); + } + + @Override + protected void drawGuiContainerForegroundLayer(final int x, final int y) { + this.fontRendererObj.drawString( + this.tileEntity.getInventoryName(), + this.xSize / 2 - this.fontRendererObj.getStringWidth( + this.tileEntity.getInventoryName()) / + 2, + 6, 4210752); + this.drawTextWithTooltip("frequency", "%1:", 8, 30, x, y); + super.textFieldFrequency.drawTextBox(); + GL11.glPushMatrix(); + GL11.glRotatef(-90.0f, 0.0f, 0.0f, 1.0f); + this.drawTextWithTooltip("upgrade", -95, 140, x, y); + GL11.glPopMatrix(); + if (this.buttonList.get(1) instanceof GuiButton) { + if (!this.tileEntity.isInversed) { + ((GuiButton) this.buttonList.get(1)).displayString = "Derive"; + } else { + ((GuiButton) this.buttonList.get(1)).displayString = "Integrate"; + } + } + this.fontRendererObj.drawString( + 1000.0 * UniversalElectricity.TO_BC_RATIO + " MJ/s", 85, 30, 4210752); + this.fontRendererObj.drawString( + 1000.0 * UniversalElectricity.TO_IC2_RATIO + " EU/s", 85, 40, 4210752); + this.fontRendererObj.drawString( + ElectricityDisplay.getDisplayShort( + 1000.0, ElectricityDisplay.ElectricUnit.WATT), + 85, 50, 4210752); + this.fontRendererObj.drawString( + ElectricityDisplay.getDisplayShort( + this.tileEntity.getVoltage(), + ElectricityDisplay.ElectricUnit.VOLTAGE), + 85, 60, 4210752); + this.drawTextWithTooltip( + "progress", "%1: " + (this.tileEntity.isActive() ? "Running" : "Idle"), + 8, 70, x, y); + this.drawTextWithTooltip("fortron", + "%1: " + + ElectricityDisplay.getDisplayShort( + this.tileEntity.getFortronEnergy(), + ElectricityDisplay.ElectricUnit.JOULES), + 8, 105, x, y); + this.fontRendererObj.drawString( + "§2+" + ElectricityDisplay.getDisplayShort( + this.tileEntity.getProductionRate() * 20, + ElectricityDisplay.ElectricUnit.JOULES), + 120, 117, 4210752); + super.drawGuiContainerForegroundLayer(x, y); + } + + @Override + protected void drawGuiContainerBackgroundLayer(final float f, final int x, + final int y) { + super.drawGuiContainerBackgroundLayer(f, x, y); + this.drawSlot(153, 46); + this.drawSlot(153, 66); + this.drawSlot(153, 86); + this.drawSlot(8, 40); + this.drawSlot(8, 82, SlotType.BATTERY); + this.drawSlot(28, 82); + this.drawBar(50, 84, 1.0f); + this.drawForce(8, 115, + this.tileEntity.getFortronEnergy() / + (float) this.tileEntity.getFortronCapacity()); + } + + @Override + protected void actionPerformed(final GuiButton guibutton) { + super.actionPerformed(guibutton); + if (guibutton.id == 1) { + ModularForceFieldSystem.channel.sendToServer( + new PacketTile(PacketTile.Type.TOGGLE_MODE, + new Vector3(this.tileEntity), new NBTTagCompound())); + } + } +} diff --git a/src/main/java/mffs/gui/GuiForceFieldProjector.java b/src/main/java/mffs/gui/GuiForceFieldProjector.java new file mode 100644 index 0000000..7669dd3 --- /dev/null +++ b/src/main/java/mffs/gui/GuiForceFieldProjector.java @@ -0,0 +1,150 @@ +package mffs.gui; + +import mffs.base.GuiBase; +import mffs.container.ContainerForceFieldProjector; +import mffs.tileentity.TileEntityForceFieldProjector; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.world.IBlockAccess; +import org.lwjgl.opengl.GL11; +import universalelectricity.core.electricity.ElectricityDisplay; +import universalelectricity.core.vector.Vector2; +import universalelectricity.prefab.vector.Region2; + +public class GuiForceFieldProjector extends GuiBase { + private TileEntityForceFieldProjector tileEntity; + + public GuiForceFieldProjector(final EntityPlayer player, + final TileEntityForceFieldProjector + tileEntity) { + super(new ContainerForceFieldProjector(player, tileEntity), tileEntity); + this.tileEntity = tileEntity; + } + + @Override + public void initGui() { + super.textFieldPos = new Vector2(48.0, 91.0); + super.initGui(); + super.tooltips.put(new Region2(new Vector2(117.0, 44.0), + new Vector2(117.0, 44.0).add(18.0)), + "Mode"); + super.tooltips.put( + new Region2(new Vector2(90.0, 17.0), new Vector2(90.0, 17.0).add(18.0)), + "Up"); + super.tooltips.put(new Region2(new Vector2(144.0, 17.0), + new Vector2(144.0, 17.0).add(18.0)), + "Up"); + super.tooltips.put( + new Region2(new Vector2(90.0, 71.0), new Vector2(90.0, 71.0).add(18.0)), + "Down"); + super.tooltips.put(new Region2(new Vector2(144.0, 71.0), + new Vector2(144.0, 71.0).add(18.0)), + "Down"); + super.tooltips.put(new Region2(new Vector2(108.0, 17.0), + new Vector2(108.0, 17.0).add(18.0)), + "Front"); + super.tooltips.put(new Region2(new Vector2(126.0, 17.0), + new Vector2(126.0, 17.0).add(18.0)), + "Front"); + super.tooltips.put(new Region2(new Vector2(108.0, 71.0), + new Vector2(108.0, 71.0).add(18.0)), + "Back"); + super.tooltips.put(new Region2(new Vector2(126.0, 71.0), + new Vector2(126.0, 71.0).add(18.0)), + "Back"); + super.tooltips.put(new Region2(new Vector2(90.0, 35.0), + new Vector2(108.0, 35.0).add(18.0)), + "Left"); + super.tooltips.put(new Region2(new Vector2(90.0, 53.0), + new Vector2(108.0, 53.0).add(18.0)), + "Left"); + super.tooltips.put(new Region2(new Vector2(144.0, 35.0), + new Vector2(144.0, 35.0).add(18.0)), + "Right"); + super.tooltips.put(new Region2(new Vector2(144.0, 53.0), + new Vector2(144.0, 53.0).add(18.0)), + "Right"); + } + + @Override + protected void drawGuiContainerForegroundLayer(final int x, final int y) { + this.fontRendererObj.drawString( + this.tileEntity.getInventoryName(), + this.xSize / 2 - this.fontRendererObj.getStringWidth( + this.tileEntity.getInventoryName()) / + 2, + 6, 4210752); + GL11.glPushMatrix(); + GL11.glRotatef(-90.0f, 0.0f, 0.0f, 1.0f); + this.fontRendererObj.drawString( + this.tileEntity + .getDirection((IBlockAccess)this.tileEntity.getWorldObj(), + this.tileEntity.xCoord, this.tileEntity.yCoord, + this.tileEntity.zCoord) + .name(), + -63, 8, 4210752); + GL11.glPopMatrix(); + this.drawTextWithTooltip("matrix", 32, 20, x, y); + this.drawTextWithTooltip("frequency", "%1:", 8, 76, x, y); + super.textFieldFrequency.drawTextBox(); + this.drawTextWithTooltip("fortron", + "%1: " + + ElectricityDisplay.getDisplayShort( + this.tileEntity.getFortronEnergy(), + ElectricityDisplay.ElectricUnit.JOULES) + + "/" + + ElectricityDisplay.getDisplayShort( + this.tileEntity.getFortronCapacity(), + ElectricityDisplay.ElectricUnit.JOULES), + 8, 110, x, y); + this.fontRendererObj.drawString( + "§4-" + ElectricityDisplay.getDisplayShort( + this.tileEntity.getFortronCost() * 20, + ElectricityDisplay.ElectricUnit.JOULES), + 120, 121, 4210752); + super.drawGuiContainerForegroundLayer(x, y); + } + + @Override + protected void drawGuiContainerBackgroundLayer(final float f, final int x, + final int y) { + super.drawGuiContainerBackgroundLayer(f, x, y); + this.drawSlot(9, 88); + this.drawSlot(27, 88); + this.drawSlot(117, 44, SlotType.NONE, 1.0f, 0.4f, 0.4f); + for (int xSlot = 0; xSlot < 4; ++xSlot) { + for (int ySlot = 0; ySlot < 4; ++ySlot) { + if ((xSlot != 1 || ySlot != 1) && (xSlot != 2 || ySlot != 2) && + (xSlot != 1 || ySlot != 2) && (xSlot != 2 || ySlot != 1)) { + SlotType type = SlotType.NONE; + if (xSlot == 0 && ySlot == 0) { + type = SlotType.ARR_UP_LEFT; + } else if (xSlot == 0 && ySlot == 3) { + type = SlotType.ARR_DOWN_LEFT; + } else if (xSlot == 3 && ySlot == 0) { + type = SlotType.ARR_UP_RIGHT; + } else if (xSlot == 3 && ySlot == 3) { + type = SlotType.ARR_DOWN_RIGHT; + } else if (ySlot == 0) { + type = SlotType.ARR_UP; + } else if (ySlot == 3) { + type = SlotType.ARR_DOWN; + } else if (xSlot == 0) { + type = SlotType.ARR_LEFT; + } else if (xSlot == 3) { + type = SlotType.ARR_RIGHT; + } + this.drawSlot(90 + 18 * xSlot, 17 + 18 * ySlot, type); + } + } + } + for (int xSlot = 0; xSlot < 3; ++xSlot) { + for (int ySlot = 0; ySlot < 2; ++ySlot) { + this.drawSlot(18 + 18 * xSlot, 35 + 18 * ySlot); + } + } + this.drawForce(8, 120, + Math.min(this.tileEntity.getFortronEnergy() / + (float)this.tileEntity.getFortronCapacity(), + 1.0f)); + } +} diff --git a/src/main/java/mffs/gui/GuiForceManipulator.java b/src/main/java/mffs/gui/GuiForceManipulator.java new file mode 100644 index 0000000..519cf92 --- /dev/null +++ b/src/main/java/mffs/gui/GuiForceManipulator.java @@ -0,0 +1,194 @@ +package mffs.gui; + +import mffs.ModularForceFieldSystem; +import mffs.base.GuiBase; +import mffs.base.PacketTile; +import mffs.container.ContainerForceManipulator; +import mffs.gui.button.GuiIcon; +import mffs.tileentity.TileEntityForceManipulator; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Blocks; +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.IBlockAccess; +import org.lwjgl.opengl.GL11; +import universalelectricity.core.electricity.ElectricityDisplay; +import universalelectricity.core.vector.Vector2; +import universalelectricity.core.vector.Vector3; +import universalelectricity.prefab.vector.Region2; + +public class GuiForceManipulator extends GuiBase { + private TileEntityForceManipulator tileEntity; + + public GuiForceManipulator(final EntityPlayer player, + final TileEntityForceManipulator tileEntity) { + super(new ContainerForceManipulator(player, tileEntity), tileEntity); + this.tileEntity = tileEntity; + } + + @Override + public void initGui() { + super.textFieldPos = new Vector2(111.0, 93.0); + super.initGui(); + this.buttonList.add(new GuiButton(1, this.width / 2 - 60, + this.height / 2 - 22, 40, 20, "Reset")); + this.buttonList.add( + new GuiIcon(2, this.width / 2 - 82, this.height / 2 - 82, + new ItemStack[] { null, new ItemStack(Items.redstone), + new ItemStack(Blocks.redstone_block) })); + this.buttonList.add( + new GuiIcon(3, this.width / 2 - 82, this.height / 2 - 60, + new ItemStack[] { null, new ItemStack(Blocks.anvil) })); + super.tooltips.put(new Region2(new Vector2(117.0, 44.0), + new Vector2(117.0, 44.0).add(18.0)), + "Mode"); + super.tooltips.put( + new Region2(new Vector2(90.0, 17.0), new Vector2(90.0, 17.0).add(18.0)), + "Up"); + super.tooltips.put(new Region2(new Vector2(144.0, 17.0), + new Vector2(144.0, 17.0).add(18.0)), + "Up"); + super.tooltips.put( + new Region2(new Vector2(90.0, 71.0), new Vector2(90.0, 71.0).add(18.0)), + "Down"); + super.tooltips.put(new Region2(new Vector2(144.0, 71.0), + new Vector2(144.0, 71.0).add(18.0)), + "Down"); + super.tooltips.put(new Region2(new Vector2(108.0, 17.0), + new Vector2(108.0, 17.0).add(18.0)), + "Front"); + super.tooltips.put(new Region2(new Vector2(126.0, 17.0), + new Vector2(126.0, 17.0).add(18.0)), + "Front"); + super.tooltips.put(new Region2(new Vector2(108.0, 71.0), + new Vector2(108.0, 71.0).add(18.0)), + "Back"); + super.tooltips.put(new Region2(new Vector2(126.0, 71.0), + new Vector2(126.0, 71.0).add(18.0)), + "Back"); + super.tooltips.put(new Region2(new Vector2(90.0, 35.0), + new Vector2(108.0, 35.0).add(18.0)), + "Left"); + super.tooltips.put(new Region2(new Vector2(90.0, 53.0), + new Vector2(108.0, 53.0).add(18.0)), + "Left"); + super.tooltips.put(new Region2(new Vector2(144.0, 35.0), + new Vector2(144.0, 35.0).add(18.0)), + "Right"); + super.tooltips.put(new Region2(new Vector2(144.0, 53.0), + new Vector2(144.0, 53.0).add(18.0)), + "Right"); + } + + @Override + protected void drawGuiContainerForegroundLayer(final int x, final int y) { + this.fontRendererObj.drawString( + this.tileEntity.getInventoryName(), + this.xSize / 2 - this.fontRendererObj.getStringWidth( + this.tileEntity.getInventoryName()) / + 2, + 6, 4210752); + GL11.glPushMatrix(); + GL11.glRotatef(-90.0f, 0.0f, 0.0f, 1.0f); + this.fontRendererObj.drawString( + this.tileEntity + .getDirection((IBlockAccess) this.tileEntity.getWorldObj(), + this.tileEntity.xCoord, this.tileEntity.yCoord, + this.tileEntity.zCoord) + .name(), + -100, 10, 4210752); + GL11.glPopMatrix(); + this.fontRendererObj.drawString("Anchor:", 30, 60, 4210752); + if (this.tileEntity.anchor != null) { + this.fontRendererObj.drawString(this.tileEntity.anchor.intX() + ", " + + this.tileEntity.anchor.intY() + ", " + + this.tileEntity.anchor.intZ(), + 30, 72, 4210752); + } + super.textFieldFrequency.drawTextBox(); + this.drawTextWithTooltip("fortron", + "%1: " + + ElectricityDisplay.getDisplayShort( + this.tileEntity.getFortronEnergy(), + ElectricityDisplay.ElectricUnit.JOULES) + + + "/" + + ElectricityDisplay.getDisplayShort( + this.tileEntity.getFortronCapacity(), + ElectricityDisplay.ElectricUnit.JOULES), + 8, 110, x, y); + this.fontRendererObj.drawString( + "§4-" + ElectricityDisplay.getDisplayShort( + this.tileEntity.getFortronCost(), + ElectricityDisplay.ElectricUnit.JOULES), + 120, 121, 4210752); + super.drawGuiContainerForegroundLayer(x, y); + } + + @Override + public void updateScreen() { + super.updateScreen(); + ((GuiIcon) this.buttonList.get(2)).setIndex(this.tileEntity.displayMode); + ((GuiIcon) this.buttonList.get(3)) + .setIndex(this.tileEntity.doAnchor ? 1 : 0); + } + + @Override + protected void drawGuiContainerBackgroundLayer(final float f, final int x, + final int y) { + super.drawGuiContainerBackgroundLayer(f, x, y); + this.drawSlot(72, 90); + this.drawSlot(90, 90); + this.drawSlot(117, 44, SlotType.NONE, 1.0f, 0.4f, 0.4f); + for (int xSlot = 0; xSlot < 4; ++xSlot) { + for (int ySlot = 0; ySlot < 4; ++ySlot) { + if ((xSlot != 1 || ySlot != 1) && (xSlot != 2 || ySlot != 2) && + (xSlot != 1 || ySlot != 2) && (xSlot != 2 || ySlot != 1)) { + SlotType type = SlotType.NONE; + if (xSlot == 0 && ySlot == 0) { + type = SlotType.ARR_UP_LEFT; + } else if (xSlot == 0 && ySlot == 3) { + type = SlotType.ARR_DOWN_LEFT; + } else if (xSlot == 3 && ySlot == 0) { + type = SlotType.ARR_UP_RIGHT; + } else if (xSlot == 3 && ySlot == 3) { + type = SlotType.ARR_DOWN_RIGHT; + } else if (ySlot == 0) { + type = SlotType.ARR_UP; + } else if (ySlot == 3) { + type = SlotType.ARR_DOWN; + } else if (xSlot == 0) { + type = SlotType.ARR_LEFT; + } else if (xSlot == 3) { + type = SlotType.ARR_RIGHT; + } + this.drawSlot(90 + 18 * xSlot, 17 + 18 * ySlot, type); + } + } + } + for (int xSlot = 0; xSlot < 3; ++xSlot) { + for (int ySlot = 0; ySlot < 2; ++ySlot) { + this.drawSlot(30 + 18 * xSlot, 18 + 18 * ySlot); + } + } + this.drawForce(8, 120, + Math.min(this.tileEntity.getFortronEnergy() / + (float) this.tileEntity.getFortronCapacity(), + 1.0f)); + } + + @Override + protected void actionPerformed(final GuiButton guiButton) { + super.actionPerformed(guiButton); + + NBTTagCompound nbt = new NBTTagCompound(); + nbt.setInteger("buttonId", guiButton.id); + + if (guiButton.id == 1 || guiButton.id == 2 || guiButton.id == 3) { + ModularForceFieldSystem.channel.sendToServer(new PacketTile( + PacketTile.Type.TOGGLE_MODE, new Vector3(this.tileEntity), nbt)); + } + } +} diff --git a/src/main/java/mffs/gui/GuiFortronCapacitor.java b/src/main/java/mffs/gui/GuiFortronCapacitor.java new file mode 100644 index 0000000..c7a8723 --- /dev/null +++ b/src/main/java/mffs/gui/GuiFortronCapacitor.java @@ -0,0 +1,96 @@ +package mffs.gui; + +import mffs.ModularForceFieldSystem; +import mffs.base.GuiBase; +import mffs.base.PacketTile; +import mffs.container.ContainerFortronCapacitor; +import mffs.gui.button.GuiButtonPressTransferMode; +import mffs.tileentity.TileEntityFortronCapacitor; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.nbt.NBTTagCompound; +import org.lwjgl.opengl.GL11; +import universalelectricity.core.electricity.ElectricityDisplay; +import universalelectricity.core.vector.Vector2; +import universalelectricity.core.vector.Vector3; + +public class GuiFortronCapacitor extends GuiBase { + private TileEntityFortronCapacitor tileEntity; + + public GuiFortronCapacitor(final EntityPlayer player, + final TileEntityFortronCapacitor tileentity) { + super(new ContainerFortronCapacitor(player, tileentity), tileentity); + this.tileEntity = tileentity; + } + + @Override + public void initGui() { + super.textFieldPos = new Vector2(50.0, 76.0); + super.initGui(); + this.buttonList.add(new GuiButtonPressTransferMode( + 1, this.width / 2 + 15, this.height / 2 - 37, this, this.tileEntity)); + } + + @Override + protected void drawGuiContainerForegroundLayer(final int x, final int y) { + this.fontRendererObj.drawString( + this.tileEntity.getInventoryName(), + this.xSize / 2 - this.fontRendererObj.getStringWidth( + this.tileEntity.getInventoryName()) / + 2, + 6, 4210752); + GL11.glPushMatrix(); + GL11.glRotatef(-90.0f, 0.0f, 0.0f, 1.0f); + this.drawTextWithTooltip("upgrade", -95, 140, x, y); + GL11.glPopMatrix(); + this.drawTextWithTooltip("linkedDevice", + "%1: " + this.tileEntity.getLinkedDevices().size(), + 8, 28, x, y); + this.drawTextWithTooltip("transmissionRate", + "%1: " + + ElectricityDisplay.getDisplayShort( + this.tileEntity.getTransmissionRate(), + ElectricityDisplay.ElectricUnit.JOULES), + 8, 40, x, y); + this.drawTextWithTooltip( + "range", "%1: " + this.tileEntity.getTransmissionRange(), 8, 52, x, y); + this.drawTextWithTooltip("frequency", "%1:", 8, 63, x, y); + super.textFieldFrequency.drawTextBox(); + this.drawTextWithTooltip("fortron", "%1:", 8, 95, x, y); + this.fontRendererObj.drawString( + ElectricityDisplay.getDisplayShort( + this.tileEntity.getFortronEnergy(), + ElectricityDisplay.ElectricUnit.JOULES) + + "/" + + ElectricityDisplay.getDisplayShort( + this.tileEntity.getFortronCapacity(), + ElectricityDisplay.ElectricUnit.JOULES), + 8, 105, 4210752); + super.drawGuiContainerForegroundLayer(x, y); + } + + @Override + protected void drawGuiContainerBackgroundLayer(final float f, final int x, + final int y) { + super.drawGuiContainerBackgroundLayer(f, x, y); + this.drawSlot(153, 46); + this.drawSlot(153, 66); + this.drawSlot(153, 86); + this.drawSlot(8, 73); + this.drawSlot(26, 73); + this.drawForce(8, 115, + Math.min(this.tileEntity.getFortronEnergy() / + (float)this.tileEntity.getFortronCapacity(), + 1.0f)); + } + + @Override + protected void actionPerformed(final GuiButton guibutton) { + super.actionPerformed(guibutton); + if (guibutton.id == 1) { + ModularForceFieldSystem.channel.sendToServer( + new PacketTile(PacketTile.Type.TOGGLE_MODE, + new Vector3(this.tileEntity), new NBTTagCompound())); + } + } +} diff --git a/src/main/java/mffs/gui/GuiInterdictionMatrix.java b/src/main/java/mffs/gui/GuiInterdictionMatrix.java new file mode 100644 index 0000000..f6b86b4 --- /dev/null +++ b/src/main/java/mffs/gui/GuiInterdictionMatrix.java @@ -0,0 +1,105 @@ +package mffs.gui; + +import mffs.ModularForceFieldSystem; +import mffs.base.GuiBase; +import mffs.base.PacketTile; +import mffs.container.ContainerInterdictionMatrix; +import mffs.tileentity.TileEntityInterdictionMatrix; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.nbt.NBTTagCompound; +import universalelectricity.core.electricity.ElectricityDisplay; +import universalelectricity.core.vector.Vector2; +import universalelectricity.core.vector.Vector3; + +public class GuiInterdictionMatrix extends GuiBase { + private TileEntityInterdictionMatrix tileEntity; + + public GuiInterdictionMatrix(final EntityPlayer player, + final TileEntityInterdictionMatrix tileEntity) { + super(new ContainerInterdictionMatrix(player, tileEntity), tileEntity); + this.tileEntity = tileEntity; + } + + @Override + public void initGui() { + super.textFieldPos = new Vector2(110.0, 91.0); + super.initGui(); + this.buttonList.add(new GuiButton(1, this.width / 2 - 80, + this.height / 2 - 65, 50, 20, "Banned")); + } + + @Override + protected void actionPerformed(final GuiButton guiButton) { + super.actionPerformed(guiButton); + if (guiButton.id == 1) { + ModularForceFieldSystem.channel.sendToServer( + new PacketTile(PacketTile.Type.TOGGLE_MODE, + new Vector3(this.tileEntity), new NBTTagCompound())); + } + } + + @Override + protected void drawGuiContainerForegroundLayer(final int x, final int y) { + this.fontRendererObj.drawString( + this.tileEntity.getInventoryName(), + this.xSize / 2 - this.fontRendererObj.getStringWidth( + this.tileEntity.getInventoryName()) / + 2, + 6, 4210752); + this.drawTextWithTooltip("warn", "%1: " + this.tileEntity.getWarningRange(), + 35, 19, x, y); + this.drawTextWithTooltip( + "action", "%1: " + this.tileEntity.getActionRange(), 100, 19, x, y); + this.drawTextWithTooltip("filterMode", "%1:", 9, 32, x, y); + if (!this.tileEntity.isBanMode()) { + if (this.buttonList.get(1) instanceof GuiButton) { + ((GuiButton)this.buttonList.get(1)).displayString = "Allowed"; + } + } else if (this.buttonList.get(1) instanceof GuiButton) { + ((GuiButton)this.buttonList.get(1)).displayString = "Banned"; + } + this.drawTextWithTooltip("frequency", "%1:", 8, 93, x, y); + super.textFieldFrequency.drawTextBox(); + this.drawTextWithTooltip("fortron", + "%1: " + + ElectricityDisplay.getDisplayShort( + this.tileEntity.getFortronEnergy(), + ElectricityDisplay.ElectricUnit.JOULES) + + "/" + + ElectricityDisplay.getDisplayShort( + this.tileEntity.getFortronCapacity(), + ElectricityDisplay.ElectricUnit.JOULES), + 8, 110, x, y); + this.fontRendererObj.drawString( + "§4-" + ElectricityDisplay.getDisplayShort( + this.tileEntity.getFortronCost() * 20, + ElectricityDisplay.ElectricUnit.JOULES), + 120, 121, 4210752); + super.drawGuiContainerForegroundLayer(x, y); + } + + @Override + protected void drawGuiContainerBackgroundLayer(final float var1, final int x, + final int y) { + super.drawGuiContainerBackgroundLayer(var1, x, y); + for (int var2 = 0; var2 < 2; ++var2) { + for (int var3 = 0; var3 < 4; ++var3) { + this.drawSlot(98 + var3 * 18, 30 + var2 * 18); + } + } + for (int var4 = 0; var4 < 9; ++var4) { + if (this.tileEntity.isBanMode()) { + this.drawSlot(8 + var4 * 18, 68, SlotType.NONE, 1.0f, 0.8f, 0.8f); + } else { + this.drawSlot(8 + var4 * 18, 68, SlotType.NONE, 0.8f, 1.0f, 0.8f); + } + } + this.drawSlot(68, 88); + this.drawSlot(86, 88); + this.drawForce(8, 120, + Math.min(this.tileEntity.getFortronEnergy() / + (float)this.tileEntity.getFortronCapacity(), + 1.0f)); + } +} diff --git a/src/main/java/mffs/gui/button/GuiButtonPress.java b/src/main/java/mffs/gui/button/GuiButtonPress.java new file mode 100644 index 0000000..3bfa4e8 --- /dev/null +++ b/src/main/java/mffs/gui/button/GuiButtonPress.java @@ -0,0 +1,89 @@ +// +// Decompiled by Procyon v0.6.0 +// + +package mffs.gui.button; + +import mffs.base.GuiBase; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.util.ResourceLocation; +import org.lwjgl.opengl.GL11; +import universalelectricity.core.vector.Vector2; +import universalelectricity.prefab.TranslationHelper; + +public class GuiButtonPress extends GuiButton { + protected Vector2 offset; + public boolean stuck; + private GuiBase mainGui; + + public GuiButtonPress(final int id, final int x, final int y, + final Vector2 offset, final GuiBase mainGui, + final String name) { + super(id, x, y, 18, 18, name); + this.offset = new Vector2(); + this.stuck = false; + this.offset = offset; + this.mainGui = mainGui; + } + + public GuiButtonPress(final int id, final int x, final int y, + final Vector2 offset, final GuiBase mainGui) { + this(id, x, y, offset, mainGui, ""); + } + + public GuiButtonPress(final int id, final int x, final int y, + final Vector2 offset) { + this(id, x, y, offset, null, ""); + } + + public GuiButtonPress(final int id, final int x, final int y) { + this(id, x, y, new Vector2()); + } + + @Override + public void drawButton(final Minecraft minecraft, final int x, + final int y) { + if (this.visible) { + Minecraft.getMinecraft().renderEngine.bindTexture( + new ResourceLocation("mffs", "textures/gui/gui_button.png")); + if (this.stuck) { + GL11.glColor4f(0.6f, 0.6f, 0.6f, 1.0f); + } else if (this.isPointInRegion(this.xPosition, this.yPosition, + this.width, this.height, x, y)) { + GL11.glColor4f(0.85f, 0.85f, 0.85f, 1.0f); + } else { + GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + } + this.drawTexturedModalRect(this.xPosition, this.yPosition, + this.offset.intX(), this.offset.intY(), + this.width, this.height); + this.mouseDragged(minecraft, x, y); + } + } + + @Override + protected void mouseDragged(final Minecraft minecraft, final int x, + final int y) { + if (this.mainGui != null && this.displayString != null && + this.displayString.length() > 0 && + this.isPointInRegion(this.xPosition, this.yPosition, this.width, + this.height, x, y)) { + final String title = TranslationHelper.getLocal("gui." + this.displayString + ".name"); + this.mainGui.tooltip = TranslationHelper.getLocal("gui." + this.displayString + ".tooltip"); + if (title != null && title.length() > 0) { + this.mainGui.tooltip = title + ": " + this.mainGui.tooltip; + } + } + } + + protected boolean isPointInRegion(final int x, final int y, final int width, + final int height, int checkX, int checkY) { + final int var7 = 0; + final int var8 = 0; + checkX -= var7; + checkY -= var8; + return checkX >= x - 1 && checkX < x + width + 1 && checkY >= y - 1 && + checkY < y + height + 1; + } +} diff --git a/src/main/java/mffs/gui/button/GuiButtonPressTransferMode.java b/src/main/java/mffs/gui/button/GuiButtonPressTransferMode.java new file mode 100644 index 0000000..cdd5159 --- /dev/null +++ b/src/main/java/mffs/gui/button/GuiButtonPressTransferMode.java @@ -0,0 +1,30 @@ +// +// Decompiled by Procyon v0.6.0 +// + +package mffs.gui.button; + +import net.minecraft.client.Minecraft; +import universalelectricity.core.vector.Vector2; +import mffs.base.GuiBase; +import mffs.tileentity.TileEntityFortronCapacitor; + +public class GuiButtonPressTransferMode extends GuiButtonPress +{ + private TileEntityFortronCapacitor tileEntity; + + public GuiButtonPressTransferMode(final int id, final int x, final int y, final GuiBase mainGui, final TileEntityFortronCapacitor tileEntity) { + super(id, x, y, new Vector2(), mainGui); + this.tileEntity = tileEntity; + } + + @Override + public void drawButton(final Minecraft minecraft, final int x, final int y) { + String transferName = this.tileEntity.getTransferMode().name().toLowerCase(); + final char first = Character.toUpperCase(transferName.charAt(0)); + transferName = first + transferName.substring(1); + this.displayString = "transferMode" + transferName; + super.offset.y = 18 * this.tileEntity.getTransferMode().ordinal(); + super.drawButton(minecraft, x, y); + } +} diff --git a/src/main/java/mffs/gui/button/GuiIcon.java b/src/main/java/mffs/gui/button/GuiIcon.java new file mode 100644 index 0000000..9be5951 --- /dev/null +++ b/src/main/java/mffs/gui/button/GuiIcon.java @@ -0,0 +1,70 @@ +package mffs.gui.button; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.client.renderer.entity.RenderItem; +import net.minecraft.init.Blocks; +import net.minecraft.item.Item; +import net.minecraft.item.ItemBlock; +import net.minecraft.item.ItemStack; +import org.lwjgl.opengl.GL11; + +public class GuiIcon extends GuiButton { + public static RenderItem itemRenderer; + public ItemStack[] itemStacks; + private int index; + + public GuiIcon(final int par1, final int par2, final int par3, + final ItemStack... itemStacks) { + super(par1, par2, par3, 20, 20, ""); + this.index = 0; + this.itemStacks = itemStacks; + } + + public void setIndex(final int i) { + if (i >= 0 && i < this.itemStacks.length) { + this.index = i; + } + } + + @Override + public void drawButton(final Minecraft par1Minecraft, final int par2, + final int par3) { + super.drawButton(par1Minecraft, par2, par3); + if (this.visible && this.itemStacks[this.index] != null) { + int yDisplacement = 2; + if (this.itemStacks[this.index].getItem() == Item.getItemFromBlock(Blocks.torch) || + this.itemStacks[this.index].getItem() == Item.getItemFromBlock(Blocks.redstone_torch)) { + yDisplacement = 0; + } else if (this.itemStacks[this.index].getItem() instanceof ItemBlock) { + yDisplacement = 3; + } + this.drawItemStack(this.itemStacks[this.index], this.xPosition, + this.yPosition + yDisplacement); + } + } + + protected void drawItemStack(final ItemStack itemStack, int x, int y) { + x += 2; + --y; + final Minecraft mc = Minecraft.getMinecraft(); + final FontRenderer fontRenderer = mc.fontRenderer; + RenderHelper.enableGUIStandardItemLighting(); + GL11.glTranslatef(0.0f, 0.0f, 32.0f); + this.zLevel = 500.0f; + GuiIcon.itemRenderer.zLevel = 500.0f; + GuiIcon.itemRenderer.renderItemAndEffectIntoGUI( + fontRenderer, mc.renderEngine, itemStack, x, y); + GuiIcon.itemRenderer.renderItemOverlayIntoGUI(fontRenderer, mc.renderEngine, + itemStack, x, y); + this.zLevel = 0.0f; + GuiIcon.itemRenderer.zLevel = 0.0f; + RenderHelper.disableStandardItemLighting(); + } + + static { + GuiIcon.itemRenderer = new RenderItem(); + } +} diff --git a/src/main/java/mffs/item/ItemRemoteController.java b/src/main/java/mffs/item/ItemRemoteController.java new file mode 100644 index 0000000..caca7c0 --- /dev/null +++ b/src/main/java/mffs/item/ItemRemoteController.java @@ -0,0 +1,145 @@ +package mffs.item; + +import java.util.List; +import java.util.Set; +import mffs.MFFSHelper; +import mffs.ModularForceFieldSystem; +import mffs.api.card.ICardLink; +import mffs.api.fortron.IFortronFrequency; +import mffs.api.security.Permission; +import mffs.fortron.FrequencyGrid; +import mffs.item.card.ItemCardFrequency; +import net.minecraft.block.Block; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ChatComponentText; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; +import net.minecraftforge.event.entity.player.PlayerInteractEvent; +import universalelectricity.core.electricity.ElectricityDisplay; +import universalelectricity.core.vector.Vector3; + +public class ItemRemoteController + extends ItemCardFrequency implements ICardLink { + public ItemRemoteController() { super("remoteController"); } + + @Override + public void addInformation(final ItemStack itemStack, + final EntityPlayer player, final List list, + final boolean b) { + super.addInformation(itemStack, player, list, b); + final Vector3 position = this.getLink(itemStack); + if (position != null) { + final Block blockId = position.getBlock(player.worldObj); + if (blockId != null) { + list.add("Linked with: " + blockId.getLocalizedName()); + list.add(position.intX() + ", " + position.intY() + ", " + + position.intZ()); + return; + } + } + list.add("Not linked."); + } + + @Override + public boolean onItemUse(final ItemStack itemStack, final EntityPlayer player, + final World world, final int x, final int y, + final int z, final int side, final float hitX, + final float hitY, final float hitZ) { + if (player.isSneaking()) { + if (!world.isRemote) { + final Vector3 vector = new Vector3(x, y, z); + this.setLink(itemStack, vector); + if (vector.getBlock((IBlockAccess)world) != null) { + player.addChatMessage(new ChatComponentText( + "Linked remote to position: " + x + ", " + y + ", " + z + + " with block: " + vector.getBlock(world).getLocalizedName())); + } + } + return true; + } + return false; + } + + @Override + public ItemStack onItemRightClick(final ItemStack itemStack, + final World world, + final EntityPlayer entityPlayer) { + if (!entityPlayer.isSneaking()) { + final Vector3 position = this.getLink(itemStack); + if (position != null) { + final Block blockId = position.getBlock(world); + if (blockId != null) { + final Chunk chunk = + world.getChunkFromBlockCoords(position.intX(), position.intZ()); + if (chunk != null && chunk.isChunkLoaded && + (MFFSHelper.hasPermission( + world, position, + PlayerInteractEvent.Action.RIGHT_CLICK_BLOCK, + entityPlayer) || + MFFSHelper.hasPermission( + world, position, Permission.REMOTE_CONTROL, entityPlayer))) { + final double requiredEnergy = + Vector3.distance(new Vector3((Entity)entityPlayer), position) * + 10.0; + int receivedEnergy = 0; + final Set fortronTiles = + FrequencyGrid.instance().getFortronTiles( + world, new Vector3((Entity)entityPlayer), 50, + this.getFrequency(itemStack)); + for (final IFortronFrequency fortronTile : fortronTiles) { + final int consumedEnergy = fortronTile.requestFortron( + (int)Math.ceil(requiredEnergy / fortronTiles.size()), true); + if (consumedEnergy > 0) { + if (world.isRemote) { + ModularForceFieldSystem.proxy.renderBeam( + world, + new Vector3((Entity)entityPlayer) + .add(new Vector3( + 0.0, entityPlayer.getEyeHeight() - 0.2, 0.0)), + new Vector3((TileEntity)fortronTile).add(0.5), 0.6f, 0.6f, + 1.0f, 20); + } + receivedEnergy += consumedEnergy; + } + if (receivedEnergy >= requiredEnergy) { + try { + blockId.onBlockActivated(world, position.intX(), + position.intY(), position.intZ(), + entityPlayer, 0, 0.0f, 0.0f, 0.0f); + } catch (final Exception e) { + e.printStackTrace(); + } + return itemStack; + } + } + if (!world.isRemote) { + entityPlayer.addChatMessage(new ChatComponentText( + "Unable to harness " + + ElectricityDisplay.getDisplay( + requiredEnergy, ElectricityDisplay.ElectricUnit.JOULES) + + " from the Fortron field.")); + } + } + } + } + } + return itemStack; + } + + @Override + public void setLink(final ItemStack itemStack, final Vector3 position) { + final NBTTagCompound nbt = MFFSHelper.getNBTTagCompound(itemStack); + nbt.setTag("position", position.writeToNBT(new NBTTagCompound())); + } + + @Override + public Vector3 getLink(final ItemStack itemStack) { + final NBTTagCompound nbt = MFFSHelper.getNBTTagCompound(itemStack); + return Vector3.readFromNBT(nbt.getCompoundTag("position")); + } +} diff --git a/src/main/java/mffs/item/card/ItemCardFrequency.java b/src/main/java/mffs/item/card/ItemCardFrequency.java new file mode 100644 index 0000000..598c5fb --- /dev/null +++ b/src/main/java/mffs/item/card/ItemCardFrequency.java @@ -0,0 +1,77 @@ +package mffs.item.card; + +import icbm.api.IItemFrequency; +import java.util.List; +import mffs.base.TileEntityFrequency; +import mffs.card.ItemCard; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ChatComponentText; +import net.minecraft.world.World; + +public class ItemCardFrequency extends ItemCard implements IItemFrequency { + public ItemCardFrequency(final String name) { super(name); } + + public ItemCardFrequency() { this("cardFrequency"); } + + @Override + public void addInformation(final ItemStack itemStack, + final EntityPlayer par2EntityPlayer, + final List list, final boolean par4) { + list.add("Frequency: " + this.getFrequency(itemStack)); + } + + @Override + public int getFrequency(final ItemStack itemStack) { + if (itemStack != null) { + if (itemStack.getTagCompound() == null) { + itemStack.setTagCompound(new NBTTagCompound()); + } + return itemStack.getTagCompound().getInteger("frequency"); + } + return 0; + } + + @Override + public void setFrequency(final int frequency, final ItemStack itemStack) { + if (itemStack != null) { + if (itemStack.getTagCompound() == null) { + itemStack.setTagCompound(new NBTTagCompound()); + } + itemStack.getTagCompound().setInteger("frequency", frequency); + } + } + + @Override + public ItemStack onItemRightClick(final ItemStack itemStack, + final World world, + final EntityPlayer player) { + if (!world.isRemote && player.isSneaking()) { + this.setFrequency(world.rand.nextInt(15), itemStack); + player.addChatMessage(new ChatComponentText( + "Generated random frequency: " + this.getFrequency(itemStack))); + } + return itemStack; + } + + @Override + public boolean onItemUse(final ItemStack itemStack, final EntityPlayer player, + final World world, final int x, final int y, + final int z, final int side, final float hitX, + final float hitY, final float hitZ) { + final TileEntity tileEntity = world.getTileEntity(x, y, z); + if (tileEntity instanceof TileEntityFrequency) { + if (!world.isRemote) { + ((TileEntityFrequency)tileEntity) + .setFrequency(this.getFrequency(itemStack)); + world.markBlockForUpdate(x, y, z); + player.addChatMessage(new ChatComponentText( + "Frequency set to: " + this.getFrequency(itemStack))); + } + return true; + } + return false; + } +} diff --git a/src/main/java/mffs/item/card/ItemCardID.java b/src/main/java/mffs/item/card/ItemCardID.java new file mode 100644 index 0000000..32dbd03 --- /dev/null +++ b/src/main/java/mffs/item/card/ItemCardID.java @@ -0,0 +1,106 @@ +package mffs.item.card; + +import java.util.List; +import mffs.MFFSHelper; +import mffs.api.card.ICardIdentification; +import mffs.api.security.Permission; +import mffs.card.ItemCard; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.world.World; +import universalelectricity.prefab.TranslationHelper; + +public class ItemCardID extends ItemCard implements ICardIdentification { + + public ItemCardID() { super("cardIdentification"); } + + public ItemCardID(final String name) { super(name); } + + @Override + public boolean hitEntity(final ItemStack itemStack, + final EntityLivingBase entityLiving, + final EntityLivingBase par3EntityLiving) { + if (entityLiving instanceof EntityPlayer) { + this.setUsername(itemStack, + ((EntityPlayer)entityLiving).getDisplayName()); + } + return false; + } + + @Override + public void addInformation(final ItemStack itemStack, + final EntityPlayer player, final List info, + final boolean b) { + if (this.getUsername(itemStack) != null && + !this.getUsername(itemStack).isEmpty()) { + info.add("Username: " + this.getUsername(itemStack)); + } else { + info.add("Unidentified"); + } + String tooltip = ""; + boolean isFirst = true; + for (final Permission permission : Permission.getPermissions()) { + if (this.hasPermission(itemStack, permission)) { + if (!isFirst) { + tooltip += ", "; + } + isFirst = false; + tooltip += + TranslationHelper.getLocal("gui." + permission.name + ".name"); + } + } + if (tooltip != null && tooltip.length() > 0) { + info.addAll(MFFSHelper.splitStringPerWord(tooltip, 5)); + } + } + + @Override + public ItemStack onItemRightClick(final ItemStack itemStack, + final World par2World, + final EntityPlayer entityPlayer) { + this.setUsername(itemStack, entityPlayer.getDisplayName()); + return itemStack; + } + + @Override + public void setUsername(final ItemStack itemStack, final String username) { + final NBTTagCompound nbtTagCompound = + MFFSHelper.getNBTTagCompound(itemStack); + nbtTagCompound.setString("name", username); + } + + @Override + public String getUsername(final ItemStack itemStack) { + final NBTTagCompound nbtTagCompound = + MFFSHelper.getNBTTagCompound(itemStack); + if (nbtTagCompound != null && nbtTagCompound.getString("name") != "") { + return nbtTagCompound.getString("name"); + } + return null; + } + + @Override + public boolean hasPermission(final ItemStack itemStack, + final Permission permission) { + final NBTTagCompound nbt = MFFSHelper.getNBTTagCompound(itemStack); + return nbt.getBoolean("mffs_permission_" + permission.id); + } + + @Override + public boolean addPermission(final ItemStack itemStack, + final Permission permission) { + final NBTTagCompound nbt = MFFSHelper.getNBTTagCompound(itemStack); + nbt.setBoolean("mffs_permission_" + permission.id, true); + return false; + } + + @Override + public boolean removePermission(final ItemStack itemStack, + final Permission permission) { + final NBTTagCompound nbt = MFFSHelper.getNBTTagCompound(itemStack); + nbt.setBoolean("mffs_permission_" + permission.id, false); + return false; + } +} diff --git a/src/main/java/mffs/item/card/ItemCardInfinite.java b/src/main/java/mffs/item/card/ItemCardInfinite.java new file mode 100644 index 0000000..14f3fed --- /dev/null +++ b/src/main/java/mffs/item/card/ItemCardInfinite.java @@ -0,0 +1,8 @@ +package mffs.item.card; + +import mffs.api.card.ICardInfinite; +import mffs.card.ItemCard; + +public class ItemCardInfinite extends ItemCard implements ICardInfinite { + public ItemCardInfinite() { super("cardInfinite"); } +} diff --git a/src/main/java/mffs/item/card/ItemCardLink.java b/src/main/java/mffs/item/card/ItemCardLink.java new file mode 100644 index 0000000..a9b8b5c --- /dev/null +++ b/src/main/java/mffs/item/card/ItemCardLink.java @@ -0,0 +1,66 @@ +package mffs.item.card; + +import java.util.List; +import mffs.MFFSHelper; +import mffs.api.card.ICardLink; +import mffs.card.ItemCard; +import net.minecraft.block.Block; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.util.ChatComponentText; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; +import universalelectricity.core.vector.Vector3; + +public class ItemCardLink extends ItemCard implements ICardLink { + public ItemCardLink() { super("cardLink"); } + + @Override + public void addInformation(final ItemStack itemStack, + final EntityPlayer player, final List list, + final boolean b) { + final Vector3 position = this.getLink(itemStack); + if (position != null) { + final Block blockId = + position.getBlock((IBlockAccess)((Entity)player).worldObj); + if (blockId != null) { + list.add("Linked with: " + blockId.getLocalizedName()); + list.add(position.intX() + ", " + position.intY() + ", " + + position.intZ()); + return; + } + } + list.add("Not linked."); + } + + public boolean onItemUse(final ItemStack itemStack, final EntityPlayer player, + final World world, final int x, final int y, + final int z, final int par7, final float par8, + final float par9, final float par10) { + if (!world.isRemote) { + final Vector3 vector = new Vector3(x, y, z); + this.setLink(itemStack, vector); + Block block = vector.getBlock(world); + if (block != null) { + player.addChatMessage(new ChatComponentText( + "Linked card to position: " + x + ", " + y + ", " + z + + " with block: " + block.getLocalizedName())); + } + } + return true; + } + + @Override + public void setLink(final ItemStack itemStack, final Vector3 position) { + final NBTTagCompound nbt = MFFSHelper.getNBTTagCompound(itemStack); + nbt.setTag("position", position.writeToNBT(new NBTTagCompound())); + } + + @Override + public Vector3 getLink(final ItemStack itemStack) { + final NBTTagCompound nbt = MFFSHelper.getNBTTagCompound(itemStack); + return Vector3.readFromNBT(nbt.getCompoundTag("position")); + } +} diff --git a/src/main/java/mffs/item/mode/ItemMode.java b/src/main/java/mffs/item/mode/ItemMode.java new file mode 100644 index 0000000..a10db9b --- /dev/null +++ b/src/main/java/mffs/item/mode/ItemMode.java @@ -0,0 +1,27 @@ +package mffs.item.mode; + +import universalelectricity.core.vector.Vector3; +import mffs.api.IFieldInteraction; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import mffs.api.IProjector; +import mffs.api.modules.IProjectorMode; +import mffs.base.ItemBase; + +public abstract class ItemMode extends ItemBase implements IProjectorMode +{ + public ItemMode(final String name) { + super(name); + this.setMaxStackSize(1); + } + + @SideOnly(Side.CLIENT) + @Override + public void render(final IProjector projector, final double x, final double y, final double z, final float f, final long ticks) { + } + + @Override + public boolean isInField(final IFieldInteraction projector, final Vector3 position) { + return false; + } +} diff --git a/src/main/java/mffs/item/mode/ItemModeCube.java b/src/main/java/mffs/item/mode/ItemModeCube.java new file mode 100644 index 0000000..1ac8b52 --- /dev/null +++ b/src/main/java/mffs/item/mode/ItemModeCube.java @@ -0,0 +1,79 @@ +package mffs.item.mode; + +import calclavia.lib.CalculationHelper; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import java.util.HashSet; +import java.util.Set; +import mffs.api.IFieldInteraction; +import mffs.api.IProjector; +import mffs.render.model.ModelCube; +import net.minecraft.tileentity.TileEntity; +import org.lwjgl.opengl.GL11; +import universalelectricity.core.vector.Vector3; +import universalelectricity.prefab.vector.Region3; + +public class ItemModeCube extends ItemMode { + public ItemModeCube(final String name) { super(name); } + + public ItemModeCube(final int i) { this("modeCube"); } + + @Override + public Set getExteriorPoints(final IFieldInteraction projector) { + final Set fieldBlocks = new HashSet<>(); + final Vector3 posScale = projector.getPositiveScale(); + final Vector3 negScale = projector.getNegativeScale(); + for (float x = (float)(-negScale.intX()); x <= posScale.intX(); x += 0.5f) { + for (float z = (float)(-negScale.intZ()); z <= posScale.intZ(); + z += 0.5f) { + for (float y = (float)(-negScale.intY()); y <= posScale.intY(); + y += 0.5f) { + if (y == -negScale.intY() || y == posScale.intY() || + x == -negScale.intX() || x == posScale.intX() || + z == -negScale.intZ() || z == posScale.intZ()) { + fieldBlocks.add(new Vector3(x, y, z)); + } + } + } + } + return fieldBlocks; + } + + @Override + public Set getInteriorPoints(final IFieldInteraction projector) { + final Set fieldBlocks = new HashSet<>(); + final Vector3 posScale = projector.getPositiveScale(); + final Vector3 negScale = projector.getNegativeScale(); + for (int x = -negScale.intX(); x <= posScale.intX(); ++x) { + for (int z = -negScale.intZ(); z <= posScale.intZ(); ++z) { + for (int y = -negScale.intY(); y <= posScale.intY(); ++y) { + fieldBlocks.add(new Vector3(x, y, z)); + } + } + } + return fieldBlocks; + } + + @Override + public boolean isInField(final IFieldInteraction projector, + final Vector3 position) { + final Vector3 projectorPos = new Vector3((TileEntity)projector); + projectorPos.add(projector.getTranslation()); + final Vector3 relativePosition = position.clone().subtract(projectorPos); + CalculationHelper.rotateByAngle(relativePosition, + -projector.getRotationYaw(), + -projector.getRotationPitch()); + final Region3 region = + new Region3(projector.getNegativeScale().clone().multiply(-1.0), + projector.getPositiveScale()); + return region.isIn(relativePosition); + } + + @SideOnly(Side.CLIENT) + @Override + public void render(final IProjector projector, final double x, final double y, + final double z, final float f, final long ticks) { + GL11.glScalef(0.5f, 0.5f, 0.5f); + ModelCube.INSTNACE.render(); + } +} diff --git a/src/main/java/mffs/item/mode/ItemModeSphere.java b/src/main/java/mffs/item/mode/ItemModeSphere.java new file mode 100644 index 0000000..5ceeb4f --- /dev/null +++ b/src/main/java/mffs/item/mode/ItemModeSphere.java @@ -0,0 +1,98 @@ +package mffs.item.mode; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import java.util.HashSet; +import java.util.Set; +import mffs.ModularForceFieldSystem; +import mffs.api.IFieldInteraction; +import mffs.api.IProjector; +import mffs.render.model.ModelCube; +import net.minecraft.tileentity.TileEntity; +import org.lwjgl.opengl.GL11; +import universalelectricity.core.vector.Vector3; + +public class ItemModeSphere extends ItemMode { + public ItemModeSphere(final int i) { super("modeSphere"); } + + @Override + public Set getExteriorPoints(final IFieldInteraction projector) { + final Set fieldBlocks = new HashSet<>(); + final int radius = projector.getModuleCount( + ModularForceFieldSystem.itemModuleScale, new int[0]); + for (int steps = (int)Math.ceil(3.141592653589793 / + Math.atan(1.0 / radius / 2.0)), + phi_n = 0; + phi_n < 2 * steps; ++phi_n) { + for (int theta_n = 0; theta_n < steps; ++theta_n) { + final double phi = 6.283185307179586 / steps * phi_n; + final double theta = 3.141592653589793 / steps * theta_n; + final Vector3 point = + new Vector3(Math.sin(theta) * Math.cos(phi), Math.cos(theta), + Math.sin(theta) * Math.sin(phi)) + .multiply(radius); + fieldBlocks.add(point); + } + } + return fieldBlocks; + } + + @Override + public Set getInteriorPoints(final IFieldInteraction projector) { + final Set fieldBlocks = new HashSet<>(); + final Vector3 translation = projector.getTranslation(); + for (int radius = projector.getModuleCount( + ModularForceFieldSystem.itemModuleScale, new int[0]), + x = -radius; + x <= radius; ++x) { + for (int z = -radius; z <= radius; ++z) { + for (int y = -radius; y <= radius; ++y) { + final Vector3 position = new Vector3(x, y, z); + if (this.isInField( + projector, + Vector3.add(position, new Vector3((TileEntity)projector)) + .add(translation))) { + fieldBlocks.add(position); + } + } + } + } + return fieldBlocks; + } + + @Override + public boolean isInField(final IFieldInteraction projector, + final Vector3 position) { + return new Vector3((TileEntity)projector) + .add(projector.getTranslation()) + .distanceTo(position) < + projector.getModuleCount(ModularForceFieldSystem.itemModuleScale, + new int[0]); + } + + @SideOnly(Side.CLIENT) + @Override + public void render(final IProjector projector, final double x1, + final double y1, final double z1, final float f, + final long ticks) { + final float scale = 0.15f; + GL11.glScalef(scale, scale, scale); + final float radius = 1.5f; + for (int steps = (int)Math.ceil(3.141592653589793 / + Math.atan(1.0 / radius / 2.0)), + phi_n = 0; + phi_n < 2 * steps; ++phi_n) { + for (int theta_n = 0; theta_n < steps; ++theta_n) { + final double phi = 6.283185307179586 / steps * phi_n; + final double theta = 3.141592653589793 / steps * theta_n; + final Vector3 vector = + new Vector3(Math.sin(theta) * Math.cos(phi), Math.cos(theta), + Math.sin(theta) * Math.sin(phi)); + vector.multiply(radius); + GL11.glTranslated(vector.x, vector.y, vector.z); + ModelCube.INSTNACE.render(); + GL11.glTranslated(-vector.x, -vector.y, -vector.z); + } + } + } +} diff --git a/src/main/java/mffs/item/mode/ItemModeTube.java b/src/main/java/mffs/item/mode/ItemModeTube.java new file mode 100644 index 0000000..686e696 --- /dev/null +++ b/src/main/java/mffs/item/mode/ItemModeTube.java @@ -0,0 +1,61 @@ +package mffs.item.mode; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import mffs.render.model.ModelPlane; +import org.lwjgl.opengl.GL11; +import mffs.api.IProjector; +import universalelectricity.core.vector.Vector3; +import net.minecraft.world.IBlockAccess; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraft.tileentity.TileEntity; +import java.util.HashSet; +import java.util.Set; +import mffs.api.IFieldInteraction; + +public class ItemModeTube extends ItemModeCube +{ + public ItemModeTube() { + super("modeTube"); + } + + @Override + public Set getExteriorPoints(final IFieldInteraction projector) { + final Set fieldBlocks = new HashSet<>(); + final ForgeDirection direction = projector.getDirection((IBlockAccess)((TileEntity)projector).getWorldObj(), ((TileEntity)projector).xCoord, ((TileEntity)projector).yCoord, ((TileEntity)projector).zCoord); + final Vector3 posScale = projector.getPositiveScale(); + final Vector3 negScale = projector.getNegativeScale(); + for (float x = (float)(-negScale.intX()); x <= posScale.intX(); x += 0.5f) { + for (float z = (float)(-negScale.intZ()); z <= posScale.intZ(); z += 0.5f) { + for (float y = (float)(-negScale.intY()); y <= posScale.intY(); y += 0.5f) { + if (direction != ForgeDirection.UP && direction != ForgeDirection.DOWN && (y == -negScale.intY() || y == posScale.intY())) { + fieldBlocks.add(new Vector3(x, y, z)); + } + else if (direction != ForgeDirection.NORTH && direction != ForgeDirection.SOUTH && (z == -negScale.intZ() || z == posScale.intZ())) { + fieldBlocks.add(new Vector3(x, y, z)); + } + else if (direction != ForgeDirection.WEST && direction != ForgeDirection.EAST && (x == -negScale.intX() || x == posScale.intX())) { + fieldBlocks.add(new Vector3(x, y, z)); + } + } + } + } + return fieldBlocks; + } + + @SideOnly(Side.CLIENT) + @Override + public void render(final IProjector projector, final double x, final double y, final double z, final float f, final long ticks) { + GL11.glScalef(0.5f, 0.5f, 0.5f); + GL11.glTranslatef(-0.5f, 0.0f, 0.0f); + ModelPlane.INSTNACE.render(); + GL11.glTranslatef(1.0f, 0.0f, 0.0f); + ModelPlane.INSTNACE.render(); + GL11.glTranslatef(-0.5f, 0.0f, 0.0f); + GL11.glRotatef(90.0f, 0.0f, 1.0f, 0.0f); + GL11.glTranslatef(0.5f, 0.0f, 0.0f); + ModelPlane.INSTNACE.render(); + GL11.glTranslatef(-1.0f, 0.0f, 0.0f); + ModelPlane.INSTNACE.render(); + } +} diff --git a/src/main/java/mffs/item/module/ItemModule.java b/src/main/java/mffs/item/module/ItemModule.java new file mode 100644 index 0000000..002cdb2 --- /dev/null +++ b/src/main/java/mffs/item/module/ItemModule.java @@ -0,0 +1,68 @@ +package mffs.item.module; + +import java.util.List; +import java.util.Set; +import mffs.api.IFieldInteraction; +import mffs.api.IProjector; +import mffs.api.modules.IModule; +import mffs.base.ItemBase; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; +import universalelectricity.core.vector.Vector3; + +public class ItemModule extends ItemBase implements IModule { + private float fortronCost; + + public ItemModule(final String name) { + super(name); + this.fortronCost = 0.5f; + } + + @Override + public void addInformation(final ItemStack itemStack, + final EntityPlayer player, final List info, + final boolean b) { + info.add("Fortron: " + this.getFortronCost(1.0f)); + super.addInformation(itemStack, player, info, b); + } + + @Override + public void onCalculate(final IFieldInteraction projector, + final Set position) {} + + @Override + public boolean onProject(final IProjector projector, + final Set fields) { + return false; + } + + @Override + public int onProject(final IProjector projector, final Vector3 position) { + return 0; + } + + @Override + public boolean onCollideWithForceField(final World world, final int x, + final int y, final int z, + final Entity entity, + final ItemStack moduleStack) { + return false; + } + + public ItemModule setCost(final float cost) { + this.fortronCost = cost; + return this; + } + + public ItemModule setMaxStackSize(final int par1) { + super.setMaxStackSize(par1); + return this; + } + + @Override + public float getFortronCost(final float amplifier) { + return this.fortronCost * amplifier; + } +} diff --git a/src/main/java/mffs/item/module/interdiction/ItemModuleAntiFriendly.java b/src/main/java/mffs/item/module/interdiction/ItemModuleAntiFriendly.java new file mode 100644 index 0000000..454b5ed --- /dev/null +++ b/src/main/java/mffs/item/module/interdiction/ItemModuleAntiFriendly.java @@ -0,0 +1,22 @@ +package mffs.item.module.interdiction; + +import mffs.ModularForceFieldSystem; +import net.minecraft.entity.INpc; +import net.minecraft.entity.monster.IMob; +import net.minecraft.entity.EntityLivingBase; +import mffs.api.security.IInterdictionMatrix; + +public class ItemModuleAntiFriendly extends ItemModuleInterdictionMatrix +{ + public ItemModuleAntiFriendly() { + super("moduleAntiFriendly"); + } + + @Override + public boolean onDefend(final IInterdictionMatrix interdictionMatrix, final EntityLivingBase entityLiving) { + if (!(entityLiving instanceof IMob) || entityLiving instanceof INpc) { + entityLiving.attackEntityFrom(ModularForceFieldSystem.damagefieldShock, Integer.MAX_VALUE); + } + return false; + } +} diff --git a/src/main/java/mffs/item/module/interdiction/ItemModuleAntiHostile.java b/src/main/java/mffs/item/module/interdiction/ItemModuleAntiHostile.java new file mode 100644 index 0000000..756c40b --- /dev/null +++ b/src/main/java/mffs/item/module/interdiction/ItemModuleAntiHostile.java @@ -0,0 +1,22 @@ +package mffs.item.module.interdiction; + +import mffs.ModularForceFieldSystem; +import net.minecraft.entity.INpc; +import net.minecraft.entity.monster.IMob; +import net.minecraft.entity.EntityLivingBase; +import mffs.api.security.IInterdictionMatrix; + +public class ItemModuleAntiHostile extends ItemModuleInterdictionMatrix +{ + public ItemModuleAntiHostile() { + super("moduleAntiHostile"); + } + + @Override + public boolean onDefend(final IInterdictionMatrix interdictionMatrix, final EntityLivingBase entityLiving) { + if (entityLiving instanceof IMob && !(entityLiving instanceof INpc)) { + entityLiving.attackEntityFrom(ModularForceFieldSystem.damagefieldShock, 20); + } + return false; + } +} diff --git a/src/main/java/mffs/item/module/interdiction/ItemModuleAntiPersonnel.java b/src/main/java/mffs/item/module/interdiction/ItemModuleAntiPersonnel.java new file mode 100644 index 0000000..506051f --- /dev/null +++ b/src/main/java/mffs/item/module/interdiction/ItemModuleAntiPersonnel.java @@ -0,0 +1,39 @@ +package mffs.item.module.interdiction; + +import mffs.ModularForceFieldSystem; +import mffs.Settings; +import mffs.api.security.IInterdictionMatrix; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ChatComponentText; + +public class ItemModuleAntiPersonnel extends ItemModuleInterdictionMatrix { + public ItemModuleAntiPersonnel() { super("moduleAntiPersonnel"); } + + @Override + public boolean onDefend(final IInterdictionMatrix interdictionMatrix, + final EntityLivingBase entityLiving) { + final boolean hasPermission = false; + if (!hasPermission && entityLiving instanceof EntityPlayer) { + final EntityPlayer player = (EntityPlayer)entityLiving; + if (!player.capabilities.isCreativeMode && + !player.isEntityInvulnerable()) { + for (int i = 0; i < player.inventory.getSizeInventory(); ++i) { + if (player.inventory.getStackInSlot(i) != null) { + interdictionMatrix.mergeIntoInventory( + player.inventory.getStackInSlot(i)); + player.inventory.setInventorySlotContents(i, (ItemStack)null); + } + } + player.attackEntityFrom(ModularForceFieldSystem.damagefieldShock, + Integer.MAX_VALUE); + interdictionMatrix.requestFortron(Settings.INTERDICTION_MURDER_ENERGY, + false); + player.addChatMessage(new ChatComponentText( + "[" + interdictionMatrix.getInventoryName() + "] Fairwell.")); + } + } + return false; + } +} diff --git a/src/main/java/mffs/item/module/interdiction/ItemModuleConfiscate.java b/src/main/java/mffs/item/module/interdiction/ItemModuleConfiscate.java new file mode 100644 index 0000000..541b19a --- /dev/null +++ b/src/main/java/mffs/item/module/interdiction/ItemModuleConfiscate.java @@ -0,0 +1,77 @@ +package mffs.item.module.interdiction; + +import java.util.Set; +import mffs.api.security.IBiometricIdentifier; +import mffs.api.security.IInterdictionMatrix; +import mffs.api.security.Permission; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ChatComponentText; + +public class ItemModuleConfiscate extends ItemModuleInterdictionMatrix { + public ItemModuleConfiscate() { super("moduleConfiscate"); } + + @Override + public boolean onDefend(final IInterdictionMatrix interdictionMatrix, + final EntityLivingBase entityLiving) { + if (entityLiving instanceof EntityPlayer) { + final EntityPlayer player = (EntityPlayer)entityLiving; + final IBiometricIdentifier biometricIdentifier = + interdictionMatrix.getBiometricIdentifier(); + if (biometricIdentifier != null && + biometricIdentifier.isAccessGranted( + player.getDisplayName(), + Permission.DEFENSE_STATION_CONFISCATION)) { + return false; + } + } + final Set controlledStacks = + interdictionMatrix.getFilteredItems(); + int confiscationCount = 0; + IInventory inventory = null; + if (entityLiving instanceof EntityPlayer) { + final IBiometricIdentifier biometricIdentifier2 = + interdictionMatrix.getBiometricIdentifier(); + if (biometricIdentifier2 != null && + biometricIdentifier2.isAccessGranted( + ((EntityPlayer)entityLiving).getDisplayName(), + Permission.BYPASS_INTERDICTION_MATRIX)) { + return false; + } + final EntityPlayer player2 = (EntityPlayer)entityLiving; + inventory = (IInventory)player2.inventory; + } else if (entityLiving instanceof IInventory) { + inventory = (IInventory)entityLiving; + } + if (inventory != null) { + for (int i = 0; i < inventory.getSizeInventory(); ++i) { + final ItemStack checkStack = inventory.getStackInSlot(i); + if (checkStack != null) { + boolean stacksMatch = false; + for (final ItemStack itemStack : controlledStacks) { + if (itemStack != null && itemStack.isItemEqual(checkStack)) { + stacksMatch = true; + break; + } + } + if ((interdictionMatrix.getFilterMode() && stacksMatch) || + (!interdictionMatrix.getFilterMode() && !stacksMatch)) { + interdictionMatrix.mergeIntoInventory(inventory.getStackInSlot(i)); + inventory.setInventorySlotContents(i, (ItemStack)null); + ++confiscationCount; + } + } + } + if (confiscationCount > 0 && entityLiving instanceof EntityPlayer) { + ((EntityPlayer)entityLiving) + .addChatMessage(new ChatComponentText( + "[" + interdictionMatrix.getInventoryName() + "] " + + confiscationCount + " of your item(s) has been confiscated.")); + } + interdictionMatrix.requestFortron(confiscationCount, true); + } + return false; + } +} diff --git a/src/main/java/mffs/item/module/interdiction/ItemModuleInterdictionMatrix.java b/src/main/java/mffs/item/module/interdiction/ItemModuleInterdictionMatrix.java new file mode 100644 index 0000000..1589217 --- /dev/null +++ b/src/main/java/mffs/item/module/interdiction/ItemModuleInterdictionMatrix.java @@ -0,0 +1,28 @@ +package mffs.item.module.interdiction; + +import java.util.List; +import mffs.api.modules.IInterdictionMatrixModule; +import mffs.api.security.IInterdictionMatrix; +import mffs.item.module.ItemModule; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; + +public class ItemModuleInterdictionMatrix + extends ItemModule implements IInterdictionMatrixModule { + public ItemModuleInterdictionMatrix(final String name) { super(name); } + + @Override + public void addInformation(final ItemStack itemStack, + final EntityPlayer player, final List info, + final boolean b) { + info.add("§4Interdiction Matrix"); + super.addInformation(itemStack, player, info, b); + } + + @Override + public boolean onDefend(final IInterdictionMatrix interdictionMatrix, + final EntityLivingBase entityLiving) { + return false; + } +} diff --git a/src/main/java/mffs/item/module/interdiction/ItemModuleWarn.java b/src/main/java/mffs/item/module/interdiction/ItemModuleWarn.java new file mode 100644 index 0000000..e316f59 --- /dev/null +++ b/src/main/java/mffs/item/module/interdiction/ItemModuleWarn.java @@ -0,0 +1,22 @@ +package mffs.item.module.interdiction; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.ChatComponentText; +import net.minecraft.entity.EntityLivingBase; +import mffs.api.security.IInterdictionMatrix; + +public class ItemModuleWarn extends ItemModuleInterdictionMatrix +{ + public ItemModuleWarn() { + super("moduleWarn"); + } + + @Override + public boolean onDefend(final IInterdictionMatrix interdictionMatrix, final EntityLivingBase entityLiving) { + final boolean hasPermission = false; + if (!hasPermission && entityLiving instanceof EntityPlayer) { + ((EntityPlayer)entityLiving).addChatMessage(new ChatComponentText("[" + interdictionMatrix.getInventoryName() + "] Leave this zone immediately. You have no right to enter.")); + } + return false; + } +} diff --git a/src/main/java/mffs/item/module/projector/ItemModeCustom.java b/src/main/java/mffs/item/module/projector/ItemModeCustom.java new file mode 100644 index 0000000..8ee7d95 --- /dev/null +++ b/src/main/java/mffs/item/module/projector/ItemModeCustom.java @@ -0,0 +1,339 @@ +package mffs.item.module.projector; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import java.io.File; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.List; +import java.util.Set; +import mffs.MFFSHelper; +import mffs.ModularForceFieldSystem; +import mffs.Settings; +import mffs.api.ICache; +import mffs.api.IFieldInteraction; +import mffs.api.IProjector; +import mffs.api.modules.IProjectorMode; +import mffs.item.mode.ItemMode; +import net.minecraft.block.Block; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompressedStreamTools; +import net.minecraft.nbt.NBTBase; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.server.MinecraftServer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ChatComponentText; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; +import universalelectricity.core.vector.Vector3; + +public class ItemModeCustom extends ItemMode implements ICache { + private final HashMap cache; + + public ItemModeCustom() { + super("modeCustom"); + this.cache = new HashMap<>(); + } + + @Override + public void addInformation(final ItemStack itemStack, + final EntityPlayer par2EntityPlayer, + final List list, final boolean par4) { + final NBTTagCompound nbt = MFFSHelper.getNBTTagCompound(itemStack); + list.add("Mode: " + (nbt.getBoolean("mode") ? "Additive" : "Substraction")); + final Vector3 point1 = Vector3.readFromNBT(nbt.getCompoundTag("point1")); + list.add("Point 1: " + point1.intX() + ", " + point1.intY() + ", " + + point1.intZ()); + final Vector3 point2 = Vector3.readFromNBT(nbt.getCompoundTag("point2")); + list.add("Point 2: " + point2.intX() + ", " + point2.intY() + ", " + + point2.intZ()); + final int modeID = nbt.getInteger("id"); + if (modeID > 0) { + list.add("Mode ID: " + modeID); + final int fieldSize = nbt.getInteger("fieldSize"); + if (fieldSize > 0) { + list.add("Field size: " + fieldSize); + } else { + list.add("Field not saved."); + } + } + if (GuiScreen.isShiftKeyDown()) { + super.addInformation(itemStack, par2EntityPlayer, list, par4); + } else { + list.add("Hold shift for more..."); + } + } + + public ItemStack onItemRightClick(final ItemStack itemStack, + final World world, + final EntityPlayer entityPlayer) { + if (!world.isRemote) { + if (entityPlayer.isSneaking()) { + final NBTTagCompound nbt = MFFSHelper.getNBTTagCompound(itemStack); + if (nbt != null) { + final Vector3 point1 = + Vector3.readFromNBT(nbt.getCompoundTag("point1")); + final Vector3 point2 = + Vector3.readFromNBT(nbt.getCompoundTag("point2")); + if (nbt.hasKey("point1") && nbt.hasKey("point2") && + !point1.equals(point2) && + point1.distanceTo(point2) < Settings.MAX_FORCE_FIELD_SCALE) { + nbt.removeTag("point1"); + nbt.removeTag("point2"); + Vector3 midPoint = new Vector3(); + midPoint.x = (point1.x + point2.x) / 2.0; + midPoint.y = (point1.y + point2.y) / 2.0; + midPoint.z = (point1.z + point2.z) / 2.0; + midPoint = midPoint.floor(); + point1.subtract(midPoint); + point2.subtract(midPoint); + final Vector3 minPoint = new Vector3(Math.min(point1.x, point2.x), + Math.min(point1.y, point2.y), + Math.min(point1.z, point2.z)); + final Vector3 maxPoint = new Vector3(Math.max(point1.x, point2.x), + Math.max(point1.y, point2.y), + Math.max(point1.z, point2.z)); + File saveFile = Paths + .get(this.getSaveDirectory().getPath(), + "custom_mode_" + this.getModeID(itemStack)) + .toFile(); + // TODO: WTF happened to NBTFileLoader?! + NBTTagCompound saveNBT = null; + try { + saveNBT = CompressedStreamTools.read(saveFile); + } catch (IOException e1) { + throw new UncheckedIOException(e1); + } + + // NBTTagCompound saveNBT = NBTFileLoader.loadData( + // this.getSaveDirectory(), + // "custom_mode_" + this.getModeID(itemStack)); + + if (saveNBT == null) { + saveNBT = new NBTTagCompound(); + } + NBTTagList list; + if (saveNBT.hasKey("fieldPoints")) { + list = (NBTTagList)saveNBT.getTag("fieldPoints"); + } else { + list = new NBTTagList(); + } + for (int x = minPoint.intX(); x <= maxPoint.intX(); ++x) { + for (int y = minPoint.intY(); y <= maxPoint.intY(); ++y) { + for (int z = minPoint.intZ(); z <= maxPoint.intZ(); ++z) { + final Vector3 position = new Vector3(x, y, z); + final Vector3 targetCheck = Vector3.add(midPoint, position); + final Block blockID = targetCheck.getBlock(world); + if (blockID != Blocks.air) { + if (nbt.getBoolean("mode")) { + final NBTTagCompound vectorTag = new NBTTagCompound(); + position.writeToNBT(vectorTag); + vectorTag.setInteger("blockID", + Block.getIdFromBlock(blockID)); + vectorTag.setInteger( + "blockMetadata", + targetCheck.getBlockMetadata((IBlockAccess)world)); + list.appendTag((NBTBase)vectorTag); + } else { + for (int i = 0; i < list.tagCount(); ++i) { + final Vector3 vector = Vector3.readFromNBT( + (NBTTagCompound)list.getCompoundTagAt(i)); + if (vector.equals(position)) { + list.removeTag(i); + } + } + } + } + } + } + } + saveNBT.setTag("fieldPoints", (NBTBase)list); + nbt.setInteger("fieldSize", list.tagCount()); + + try { + CompressedStreamTools.write(saveNBT, saveFile); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + + // NBTFileLoader.saveData(this.getSaveDirectory(), + // "custom_mode_" + this.getModeID(itemStack), + // saveNBT); + this.clearCache(); + entityPlayer.addChatMessage( + new ChatComponentText("Field structure saved.")); + } + } + } else { + final NBTTagCompound nbt = MFFSHelper.getNBTTagCompound(itemStack); + if (nbt != null) { + nbt.setBoolean("mode", !nbt.getBoolean("mode")); + entityPlayer.addChatMessage(new ChatComponentText( + "Changed selection mode to " + + (nbt.getBoolean("mode") ? "additive" : "substraction"))); + } + } + } + return itemStack; + } + + public boolean onItemUse(final ItemStack itemStack, + final EntityPlayer entityPlayer, final World world, + final int x, final int y, final int z, + final int par7, final float par8, final float par9, + final float par10) { + if (!world.isRemote) { + final NBTTagCompound nbt = MFFSHelper.getNBTTagCompound(itemStack); + if (nbt != null) { + final Vector3 point1 = + Vector3.readFromNBT(nbt.getCompoundTag("point1")); + if (!nbt.hasKey("point1") || + point1.equals(new Vector3(0.0, 0.0, 0.0))) { + nbt.setTag("point1", + new Vector3(x, y, z).writeToNBT(new NBTTagCompound())); + entityPlayer.addChatMessage(new ChatComponentText( + "Set point 1: " + x + ", " + y + ", " + z + ".")); + } else { + nbt.setTag("point2", + new Vector3(x, y, z).writeToNBT(new NBTTagCompound())); + entityPlayer.addChatMessage(new ChatComponentText( + "Set point 2: " + x + ", " + y + ", " + z + ".")); + } + } + } + return true; + } + + public int getModeID(final ItemStack itemStack) { + final NBTTagCompound nbt = MFFSHelper.getNBTTagCompound(itemStack); + int id = nbt.getInteger("id"); + if (id <= 0) { + nbt.setInteger("id", this.getNextAvaliableID()); + id = nbt.getInteger("id"); + } + return id; + } + + public int getNextAvaliableID() { + int i = 1; + i += this.getSaveDirectory().list().length; + return i; + } + + public File getSaveDirectory() { + final File saveDirectory = + // TODO: might be wrong path? + Paths.get(MinecraftServer.getServer().getFolderName(), "saves") + .toFile(); + if (!saveDirectory.exists()) { + saveDirectory.mkdir(); + } + final File file = new File(saveDirectory, "mffs"); + if (!file.exists()) { + file.mkdir(); + } + return file; + } + + public Set getFieldBlocks(final IFieldInteraction projector, + final ItemStack itemStack) { + return this.getFieldBlockMap(projector, itemStack).keySet(); + } + + public HashMap + getFieldBlockMap(final IFieldInteraction projector, + final ItemStack itemStack) { + final String cacheID = "itemStack_" + itemStack.hashCode(); + if (Settings.USE_CACHE && this.cache.containsKey(cacheID) && + this.cache.get(cacheID) instanceof HashMap) { + return (HashMap)this.cache.get(cacheID); + } + final float scale = + projector.getModuleCount(ModularForceFieldSystem.itemModuleScale, + new int[0]) / + 3.0f; + final HashMap fieldBlocks = new HashMap<>(); + if (this.getSaveDirectory() != null) { + NBTTagCompound nbt = null; + try { + nbt = CompressedStreamTools.read( + Paths + .get(this.getSaveDirectory().getPath(), + "custom_mode_" + this.getModeID(itemStack)) + .toFile()); + } catch (IOException e) { + e.printStackTrace(); + } + // final NBTTagCompound nbt = NBTFileLoader.loadData( + // this.getSaveDirectory(), "custom_mode_" + this.getModeID(itemStack)); + if (nbt != null) { + final NBTTagList nbtTagList = nbt.getTagList("fieldPoints", 10); + for (int i = 0; i < nbtTagList.tagCount(); ++i) { + final NBTTagCompound vectorTag = + (NBTTagCompound)nbtTagList.getCompoundTagAt(i); + final Vector3 position = Vector3.readFromNBT(vectorTag); + if (scale > 0.0f) { + position.multiply(scale); + } + final int[] blockInfo = {vectorTag.getInteger("blockID"), + vectorTag.getInteger("blockMetadata")}; + if (position != null) { + fieldBlocks.put(position, blockInfo); + } + } + } + if (Settings.USE_CACHE) { + this.cache.put(cacheID, fieldBlocks); + } + } + return fieldBlocks; + } + + @Override + public Object getCache(final String cacheID) { + return this.cache.get(cacheID); + } + + @Override + public void clearCache(final String cacheID) { + this.cache.remove(cacheID); + } + + @Override + public void clearCache() { + this.cache.clear(); + } + + public Set getExteriorPoints(final IFieldInteraction projector) { + return this.getFieldBlocks(projector, projector.getModeStack()); + } + + @Override + public Set getInteriorPoints(final IFieldInteraction projector) { + return this.getExteriorPoints(projector); + } + + @Override + public boolean isInField(final IFieldInteraction projector, + final Vector3 position) { + return false; + } + + @SideOnly(Side.CLIENT) + @Override + public void render(final IProjector projector, final double x, final double y, + final double z, final float f, final long ticks) { + final IProjectorMode[] modes = {ModularForceFieldSystem.itemModeCube, + ModularForceFieldSystem.itemModeSphere, + ModularForceFieldSystem.itemModeTube, + ModularForceFieldSystem.itemModePyramid}; + modes[((TileEntity)projector).getWorldObj().rand.nextInt(modes.length - 1)] + .render(projector, x, y, z, f, ticks); + } +} diff --git a/src/main/java/mffs/item/module/projector/ItemModeCylinder.java b/src/main/java/mffs/item/module/projector/ItemModeCylinder.java new file mode 100644 index 0000000..c659678 --- /dev/null +++ b/src/main/java/mffs/item/module/projector/ItemModeCylinder.java @@ -0,0 +1,122 @@ +package mffs.item.module.projector; + +import calclavia.lib.CalculationHelper; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import java.util.HashSet; +import java.util.Set; +import mffs.api.IFieldInteraction; +import mffs.api.IProjector; +import mffs.item.mode.ItemMode; +import mffs.render.model.ModelCube; +import net.minecraft.tileentity.TileEntity; +import org.lwjgl.opengl.GL11; +import universalelectricity.core.vector.Vector3; + +public class ItemModeCylinder extends ItemMode { + + public ItemModeCylinder() { super("modeCylinder"); } + + @Override + public Set getExteriorPoints(final IFieldInteraction projector) { + final Set fieldBlocks = new HashSet<>(); + final Vector3 posScale = projector.getPositiveScale(); + final Vector3 negScale = projector.getNegativeScale(); + final int radius = (posScale.intX() + negScale.intX() + posScale.intZ() + + negScale.intZ()) / + 2; + final int height = posScale.intY() + negScale.intY(); + for (float x = (float)(-radius); x <= radius; ++x) { + for (float z = (float)(-radius); z <= radius; ++z) { + for (float y = 0.0f; y < height; ++y) { + if ((y == 0.0f || y == height - 1) && + x * x + z * z + 0.0f <= radius * radius) { + fieldBlocks.add(new Vector3(x, y, z)); + } + if (x * x + z * z + 0.0f <= radius * radius && + x * x + z * z + 0.0f >= (radius - 1) * (radius - 1)) { + fieldBlocks.add(new Vector3(x, y, z)); + } + } + } + } + return fieldBlocks; + } + + @Override + public Set getInteriorPoints(final IFieldInteraction projector) { + final Set fieldBlocks = new HashSet<>(); + final Vector3 translation = projector.getTranslation(); + final Vector3 posScale = projector.getPositiveScale(); + final Vector3 negScale = projector.getNegativeScale(); + final int radius = (posScale.intX() + negScale.intX() + posScale.intZ() + + negScale.intZ()) / + 2; + final int height = posScale.intY() + negScale.intY(); + for (int x = -radius; x <= radius; ++x) { + for (int z = -radius; z <= radius; ++z) { + for (int y = 0; y < height; ++y) { + final Vector3 position = new Vector3(x, y, z); + if (this.isInField( + projector, + Vector3.add(position, new Vector3((TileEntity)projector)) + .add(translation))) { + fieldBlocks.add(position); + } + } + } + } + return fieldBlocks; + } + + @Override + public boolean isInField(final IFieldInteraction projector, + final Vector3 position) { + final Vector3 posScale = projector.getPositiveScale(); + final Vector3 negScale = projector.getNegativeScale(); + final int radius = (posScale.intX() + negScale.intX() + posScale.intZ() + + negScale.intZ()) / + 2; + final Vector3 projectorPos = new Vector3((TileEntity)projector); + projectorPos.add(projector.getTranslation()); + final Vector3 relativePosition = position.clone().subtract(projectorPos); + CalculationHelper.rotateByAngle(relativePosition, + -projector.getRotationYaw(), + -projector.getRotationPitch()); + return relativePosition.x * relativePosition.x + + relativePosition.z * relativePosition.z + 0.0 <= + radius * radius; + } + + @SideOnly(Side.CLIENT) + @Override + public void render(final IProjector projector, final double x, final double y, + final double z, final float f, final long ticks) { + final float scale = 0.15f; + final float detail = 0.5f; + GL11.glScalef(scale, scale, scale); + final float radius = 1.5f; + int i = 0; + for (float renderX = -radius; renderX <= radius; renderX += detail) { + for (float renderZ = -radius; renderZ <= radius; renderZ += detail) { + for (float renderY = -radius; renderY <= radius; renderY += detail) { + if ((renderX * renderX + renderZ * renderZ + 0.0f <= + radius * radius && + renderX * renderX + renderZ * renderZ + 0.0f >= + (radius - 1.0f) * (radius - 1.0f)) || + ((renderY == 0.0f || renderY == radius - 1.0f) && + renderX * renderX + renderZ * renderZ + 0.0f <= + radius * radius)) { + if (i % 2 == 0) { + final Vector3 vector = new Vector3(renderX, renderY, renderZ); + GL11.glTranslated(vector.x, vector.y, vector.z); + ModelCube.INSTNACE.render(); + GL11.glTranslated(-vector.x, -vector.y, -vector.z); + } + ++i; + } + } + } + } + } +} diff --git a/src/main/java/mffs/item/module/projector/ItemModePyramid.java b/src/main/java/mffs/item/module/projector/ItemModePyramid.java new file mode 100644 index 0000000..e890030 --- /dev/null +++ b/src/main/java/mffs/item/module/projector/ItemModePyramid.java @@ -0,0 +1,137 @@ +package mffs.item.module.projector; + +import calclavia.lib.CalculationHelper; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import java.util.HashSet; +import java.util.Set; +import mffs.api.IFieldInteraction; +import mffs.api.IProjector; +import mffs.item.mode.ItemMode; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.tileentity.TileEntity; +import org.lwjgl.opengl.GL11; +import universalelectricity.core.vector.Vector3; +import universalelectricity.prefab.vector.Region3; + +public class ItemModePyramid extends ItemMode { + public ItemModePyramid() { super("modePyramid"); } + + @Override + public Set getExteriorPoints(final IFieldInteraction projector) { + final Set fieldBlocks = new HashSet<>(); + final Vector3 posScale = projector.getPositiveScale(); + final Vector3 negScale = projector.getNegativeScale(); + final int xStretch = posScale.intX() + negScale.intX(); + final int yStretch = posScale.intY() + negScale.intY(); + final int zStretch = posScale.intZ() + negScale.intZ(); + final Vector3 translation = new Vector3(0.0, -negScale.intY(), 0.0); + for (float y = 0.0f; y <= yStretch; ++y) { + for (float x = (float)(-xStretch); x <= xStretch; ++x) { + for (float z = (float)(-zStretch); z <= zStretch; ++z) { + final double yTest = y / yStretch * 8.0f; + final double xzPositivePlane = + (1.0f - x / xStretch - z / zStretch) * 8.0f; + final double xzNegativePlane = + (1.0f + x / xStretch - z / zStretch) * 8.0f; + if (x >= 0.0f && z >= 0.0f && + Math.round(xzPositivePlane) == Math.round(yTest)) { + fieldBlocks.add(new Vector3(x, y, z).add(translation)); + fieldBlocks.add(new Vector3(x, y, -z).add(translation)); + } + if (x <= 0.0f && z >= 0.0f && + Math.round(xzNegativePlane) == Math.round(yTest)) { + fieldBlocks.add(new Vector3(x, y, -z).add(translation)); + fieldBlocks.add(new Vector3(x, y, z).add(translation)); + } + if (y == 0.0f && + Math.abs(x) + Math.abs(z) < (xStretch + yStretch) / 2) { + fieldBlocks.add(new Vector3(x, y, z).add(translation)); + } + } + } + } + return fieldBlocks; + } + + @Override + public Set getInteriorPoints(final IFieldInteraction projector) { + final Set fieldBlocks = new HashSet<>(); + final Vector3 posScale = projector.getPositiveScale(); + final Vector3 negScale = projector.getNegativeScale(); + final int xStretch = posScale.intX() + negScale.intX(); + final int yStretch = posScale.intY() + negScale.intY(); + final int zStretch = posScale.intZ() + negScale.intZ(); + final Vector3 translation = new Vector3(0.0, -0.4, 0.0); + for (float x = (float)(-xStretch); x <= xStretch; ++x) { + for (float z = (float)(-zStretch); z <= zStretch; ++z) { + for (float y = 0.0f; y <= yStretch; ++y) { + final Vector3 position = new Vector3(x, y, z).add(translation); + if (this.isInField( + projector, + Vector3.add(position, new Vector3((TileEntity)projector)))) { + fieldBlocks.add(position); + } + } + } + } + return fieldBlocks; + } + + @Override + public boolean isInField(final IFieldInteraction projector, + final Vector3 position) { + final Vector3 posScale = projector.getPositiveScale().clone(); + final Vector3 negScale = projector.getNegativeScale().clone(); + final int xStretch = posScale.intX() + negScale.intX(); + final int yStretch = posScale.intY() + negScale.intY(); + final int zStretch = posScale.intZ() + negScale.intZ(); + final Vector3 projectorPos = new Vector3((TileEntity)projector); + projectorPos.add(projector.getTranslation()); + projectorPos.add(new Vector3(0.0, -negScale.intY() + 1, 0.0)); + final Vector3 relativePosition = position.clone().subtract(projectorPos); + CalculationHelper.rotateByAngle(relativePosition, + -projector.getRotationYaw(), + -projector.getRotationPitch()); + final Region3 region = new Region3(negScale.multiply(-1.0), posScale); + return region.isIn(relativePosition) && relativePosition.y > 0.0 && + 1.0 - Math.abs(relativePosition.x) / xStretch - + Math.abs(relativePosition.z) / zStretch > + relativePosition.y / yStretch; + } + + @SideOnly(Side.CLIENT) + @Override + public void render(final IProjector projector, final double x, final double y, + final double z, final float f, final long ticks) { + final Tessellator tessellator = Tessellator.instance; + GL11.glPushMatrix(); + GL11.glRotatef(180.0f, 0.0f, 0.0f, 1.0f); + final float height = 0.5f; + final float width = 0.3f; + final int uvMaxX = 2; + final int uvMaxY = 2; + final Vector3 translation = new Vector3(0.0, -0.4, 0.0); + tessellator.startDrawing(6); + tessellator.setColorRGBA(72, 198, 255, 255); + tessellator.addVertexWithUV(0.0 + translation.x, 0.0 + translation.y, + 0.0 + translation.z, 0.0, 0.0); + tessellator.addVertexWithUV(-width + translation.x, height + translation.y, + -width + translation.z, (double)(-uvMaxX), + (double)(-uvMaxY)); + tessellator.addVertexWithUV(-width + translation.x, height + translation.y, + width + translation.z, (double)(-uvMaxX), + (double)uvMaxY); + tessellator.addVertexWithUV(width + translation.x, height + translation.y, + width + translation.z, (double)uvMaxX, + (double)uvMaxY); + tessellator.addVertexWithUV(width + translation.x, height + translation.y, + -width + translation.z, (double)uvMaxX, + (double)(-uvMaxY)); + tessellator.addVertexWithUV(-width + translation.x, height + translation.y, + -width + translation.z, (double)(-uvMaxX), + (double)(-uvMaxY)); + tessellator.draw(); + GL11.glPopMatrix(); + } +} diff --git a/src/main/java/mffs/item/module/projector/ItemModuleDisintegration.java b/src/main/java/mffs/item/module/projector/ItemModuleDisintegration.java new file mode 100644 index 0000000..4947d71 --- /dev/null +++ b/src/main/java/mffs/item/module/projector/ItemModuleDisintegration.java @@ -0,0 +1,109 @@ +package mffs.item.module.projector; + +import java.util.HashSet; +import java.util.Set; +import mffs.IDelayedEventHandler; +import mffs.MFFSHelper; +import mffs.ModularForceFieldSystem; +import mffs.base.PacketFxs; +import mffs.api.Blacklist; +import mffs.api.IProjector; +import mffs.base.TileEntityInventory; +import mffs.event.BlockDropDelayedEvent; +import mffs.event.BlockInventoryDropDelayedEvent; +import mffs.item.module.ItemModule; +import mffs.tileentity.TileEntityForceFieldProjector; +import net.minecraft.block.Block; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.IBlockAccess; +import net.minecraftforge.fluids.IFluidBlock; +import universalelectricity.core.vector.Vector3; + +public class ItemModuleDisintegration extends ItemModule { + private int blockCount; + + public ItemModuleDisintegration() { + super("moduleDisintegration"); + this.blockCount = 0; + this.setMaxStackSize(1); + this.setCost(20.0f); + } + + @Override + public boolean onProject(final IProjector projector, + final Set fields) { + this.blockCount = 0; + return false; + } + + @Override + public int onProject(final IProjector projector, final Vector3 position) { + if (projector.getTicks() % 40L == 0L) { + final TileEntity tileEntity = (TileEntity) projector; + final Block block = position.getBlock((IBlockAccess) tileEntity.getWorldObj()); + if (block != Blocks.air) { + if (projector.getModuleCount( + ModularForceFieldSystem.itemModuleCamouflage, new int[0]) > 0) { + final int blockMetadata = position.getBlockMetadata((IBlockAccess) tileEntity.getWorldObj()); + final Set filterStacks = new HashSet<>(); + for (final int i : projector.getModuleSlots()) { + final ItemStack checkStack = projector.getStackInSlot(i); + final Block filterBlock = MFFSHelper.getFilterBlock(checkStack); + if (filterBlock != null) { + filterStacks.add(checkStack); + } + } + boolean contains = false; + for (final ItemStack filterStack : filterStacks) { + if (filterStack.isItemEqual( + new ItemStack(block, 1, blockMetadata))) { + contains = true; + break; + } + } + if (!contains) { + return 1; + } + } + if (Blacklist.disintegrationBlacklist.contains(block) || + block instanceof IFluidBlock) { + return 1; + } + + NBTTagCompound fxsData = new NBTTagCompound(); + + position.writeToNBT(fxsData); + fxsData.setInteger("type", 2); + + ModularForceFieldSystem.channel.sendToAll( + new PacketFxs(new Vector3((TileEntity) projector), fxsData)); + + if (projector.getModuleCount( + ModularForceFieldSystem.itemModuleCollection, new int[0]) > 0) { + ((TileEntityForceFieldProjector) projector) + .getDelayedEvents() + .add(new BlockInventoryDropDelayedEvent( + (IDelayedEventHandler) projector, 39, block, + tileEntity.getWorldObj(), position, + (TileEntityInventory) projector)); + } else { + ((TileEntityForceFieldProjector) projector) + .getDelayedEvents() + .add(new BlockDropDelayedEvent( + (IDelayedEventHandler) projector, 39, block, + tileEntity.getWorldObj(), position)); + } + if (this.blockCount++ >= projector.getModuleCount(ModularForceFieldSystem.itemModuleSpeed, + new int[0]) / + 3) { + return 2; + } + return 1; + } + } + return 1; + } +} diff --git a/src/main/java/mffs/item/module/projector/ItemModuleFusion.java b/src/main/java/mffs/item/module/projector/ItemModuleFusion.java new file mode 100644 index 0000000..194c26a --- /dev/null +++ b/src/main/java/mffs/item/module/projector/ItemModuleFusion.java @@ -0,0 +1,48 @@ +package mffs.item.module.projector; + +import icbm.api.IBlockFrequency; +import java.util.Iterator; +import java.util.Set; +import mffs.api.IFieldInteraction; +import mffs.api.IProjector; +import mffs.api.fortron.IFortronFrequency; +import mffs.base.TileEntityBase; +import mffs.fortron.FrequencyGrid; +import mffs.item.module.ItemModule; +import net.minecraft.tileentity.TileEntity; +import universalelectricity.core.vector.Vector3; + +public class ItemModuleFusion extends ItemModule { + public ItemModuleFusion() { + super("moduleFusion"); + this.setMaxStackSize(1); + this.setCost(1.0f); + } + + @Override + public boolean onProject(final IProjector projector, + final Set fieldBlocks) { + final Set machines = FrequencyGrid.instance().get( + ((IFortronFrequency)projector).getFrequency()); + for (final IBlockFrequency compareProjector : machines) { + if (compareProjector instanceof IProjector && + compareProjector != projector && + ((TileEntity)compareProjector).getWorldObj() == + ((TileEntity)projector).getWorldObj() && + ((TileEntityBase)compareProjector).isActive() && + ((IProjector)compareProjector).getMode() != null) { + final Iterator it = fieldBlocks.iterator(); + while (it.hasNext()) { + final Vector3 position = it.next(); + if (((IProjector)compareProjector) + .getMode() + .isInField((IFieldInteraction)compareProjector, + position.clone())) { + it.remove(); + } + } + } + } + return false; + } +} diff --git a/src/main/java/mffs/item/module/projector/ItemModuleManipulator.java b/src/main/java/mffs/item/module/projector/ItemModuleManipulator.java new file mode 100644 index 0000000..cf90110 --- /dev/null +++ b/src/main/java/mffs/item/module/projector/ItemModuleManipulator.java @@ -0,0 +1,24 @@ +package mffs.item.module.projector; + +import java.util.Iterator; +import java.util.Set; +import mffs.api.IFieldInteraction; +import mffs.item.module.ItemModule; +import net.minecraft.tileentity.TileEntity; +import universalelectricity.core.vector.Vector3; + +public class ItemModuleManipulator extends ItemModule { + public ItemModuleManipulator() { super("moduleManipulator"); } + + @Override + public void onCalculate(final IFieldInteraction projector, + final Set fieldBlocks) { + final Iterator it = fieldBlocks.iterator(); + while (it.hasNext()) { + final Vector3 position = it.next(); + if (position.y < ((TileEntity)projector).yCoord) { + it.remove(); + } + } + } +} diff --git a/src/main/java/mffs/item/module/projector/ItemModuleShock.java b/src/main/java/mffs/item/module/projector/ItemModuleShock.java new file mode 100644 index 0000000..c3ac5a3 --- /dev/null +++ b/src/main/java/mffs/item/module/projector/ItemModuleShock.java @@ -0,0 +1,24 @@ +package mffs.item.module.projector; + +import mffs.ModularForceFieldSystem; +import mffs.item.module.ItemModule; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLiving; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; + +public class ItemModuleShock extends ItemModule { + public ItemModuleShock() { super("moduleShock"); } + + @Override + public boolean onCollideWithForceField(final World world, final int x, + final int y, final int z, + final Entity entity, + final ItemStack moduleStack) { + if (entity instanceof EntityLiving) { + entity.attackEntityFrom(ModularForceFieldSystem.damagefieldShock, + moduleStack.stackSize); + } + return false; + } +} diff --git a/src/main/java/mffs/item/module/projector/ItemModuleSponge.java b/src/main/java/mffs/item/module/projector/ItemModuleSponge.java new file mode 100644 index 0000000..1de44a1 --- /dev/null +++ b/src/main/java/mffs/item/module/projector/ItemModuleSponge.java @@ -0,0 +1,31 @@ +package mffs.item.module.projector; + +import java.util.Set; +import mffs.api.IProjector; +import mffs.item.module.ItemModule; +import net.minecraft.init.Blocks; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.World; +import net.minecraftforge.fluids.IFluidBlock; +import universalelectricity.core.vector.Vector3; + +public class ItemModuleSponge extends ItemModule { + public ItemModuleSponge() { + super("moduleSponge"); + this.setMaxStackSize(1); + } + + @Override + public boolean onProject(final IProjector projector, + final Set fields) { + if (projector.getTicks() % 60L == 0L) { + final World world = ((TileEntity)projector).getWorldObj(); + for (final Vector3 point : projector.getInteriorPoints()) { + if (point.getBlock(world) instanceof IFluidBlock) { + point.setBlock(world, Blocks.air); + } + } + } + return super.onProject(projector, fields); + } +} diff --git a/src/main/java/mffs/item/module/projector/ItemModuleStablize.java b/src/main/java/mffs/item/module/projector/ItemModuleStablize.java new file mode 100644 index 0000000..13fba0c --- /dev/null +++ b/src/main/java/mffs/item/module/projector/ItemModuleStablize.java @@ -0,0 +1,124 @@ +package mffs.item.module.projector; + +import calclavia.lib.CalculationHelper; +import java.util.HashMap; +import java.util.Set; +import mffs.base.PacketFxs; +import mffs.ModularForceFieldSystem; +import mffs.api.Blacklist; +import mffs.api.IProjector; +import mffs.item.module.ItemModule; +import net.minecraft.block.Block; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.inventory.IInventory; +import net.minecraft.item.ItemBlock; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.IFluidBlock; +import universalelectricity.core.vector.Vector3; +import universalelectricity.core.vector.VectorHelper; + +public class ItemModuleStablize extends ItemModule { + private int blockCount; + + public ItemModuleStablize() { + super("moduleStabilize"); + this.blockCount = 0; + this.setMaxStackSize(1); + this.setCost(20.0f); + } + + @Override + public boolean onProject(final IProjector projector, + final Set fields) { + this.blockCount = 0; + return false; + } + + @Override + public int onProject(final IProjector projector, final Vector3 position) { + int[] blockInfo = null; + if (projector.getTicks() % 40L == 0L) { + if (projector.getMode() instanceof ItemModeCustom) { + final HashMap fieldBlocks = ((ItemModeCustom) projector.getMode()) + .getFieldBlockMap(projector, projector.getModeStack()); + final Vector3 fieldCenter = new Vector3((TileEntity) projector).add(projector.getTranslation()); + final Vector3 relativePosition = position.clone().subtract(fieldCenter); + CalculationHelper.rotateByAngle(relativePosition, + -projector.getRotationYaw(), + -projector.getRotationPitch()); + blockInfo = fieldBlocks.get(relativePosition.round()); + } + for (int dir = 0; dir < 6; ++dir) { + final ForgeDirection direction = ForgeDirection.getOrientation(dir); + final TileEntity tileEntity = VectorHelper.getTileEntityFromSide( + ((TileEntity) projector).getWorldObj(), + new Vector3((TileEntity) projector), direction); + if (tileEntity instanceof IInventory) { + final IInventory inventory = (IInventory) tileEntity; + for (int i = 0; i < inventory.getSizeInventory(); ++i) { + final ItemStack checkStack = inventory.getStackInSlot(i); + if (checkStack != null && checkStack.getItem() instanceof ItemBlock) { + if (blockInfo != null) { + if (Block.getBlockById(blockInfo[0]) != Block + .getBlockFromItem((ItemBlock) checkStack.getItem())) { + continue; + } + } + try { + if (((TileEntity) projector) + .getWorldObj() + .canPlaceEntityOnSide( + Block.getBlockFromItem( + (ItemBlock) checkStack.getItem()), + position.intX(), position.intY(), position.intZ(), + false, 0, (Entity) null, checkStack)) { + final int metadata = (blockInfo != null) + ? blockInfo[1] + : (checkStack.getHasSubtypes() + ? checkStack.getItemDamage() + : 0); + final Block block = (blockInfo != null) + ? Block.getBlockById(blockInfo[0]) + : null; + if (Blacklist.stabilizationBlacklist.contains(block) || + block instanceof IFluidBlock) { + return 1; + } + ((ItemBlock) checkStack.getItem()) + .placeBlockAt(checkStack, (EntityPlayer) null, + ((TileEntity) projector).getWorldObj(), + position.intX(), position.intY(), + position.intZ(), 0, 0.0f, 0.0f, 0.0f, + metadata); + inventory.decrStackSize(i, 1); + + NBTTagCompound fxsData = new NBTTagCompound(); + + position.writeToNBT(fxsData); + fxsData.setInteger("type", 1); + + ModularForceFieldSystem.channel.sendToAll(new PacketFxs( + new Vector3((TileEntity) projector), fxsData)); + + if (this.blockCount++ >= projector.getModuleCount( + ModularForceFieldSystem.itemModuleSpeed, new int[0]) / + 3) { + return 2; + } + return 1; + } + } catch (final Exception e) { + e.printStackTrace(); + } + } + } + } + } + } + return 1; + } +} diff --git a/src/main/java/mffs/recipe/IRecipeAdapter.java b/src/main/java/mffs/recipe/IRecipeAdapter.java new file mode 100644 index 0000000..3cc4960 --- /dev/null +++ b/src/main/java/mffs/recipe/IRecipeAdapter.java @@ -0,0 +1,14 @@ +package mffs.recipe; + +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.IRecipe; + +public interface IRecipeAdapter { + public void setOutput(ItemStack item); + + public void setPattern(String... pattern); + + public void addIngredient(Object... ingredients); + + public IRecipe create(); +} diff --git a/src/main/java/mffs/recipe/RecipeBuilder.java b/src/main/java/mffs/recipe/RecipeBuilder.java new file mode 100644 index 0000000..dbb7b78 --- /dev/null +++ b/src/main/java/mffs/recipe/RecipeBuilder.java @@ -0,0 +1,49 @@ +package mffs.recipe; + +import cpw.mods.fml.common.registry.GameRegistry; +import net.minecraft.block.Block; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; + +public class RecipeBuilder { + IRecipeAdapter adapter; + + public RecipeBuilder(IRecipeAdapter adapter) { this.adapter = adapter; } + + public RecipeBuilder output(ItemStack stack) { + this.adapter.setOutput(stack); + return this; + } + + public RecipeBuilder output(Item item) { + this.adapter.setOutput(new ItemStack(item)); + return this; + } + + public RecipeBuilder output(Block block) { + this.adapter.setOutput(new ItemStack(block)); + return this; + } + + public RecipeBuilder output(Block block, int count) { + this.adapter.setOutput(new ItemStack(block, count)); + return this; + } + + public RecipeBuilder output(Item item, int count) { + this.adapter.setOutput(new ItemStack(item, count)); + return this; + } + + public RecipeBuilder pattern(String... pat) { + this.adapter.setPattern(pat); + return this; + } + + public RecipeBuilder ingredient(Object... i) { + this.adapter.addIngredient(i); + return this; + } + + public void register() { GameRegistry.addRecipe(this.adapter.create()); } +} diff --git a/src/main/java/mffs/recipe/ShapedOreRecipeAdapter.java b/src/main/java/mffs/recipe/ShapedOreRecipeAdapter.java new file mode 100644 index 0000000..c11487f --- /dev/null +++ b/src/main/java/mffs/recipe/ShapedOreRecipeAdapter.java @@ -0,0 +1,41 @@ +package mffs.recipe; + +import java.util.ArrayList; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.IRecipe; +import net.minecraftforge.oredict.ShapedOreRecipe; + +public class ShapedOreRecipeAdapter implements IRecipeAdapter { + ItemStack output; + String[] pattern; + ArrayList ingredients = new ArrayList<>(); + + @Override + public void setOutput(ItemStack item) { + this.output = item; + } + + @Override + public void setPattern(String... pattern) { + this.pattern = pattern; + } + + @Override + public void addIngredient(Object... ingredients) { + this.ingredients.add(ingredients[0]); + this.ingredients.add(ingredients[1]); + } + + @Override + public IRecipe create() { + ArrayList args = new ArrayList<>(); + + for (String pat : this.pattern) + args.add(pat); + + for (Object ing : this.ingredients) + args.add(ing); + + return new ShapedOreRecipe(this.output, args.toArray()); + } +} diff --git a/src/main/java/mffs/recipe/ShapelessOreRecipeAdapter.java b/src/main/java/mffs/recipe/ShapelessOreRecipeAdapter.java new file mode 100644 index 0000000..ee67d0f --- /dev/null +++ b/src/main/java/mffs/recipe/ShapelessOreRecipeAdapter.java @@ -0,0 +1,31 @@ +package mffs.recipe; + +import java.util.ArrayList; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.IRecipe; +import net.minecraftforge.oredict.ShapelessOreRecipe; + +public class ShapelessOreRecipeAdapter implements IRecipeAdapter { + ItemStack output; + ArrayList ingredients = new ArrayList<>(); + + @Override + public void setOutput(ItemStack item) { + this.output = item; + } + + @Override + public void setPattern(String... pattern) { + throw new UnsupportedOperationException("Shapeless recipe has no pattern!"); + } + + @Override + public void addIngredient(Object... ingredients) { + this.ingredients.add(ingredients[0]); + } + + @Override + public IRecipe create() { + return new ShapelessOreRecipe(this.output, this.ingredients.toArray()); + } +} diff --git a/src/main/java/mffs/render/FXBeam.java b/src/main/java/mffs/render/FXBeam.java new file mode 100644 index 0000000..3e28d36 --- /dev/null +++ b/src/main/java/mffs/render/FXBeam.java @@ -0,0 +1,185 @@ +package mffs.render; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.client.Minecraft; +import net.minecraft.client.particle.EntityFX; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.util.MathHelper; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.World; +import org.lwjgl.opengl.GL11; +import universalelectricity.core.vector.Vector3; + +@SideOnly(Side.CLIENT) +public class FXBeam extends EntityFX { + double movX; + double movY; + double movZ; + private float length; + private float rotYaw; + private float rotPitch; + private float prevYaw; + private float prevPitch; + private Vector3 target; + private float endModifier; + private boolean reverse; + private boolean pulse; + private int rotationSpeed; + private float prevSize; + + public FXBeam(final World par1World, final Vector3 position, + final Vector3 target, final float red, final float green, + final float blue, final int age) { + super(par1World, position.x, position.y, position.z, 0.0, 0.0, 0.0); + this.movX = 0.0; + this.movY = 0.0; + this.movZ = 0.0; + this.length = 0.0f; + this.rotYaw = 0.0f; + this.rotPitch = 0.0f; + this.prevYaw = 0.0f; + this.prevPitch = 0.0f; + this.target = new Vector3(); + this.endModifier = 1.0f; + this.reverse = false; + this.pulse = true; + this.rotationSpeed = 20; + this.prevSize = 0.0f; + this.setRGB(red, green, blue); + this.setSize(0.02f, 0.02f); + ((Entity)this).noClip = true; + ((Entity)this).motionX = 0.0; + ((Entity)this).motionY = 0.0; + ((Entity)this).motionZ = 0.0; + this.target = target; + final float xd = (float)(((Entity)this).posX - this.target.x); + final float yd = (float)(((Entity)this).posY - this.target.y); + final float zd = (float)(((Entity)this).posZ - this.target.z); + this.length = (float)new Vector3((Entity)this).distanceTo(this.target); + final double var7 = MathHelper.sqrt_double((double)(xd * xd + zd * zd)); + this.rotYaw = (float)(Math.atan2(xd, zd) * 180.0 / 3.141592653589793); + this.rotPitch = (float)(Math.atan2(yd, var7) * 180.0 / 3.141592653589793); + this.prevYaw = this.rotYaw; + this.prevPitch = this.rotPitch; + super.particleMaxAge = age; + final EntityLivingBase renderentity = + Minecraft.getMinecraft().renderViewEntity; + int visibleDistance = 50; + if (!Minecraft.getMinecraft().gameSettings.fancyGraphics) { + visibleDistance = 25; + } + if (renderentity.getDistance(((Entity)this).posX, ((Entity)this).posY, + ((Entity)this).posZ) > visibleDistance) { + super.particleMaxAge = 0; + } + } + + public void onUpdate() { + ((Entity)this).prevPosX = ((Entity)this).posX; + ((Entity)this).prevPosY = ((Entity)this).posY; + ((Entity)this).prevPosZ = ((Entity)this).posZ; + this.prevYaw = this.rotYaw; + this.prevPitch = this.rotPitch; + final float xd = (float)(((Entity)this).posX - this.target.x); + final float yd = (float)(((Entity)this).posY - this.target.y); + final float zd = (float)(((Entity)this).posZ - this.target.z); + this.length = MathHelper.sqrt_float(xd * xd + yd * yd + zd * zd); + final double var7 = MathHelper.sqrt_double((double)(xd * xd + zd * zd)); + this.rotYaw = (float)(Math.atan2(xd, zd) * 180.0 / 3.141592653589793); + this.rotPitch = (float)(Math.atan2(yd, var7) * 180.0 / 3.141592653589793); + if (super.particleAge++ >= super.particleMaxAge) { + this.setDead(); + } + } + + public void setRGB(final float r, final float g, final float b) { + super.particleRed = r; + super.particleGreen = g; + super.particleBlue = b; + } + + public void renderParticle(final Tessellator tessellator, final float f, + final float f1, final float f2, final float f3, + final float f4, final float f5) { + tessellator.draw(); + GL11.glPushMatrix(); + final float var9 = 1.0f; + final float slide = (float)((Entity)this).worldObj.getTotalWorldTime(); + final float rot = ((Entity)this).worldObj.provider.getWorldTime() % + (360 / this.rotationSpeed) * this.rotationSpeed + + this.rotationSpeed * f; + float size = 1.0f; + if (this.pulse) { + size = Math.min(super.particleAge / 4.0f, 1.0f); + size = this.prevSize + (size - this.prevSize) * f; + } + float op = 0.5f; + if (this.pulse && super.particleMaxAge - super.particleAge <= 4) { + op = 0.5f - (4 - (super.particleMaxAge - super.particleAge)) * 0.1f; + } + Minecraft.getMinecraft().renderEngine.bindTexture( + new ResourceLocation("mffs", "textures/blocks/fortron.png")); + GL11.glTexParameterf(3553, 10242, 10497.0f); + GL11.glTexParameterf(3553, 10243, 10497.0f); + GL11.glDisable(2884); + float var10 = slide + f; + if (this.reverse) { + var10 *= -1.0f; + } + final float var11 = -var10 * 0.2f - MathHelper.floor_float(-var10 * 0.1f); + GL11.glEnable(3042); + GL11.glBlendFunc(770, 1); + GL11.glDepthMask(false); + final float xx = + (float)(((Entity)this).prevPosX + + (((Entity)this).posX - ((Entity)this).prevPosX) * f - + EntityFX.interpPosX); + final float yy = + (float)(((Entity)this).prevPosY + + (((Entity)this).posY - ((Entity)this).prevPosY) * f - + EntityFX.interpPosY); + final float zz = + (float)(((Entity)this).prevPosZ + + (((Entity)this).posZ - ((Entity)this).prevPosZ) * f - + EntityFX.interpPosZ); + GL11.glTranslated((double)xx, (double)yy, (double)zz); + final float ry = this.prevYaw + (this.rotYaw - this.prevYaw) * f; + final float rp = this.prevPitch + (this.rotPitch - this.prevPitch) * f; + GL11.glRotatef(90.0f, 1.0f, 0.0f, 0.0f); + GL11.glRotatef(180.0f + ry, 0.0f, 0.0f, -1.0f); + GL11.glRotatef(rp, 1.0f, 0.0f, 0.0f); + final double var12 = -0.15 * size; + final double var13 = 0.15 * size; + final double var44b = -0.15 * size * this.endModifier; + final double var17b = 0.15 * size * this.endModifier; + GL11.glRotatef(rot, 0.0f, 1.0f, 0.0f); + for (int t = 0; t < 3; ++t) { + final double var14 = this.length * size * var9; + final double var15 = 0.0; + final double var16 = 1.0; + final double var17 = -1.0f + var11 + t / 3.0f; + final double var18 = this.length * size * var9 + var17; + GL11.glRotatef(60.0f, 0.0f, 1.0f, 0.0f); + tessellator.startDrawingQuads(); + tessellator.setBrightness(200); + tessellator.setColorRGBA_F(super.particleRed, super.particleGreen, + super.particleBlue, op); + tessellator.addVertexWithUV(var44b, var14, 0.0, var16, var18); + tessellator.addVertexWithUV(var12, 0.0, 0.0, var16, var17); + tessellator.addVertexWithUV(var13, 0.0, 0.0, var15, var17); + tessellator.addVertexWithUV(var17b, var14, 0.0, var15, var18); + tessellator.draw(); + } + GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + GL11.glDepthMask(true); + GL11.glDisable(3042); + GL11.glEnable(2884); + GL11.glPopMatrix(); + tessellator.startDrawingQuads(); + this.prevSize = size; + Minecraft.getMinecraft().renderEngine.bindTexture(new ResourceLocation("particles")); + } +} diff --git a/src/main/java/mffs/render/FXHologram.java b/src/main/java/mffs/render/FXHologram.java new file mode 100644 index 0000000..098ee1e --- /dev/null +++ b/src/main/java/mffs/render/FXHologram.java @@ -0,0 +1,93 @@ +package mffs.render; + +import calclavia.lib.render.CalclaviaRenderHelper; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import mffs.ModularForceFieldSystem; +import net.minecraft.block.Block; +import net.minecraft.client.Minecraft; +import net.minecraft.client.particle.EntityFX; +import net.minecraft.client.renderer.RenderBlocks; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.texture.TextureMap; +import net.minecraft.entity.Entity; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.World; +import org.lwjgl.opengl.GL11; +import universalelectricity.core.vector.Vector3; + +@SideOnly(Side.CLIENT) +public class FXHologram extends EntityFX { + private Vector3 targetPosition; + + public FXHologram(final World par1World, final Vector3 position, + final float red, final float green, final float blue, + final int age) { + super(par1World, position.x, position.y, position.z); + this.targetPosition = null; + this.setRBGColorF(red, green, blue); + super.particleMaxAge = age; + ((Entity)this).noClip = true; + } + + public FXHologram setTarget(final Vector3 targetPosition) { + this.targetPosition = targetPosition; + ((Entity)this).motionX = + (this.targetPosition.x - ((Entity)this).posX) / super.particleMaxAge; + ((Entity)this).motionY = + (this.targetPosition.y - ((Entity)this).posY) / super.particleMaxAge; + ((Entity)this).motionZ = + (this.targetPosition.z - ((Entity)this).posZ) / super.particleMaxAge; + return this; + } + + public void onUpdate() { + ((Entity)this).prevPosX = ((Entity)this).posX; + ((Entity)this).prevPosY = ((Entity)this).posY; + ((Entity)this).prevPosZ = ((Entity)this).posZ; + if (super.particleAge++ >= super.particleMaxAge) { + this.setDead(); + return; + } + if (this.targetPosition != null) { + this.moveEntity(((Entity)this).motionX, ((Entity)this).motionY, + ((Entity)this).motionZ); + } + } + + public void renderParticle(final Tessellator tessellator, final float f, + final float f1, final float f2, final float f3, + final float f4, final float f5) { + tessellator.draw(); + GL11.glPushMatrix(); + final float xx = + (float)(((Entity)this).prevPosX + + (((Entity)this).posX - ((Entity)this).prevPosX) * f - + EntityFX.interpPosX); + final float yy = + (float)(((Entity)this).prevPosY + + (((Entity)this).posY - ((Entity)this).prevPosY) * f - + EntityFX.interpPosY); + final float zz = + (float)(((Entity)this).prevPosZ + + (((Entity)this).posZ - ((Entity)this).prevPosZ) * f - + EntityFX.interpPosZ); + GL11.glTranslated((double)xx, (double)yy, (double)zz); + GL11.glScalef(1.01f, 1.01f, 1.01f); + float op = 0.5f; + if (super.particleMaxAge - super.particleAge <= 4) { + op = 0.5f - (5 - (super.particleMaxAge - super.particleAge)) * 0.1f; + } + GL11.glColor4d((double)super.particleRed, (double)super.particleGreen, + (double)super.particleBlue, (double)(op * 2.0f)); + CalclaviaRenderHelper.disableLighting(); + CalclaviaRenderHelper.enableBlending(); + Minecraft.getMinecraft().renderEngine.bindTexture(TextureMap.locationBlocksTexture); + CalclaviaRenderHelper.renderNormalBlockAsItem( + (Block)ModularForceFieldSystem.blockForceField, 0, new RenderBlocks()); + CalclaviaRenderHelper.disableBlending(); + GL11.glPopMatrix(); + tessellator.startDrawingQuads(); + Minecraft.getMinecraft().renderEngine.bindTexture(new ResourceLocation("particles")); + } +} diff --git a/src/main/java/mffs/render/FXHologramMoving.java b/src/main/java/mffs/render/FXHologramMoving.java new file mode 100644 index 0000000..d756dd0 --- /dev/null +++ b/src/main/java/mffs/render/FXHologramMoving.java @@ -0,0 +1,79 @@ +package mffs.render; + +import calclavia.lib.render.CalclaviaRenderHelper; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import mffs.ModularForceFieldSystem; +import net.minecraft.block.Block; +import net.minecraft.client.Minecraft; +import net.minecraft.client.particle.EntityFX; +import net.minecraft.client.renderer.RenderBlocks; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.texture.TextureMap; +import net.minecraft.entity.Entity; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.World; +import org.lwjgl.opengl.GL11; +import universalelectricity.core.vector.Vector3; + +@SideOnly(Side.CLIENT) +public class FXHologramMoving extends EntityFX { + public FXHologramMoving(final World par1World, final Vector3 position, + final float red, final float green, final float blue, + final int age) { + super(par1World, position.x, position.y, position.z); + this.setRBGColorF(red, green, blue); + super.particleMaxAge = age; + ((Entity)this).noClip = true; + } + + public void onUpdate() { + ((Entity)this).prevPosX = ((Entity)this).posX; + ((Entity)this).prevPosY = ((Entity)this).posY; + ((Entity)this).prevPosZ = ((Entity)this).posZ; + if (super.particleAge++ >= super.particleMaxAge) { + this.setDead(); + } + } + + public void renderParticle(final Tessellator tessellator, final float f, + final float f1, final float f2, final float f3, + final float f4, final float f5) { + tessellator.draw(); + GL11.glPushMatrix(); + final float xx = + (float)(((Entity)this).prevPosX + + (((Entity)this).posX - ((Entity)this).prevPosX) * f - + EntityFX.interpPosX); + final float yy = + (float)(((Entity)this).prevPosY + + (((Entity)this).posY - ((Entity)this).prevPosY) * f - + EntityFX.interpPosY); + final float zz = + (float)(((Entity)this).prevPosZ + + (((Entity)this).posZ - ((Entity)this).prevPosZ) * f - + EntityFX.interpPosZ); + GL11.glTranslated((double)xx, (double)yy, (double)zz); + GL11.glScalef(1.01f, 1.01f, 1.01f); + final double completion = super.particleAge / (double)super.particleMaxAge; + GL11.glTranslated(0.0, (completion - 1.0) / 2.0, 0.0); + GL11.glScaled(1.0, completion, 1.0); + float op = 0.5f; + if (super.particleMaxAge - super.particleAge <= 4) { + op = 0.5f - (5 - (super.particleMaxAge - super.particleAge)) * 0.1f; + } + GL11.glColor4d((double)super.particleRed, (double)super.particleGreen, + (double)super.particleBlue, (double)(op * 2.0f)); + CalclaviaRenderHelper.disableLighting(); + CalclaviaRenderHelper.enableBlending(); + Minecraft.getMinecraft().renderEngine.bindTexture(TextureMap.locationBlocksTexture); + CalclaviaRenderHelper.renderNormalBlockAsItem( + (Block)ModularForceFieldSystem.blockForceField, 0, new RenderBlocks()); + CalclaviaRenderHelper.disableBlending(); + CalclaviaRenderHelper.enableLighting(); + GL11.glPopMatrix(); + tessellator.startDrawingQuads(); + Minecraft.getMinecraft().renderEngine.bindTexture( + new ResourceLocation("particles")); + } +} diff --git a/src/main/java/mffs/render/RenderBlockHandler.java b/src/main/java/mffs/render/RenderBlockHandler.java new file mode 100644 index 0000000..7c921aa --- /dev/null +++ b/src/main/java/mffs/render/RenderBlockHandler.java @@ -0,0 +1,84 @@ +package mffs.render; + +import calclavia.lib.render.CalclaviaRenderHelper; +import cpw.mods.fml.client.FMLClientHandler; +import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler; +import cpw.mods.fml.client.registry.RenderingRegistry; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import mffs.block.BlockCoercionDeriver; +import mffs.block.BlockForceFieldProjector; +import mffs.block.BlockForceManipulator; +import mffs.block.BlockFortronCapacitor; +import net.minecraft.block.Block; +import net.minecraft.client.renderer.RenderBlocks; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.IBlockAccess; +import org.lwjgl.opengl.GL11; + +@SideOnly(Side.CLIENT) +public class RenderBlockHandler implements ISimpleBlockRenderingHandler { + public static final int ID; + + @Override + public void renderInventoryBlock(final Block block, final int metadata, + final int modelID, + final RenderBlocks renderer) { + if (modelID == RenderBlockHandler.ID) { + GL11.glPushMatrix(); + if (block instanceof BlockFortronCapacitor) { + FMLClientHandler.instance().getClient().renderEngine.bindTexture( + new ResourceLocation("mffs", + "textures/models/fortronCapacitor_on.png")); + GL11.glTranslated(0.5, 1.9, 0.5); + GL11.glRotatef(180.0f, 0.0f, 0.0f, 1.0f); + GL11.glScalef(1.3f, 1.3f, 1.3f); + RenderFortronCapacitor.MODEL.render(0.0625f); + } else if (block instanceof BlockForceFieldProjector) { + FMLClientHandler.instance().getClient().renderEngine.bindTexture( + new ResourceLocation("mffs", "textures/models/projector_on.png")); + GL11.glTranslated(0.5, 1.5, 0.5); + GL11.glRotatef(180.0f, 0.0f, 0.0f, 1.0f); + RenderForceFieldProjector.MODEL.render(0.0f, 0.0625f); + } else if (block instanceof BlockCoercionDeriver) { + FMLClientHandler.instance().getClient().renderEngine.bindTexture( + new ResourceLocation("mffs", + "textures/models/coercionDeriver_on.png")); + GL11.glTranslated(0.5, 1.9, 0.5); + GL11.glRotatef(180.0f, 0.0f, 0.0f, 1.0f); + GL11.glScalef(1.3f, 1.3f, 1.3f); + RenderCoercionDeriver.MODEL.render(0.0f, 0.0625f); + } else if (block instanceof BlockForceManipulator) { + FMLClientHandler.instance().getClient().renderEngine.bindTexture( + new ResourceLocation("mffs", + "textures/models/forceManipulator_on.png")); + GL11.glTranslated(0.5, 1.4, 0.5); + GL11.glRotatef(180.0f, 0.0f, 0.0f, 1.0f); + RenderForceManipulator.MODEL.render(0.0625f); + } + GL11.glPopMatrix(); + } else { + CalclaviaRenderHelper.renderNormalBlockAsItem(block, metadata, renderer); + } + } + + @Override + public boolean renderWorldBlock(final IBlockAccess iBlockAccess, final int x, + final int y, final int z, final Block block, + final int modelID, + final RenderBlocks renderer) { + return false; + } + + @Override + public boolean shouldRender3DInInventory(int arg0) { + return true; + } + + @Override + public int getRenderId() { + return RenderBlockHandler.ID; + } + + static { ID = RenderingRegistry.getNextAvailableRenderId(); } +} diff --git a/src/main/java/mffs/render/RenderCoercionDeriver.java b/src/main/java/mffs/render/RenderCoercionDeriver.java new file mode 100644 index 0000000..9fc01c0 --- /dev/null +++ b/src/main/java/mffs/render/RenderCoercionDeriver.java @@ -0,0 +1,39 @@ +package mffs.render; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import mffs.base.TileEntityBase; +import mffs.render.model.ModelCoercionDeriver; +import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ResourceLocation; +import org.lwjgl.opengl.GL11; + +@SideOnly(Side.CLIENT) +public class RenderCoercionDeriver extends TileEntitySpecialRenderer { + public static final String TEXTURE_ON = "coercionDeriver_on.png"; + public static final String TEXTURE_OFF = "coercionDeriver_off.png"; + public static final ModelCoercionDeriver MODEL; + + @Override + public void renderTileEntityAt(final TileEntity t, final double x, + final double y, final double z, + final float f) { + final TileEntityBase tileEntity = (TileEntityBase)t; + if (tileEntity.isActive()) { + this.bindTexture(new ResourceLocation( + "mffs", "textures/models/coercionDeriver_on.png")); + } else { + this.bindTexture(new ResourceLocation( + "mffs", "textures/models/coercionDeriver_off.png")); + } + GL11.glPushMatrix(); + GL11.glTranslated(x + 0.5, y + 1.95, z + 0.5); + GL11.glRotatef(180.0f, 0.0f, 0.0f, 1.0f); + GL11.glScalef(1.3f, 1.3f, 1.3f); + RenderCoercionDeriver.MODEL.render(tileEntity.animation, 0.0625f); + GL11.glPopMatrix(); + } + + static { MODEL = new ModelCoercionDeriver(); } +} diff --git a/src/main/java/mffs/render/RenderForceField.java b/src/main/java/mffs/render/RenderForceField.java new file mode 100644 index 0000000..0535fca --- /dev/null +++ b/src/main/java/mffs/render/RenderForceField.java @@ -0,0 +1,137 @@ +package mffs.render; + +import calclavia.lib.render.CalclaviaRenderHelper; +import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler; +import cpw.mods.fml.client.registry.RenderingRegistry; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import mffs.ModularForceFieldSystem; +import mffs.tileentity.TileEntityForceField; +import net.minecraft.block.Block; +import net.minecraft.client.renderer.RenderBlocks; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.world.IBlockAccess; + +@SideOnly(Side.CLIENT) +public class RenderForceField implements ISimpleBlockRenderingHandler { + public static final int ID; + + @Override + public void renderInventoryBlock(final Block block, final int metadata, + final int modelID, + final RenderBlocks renderer) { + CalclaviaRenderHelper.renderNormalBlockAsItem(block, metadata, renderer); + } + + @Override + public boolean renderWorldBlock(final IBlockAccess iBlockAccess, final int x, + final int y, final int z, final Block block, + final int modelId, + final RenderBlocks renderer) { + int renderType = 0; + final TileEntity tileEntity = iBlockAccess.getTileEntity(x, y, z); + if (tileEntity instanceof TileEntityForceField) { + final ItemStack checkStack = ((TileEntityForceField) tileEntity).camoStack; + if (checkStack != null) { + final Block checkBlock = Block.getBlockFromItem(checkStack.getItem()); + if (checkBlock != null) { + renderType = checkBlock.getRenderType(); + } + } + } + ModularForceFieldSystem.LOGGER.fine("Render block: " + block.getUnlocalizedName()); + if (renderType >= 0) { + switch (renderType) { + case 4: { + renderer.renderBlockLiquid(block, x, y, z); + break; + } + case 31: { + renderer.renderBlockLog(block, x, y, z); + break; + } + case 1: { + renderer.renderCrossedSquares(block, x, y, z); + break; + } + case 20: { + renderer.renderBlockVine(block, x, y, z); + break; + } + case 39: { + renderer.renderBlockQuartz(block, x, y, z); + break; + } + case 5: { + renderer.renderBlockRedstoneWire(block, x, y, z); + break; + } + case 13: { + renderer.renderBlockCactus(block, x, y, z); + break; + } + case 23: { + renderer.renderBlockLilyPad(block, x, y, z); + break; + } + case 6: { + renderer.renderBlockCrops(block, x, y, z); + break; + } + case 8: { + renderer.renderBlockLadder(block, x, y, z); + break; + } + case 7: { + renderer.renderBlockDoor(block, x, y, z); + break; + } + case 12: { + renderer.renderBlockLever(block, x, y, z); + break; + } + case 29: { + renderer.renderBlockTripWireSource(block, x, y, z); + break; + } + case 30: { + renderer.renderBlockTripWire(block, x, y, z); + break; + } + case 14: { + renderer.renderBlockBed(block, x, y, z); + break; + } + case 16: { + renderer.renderPistonBase(block, x, y, z, false); + break; + } + case 17: { + renderer.renderPistonExtension(block, x, y, z, true); + break; + } + default: { + renderer.renderStandardBlock(block, x, y, z); + break; + } + } + return true; + } + return false; + } + + @Override + public boolean shouldRender3DInInventory(int arg0) { + return true; + } + + @Override + public int getRenderId() { + return RenderForceField.ID; + } + + static { + ID = RenderingRegistry.getNextAvailableRenderId(); + } +} diff --git a/src/main/java/mffs/render/RenderForceFieldProjector.java b/src/main/java/mffs/render/RenderForceFieldProjector.java new file mode 100644 index 0000000..e5baf3b --- /dev/null +++ b/src/main/java/mffs/render/RenderForceFieldProjector.java @@ -0,0 +1,119 @@ +package mffs.render; + +import calclavia.lib.render.CalclaviaRenderHelper; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import mffs.Settings; +import mffs.render.model.ModelForceFieldProjector; +import mffs.tileentity.TileEntityForceFieldProjector; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; +import net.minecraft.entity.Entity; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ResourceLocation; +import org.lwjgl.opengl.GL11; + +@SideOnly(Side.CLIENT) +public class RenderForceFieldProjector extends TileEntitySpecialRenderer { + public static final String TEXTURE_ON = "projector_on.png"; + public static final String TEXTURE_OFF = "projector_off.png"; + public static final ModelForceFieldProjector MODEL; + + @Override + public void renderTileEntityAt(final TileEntity t, final double x, + final double y, final double z, + final float f) { + if (t instanceof TileEntityForceFieldProjector) { + final TileEntityForceFieldProjector tileEntity = + (TileEntityForceFieldProjector)t; + GL11.glPushMatrix(); + GL11.glTranslated(x + 0.5, y + 1.5, z + 0.5); + if (tileEntity.isActive()) { + this.bindTexture( + new ResourceLocation("mffs", "textures/models/projector_on.png")); + } else { + this.bindTexture( + new ResourceLocation("mffs", "textures/models/projector_off.png")); + } + GL11.glRotatef(180.0f, 0.0f, 0.0f, 1.0f); + RenderForceFieldProjector.MODEL.render(tileEntity.animation, 0.0625f); + GL11.glPopMatrix(); + if (tileEntity.getMode() != null) { + final Tessellator tessellator = Tessellator.instance; + RenderHelper.disableStandardItemLighting(); + GL11.glPushMatrix(); + GL11.glTranslated(x + 0.5, y + 0.5, z + 0.5); + final double xDifference = + ((Entity)Minecraft.getMinecraft().thePlayer).posX - + (tileEntity.xCoord + 0.5); + final double zDifference = + ((Entity)Minecraft.getMinecraft().thePlayer).posZ - + (tileEntity.zCoord + 0.5); + final float rotatation = + (float)Math.toDegrees(Math.atan2(zDifference, xDifference)); + GL11.glRotatef(-rotatation + 27.0f, 0.0f, 1.0f, 0.0f); + GL11.glDisable(3553); + GL11.glShadeModel(7425); + GL11.glEnable(3042); + GL11.glBlendFunc(770, 1); + GL11.glDisable(3008); + GL11.glEnable(2884); + GL11.glDepthMask(false); + GL11.glPushMatrix(); + tessellator.startDrawing(6); + final float height = 2.0f; + final float width = 2.0f; + tessellator.setColorRGBA(72, 198, 255, 255); + tessellator.addVertex(0.0, 0.0, 0.0); + tessellator.setColorRGBA_I(0, 0); + tessellator.addVertex(-0.866 * width, (double)height, + (double)(-0.5f * width)); + tessellator.addVertex(0.866 * width, (double)height, + (double)(-0.5f * width)); + tessellator.addVertex(0.0, (double)height, (double)(1.0f * width)); + tessellator.addVertex(-0.866 * width, (double)height, + (double)(-0.5f * width)); + tessellator.draw(); + GL11.glPopMatrix(); + GL11.glDepthMask(true); + GL11.glDisable(2884); + GL11.glDisable(3042); + GL11.glShadeModel(7424); + GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + GL11.glEnable(3553); + GL11.glEnable(3008); + RenderHelper.enableStandardItemLighting(); + GL11.glPopMatrix(); + if (Settings.HIGH_GRAPHICS) { + GL11.glPushMatrix(); + GL11.glTranslated(x + 0.5, y + 1.35, z + 0.5); + this.bindTexture( + new ResourceLocation("mffs", "textures/models/force_cube.png")); + CalclaviaRenderHelper.enableBlending(); + CalclaviaRenderHelper.disableLighting(); + GL11.glPushMatrix(); + GL11.glColor4f(1.0f, 1.0f, 1.0f, + (float)Math.sin(tileEntity.getTicks() / 10.0) / 2.0f + + 1.0f); + GL11.glTranslatef(0.0f, + (float)Math.sin(Math.toRadians( + (double)(tileEntity.getTicks() * 3L))) / + 7.0f, + 0.0f); + GL11.glRotatef((float)(tileEntity.getTicks() * 4L), 0.0f, 1.0f, 0.0f); + GL11.glRotatef(36.0f + tileEntity.getTicks() * 4L, 0.0f, 1.0f, 1.0f); + tileEntity.getMode().render(tileEntity, x, y, z, f, + tileEntity.getTicks()); + GL11.glPopMatrix(); + CalclaviaRenderHelper.enableLighting(); + CalclaviaRenderHelper.disableBlending(); + GL11.glPopMatrix(); + } + } + } + } + + static { MODEL = new ModelForceFieldProjector(); } +} diff --git a/src/main/java/mffs/render/RenderForceManipulator.java b/src/main/java/mffs/render/RenderForceManipulator.java new file mode 100644 index 0000000..8495b0f --- /dev/null +++ b/src/main/java/mffs/render/RenderForceManipulator.java @@ -0,0 +1,38 @@ +package mffs.render; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import mffs.base.TileEntityBase; +import mffs.render.model.ModelForceManipulator; +import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ResourceLocation; +import org.lwjgl.opengl.GL11; + +@SideOnly(Side.CLIENT) +public class RenderForceManipulator extends TileEntitySpecialRenderer { + public static final String TEXTURE_ON = "forceManipulator_on.png"; + public static final String TEXTURE_OFF = "forceManipulator_off.png"; + public static final ModelForceManipulator MODEL; + + @Override + public void renderTileEntityAt(final TileEntity t, final double x, + final double y, final double z, + final float f) { + final TileEntityBase tileEntity = (TileEntityBase)t; + if (tileEntity.isActive()) { + this.bindTexture(new ResourceLocation( + "mffs", "textures/models/forceManipulator_on.png")); + } else { + this.bindTexture(new ResourceLocation( + "mffs", "textures/models/forceManipulator_off.png")); + } + GL11.glPushMatrix(); + GL11.glTranslated(x + 0.5, y + 1.5, z + 0.5); + GL11.glRotatef(180.0f, 0.0f, 0.0f, 1.0f); + RenderForceManipulator.MODEL.render(0.0625f); + GL11.glPopMatrix(); + } + + static { MODEL = new ModelForceManipulator(); } +} diff --git a/src/main/java/mffs/render/RenderFortronCapacitor.java b/src/main/java/mffs/render/RenderFortronCapacitor.java new file mode 100644 index 0000000..f5a850e --- /dev/null +++ b/src/main/java/mffs/render/RenderFortronCapacitor.java @@ -0,0 +1,39 @@ +package mffs.render; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import mffs.base.TileEntityBase; +import mffs.render.model.ModelFortronCapacitor; +import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ResourceLocation; +import org.lwjgl.opengl.GL11; + +@SideOnly(Side.CLIENT) +public class RenderFortronCapacitor extends TileEntitySpecialRenderer { + public static final String TEXTURE_ON = "fortronCapacitor_on.png"; + public static final String TEXTURE_OFF = "fortronCapacitor_off.png"; + public static final ModelFortronCapacitor MODEL; + + @Override + public void renderTileEntityAt(final TileEntity t, final double x, + final double y, final double z, + final float f) { + final TileEntityBase tileEntity = (TileEntityBase)t; + if (tileEntity.isActive()) { + this.bindTexture(new ResourceLocation( + "mffs", "textures/models/fortronCapacitor_on.png")); + } else { + this.bindTexture(new ResourceLocation( + "mffs", "textures/models/fortronCapacitor_off.png")); + } + GL11.glPushMatrix(); + GL11.glTranslated(x + 0.5, y + 1.95, z + 0.5); + GL11.glRotatef(180.0f, 0.0f, 0.0f, 1.0f); + GL11.glScalef(1.3f, 1.3f, 1.3f); + RenderFortronCapacitor.MODEL.render(0.0625f); + GL11.glPopMatrix(); + } + + static { MODEL = new ModelFortronCapacitor(); } +} diff --git a/src/main/java/mffs/render/RenderIDCard.java b/src/main/java/mffs/render/RenderIDCard.java new file mode 100644 index 0000000..5fa66c7 --- /dev/null +++ b/src/main/java/mffs/render/RenderIDCard.java @@ -0,0 +1,213 @@ +package mffs.render; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import mffs.ModularForceFieldSystem; +import mffs.api.card.ICardIdentification; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.ItemRenderer; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.texture.TextureMap; +import net.minecraft.entity.EntityLiving; +import net.minecraft.item.ItemStack; +import net.minecraft.util.IIcon; +import net.minecraft.util.ResourceLocation; +import net.minecraftforge.client.IItemRenderer; +import org.lwjgl.opengl.GL11; +import universalelectricity.core.vector.Vector2; + +@SideOnly(Side.CLIENT) +public class RenderIDCard implements IItemRenderer { + private Minecraft mc; + + public RenderIDCard() { this.mc = Minecraft.getMinecraft(); } + + public void renderItem(final IItemRenderer.ItemRenderType type, + final ItemStack itemStack, final Object... data) { + if (itemStack.getItem() instanceof ICardIdentification) { + final ICardIdentification card = (ICardIdentification)itemStack.getItem(); + GL11.glPushMatrix(); + GL11.glDisable(2884); + this.transform(type); + this.renderItemIcon( + ModularForceFieldSystem.itemCardID.getIcon(itemStack, 0)); + if (type != IItemRenderer.ItemRenderType.INVENTORY) { + GL11.glTranslatef(0.0f, 0.0f, -5.0E-4f); + } + this.renderPlayerFace(this.getSkin(card.getUsername(itemStack))); + if (type != IItemRenderer.ItemRenderType.INVENTORY) { + GL11.glTranslatef(0.0f, 0.0f, 0.002f); + this.renderItemIcon( + ModularForceFieldSystem.itemCardID.getIcon(itemStack, 0)); + } + GL11.glEnable(2884); + GL11.glPopMatrix(); + } + } + + private void transform(final IItemRenderer.ItemRenderType type) { + final float scale = 0.0625f; + if (type != IItemRenderer.ItemRenderType.INVENTORY) { + GL11.glScalef(scale, -scale, -scale); + GL11.glTranslatef(20.0f, -16.0f, 0.0f); + GL11.glRotatef(180.0f, 1.0f, 1.0f, 0.0f); + GL11.glRotatef(-90.0f, 0.0f, 0.0f, 1.0f); + } + if (type == IItemRenderer.ItemRenderType.ENTITY) { + GL11.glTranslatef(20.0f, 0.0f, 0.0f); + GL11.glRotatef(Minecraft.getSystemTime() / 12.0f % 360.0f, 0.0f, 1.0f, + 0.0f); + GL11.glTranslatef(-8.0f, 0.0f, 0.0f); + GL11.glTranslated( + 0.0, 2.0 * Math.sin(Minecraft.getSystemTime() / 512.0 % 360.0), 0.0); + } + } + + private int getSkin(final String name) { + return 0; + // TODO: DAFUQ + // try { + // final String skin = "http://skins.minecraft.net/MinecraftSkins/" + name + + // ".png"; + // final Minecraft mc = Minecraft.getMinecraft(); + // if (!mc.renderEngine.func_82773_c(skin)) { + // mc.renderEngine.func_78356_a(skin, (IImageBuffer)new + // ImageBufferDownload()); + // } + // return mc.renderEngine.func_78350_a(skin, "/mob/char.png"); + // } + // catch (final Exception e) { + // e.printStackTrace(); + // return 0; + // } + } + + private void renderPlayerFace(final int texID) { + final Vector2 translation = new Vector2(9.0, 5.0); + final int xSize = 4; + final int ySize = 4; + final int topLX = translation.intX(); + final int topRX = translation.intX() + xSize; + final int botLX = translation.intX(); + final int botRX = translation.intX() + xSize; + final int topLY = translation.intY(); + final int topRY = translation.intY(); + final int botLY = translation.intY() + ySize; + final int botRY = translation.intY() + ySize; + GL11.glBindTexture(3553, texID); + GL11.glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + GL11.glBegin(7); + GL11.glTexCoord2f(0.125f, 0.25f); + GL11.glVertex2f((float)topLX, (float)topLY); + GL11.glTexCoord2f(0.125f, 0.5f); + GL11.glVertex2f((float)botLX, (float)botLY); + GL11.glTexCoord2f(0.25f, 0.5f); + GL11.glVertex2f((float)botRX, (float)botRY); + GL11.glTexCoord2f(0.25f, 0.25f); + GL11.glVertex2f((float)topRX, (float)topRY); + GL11.glEnd(); + GL11.glBegin(7); + GL11.glTexCoord2f(0.625f, 0.25f); + GL11.glVertex2f((float)topLX, (float)topLY); + GL11.glTexCoord2f(0.625f, 0.5f); + GL11.glVertex2f((float)botLX, (float)botLY); + GL11.glTexCoord2f(0.75f, 0.5f); + GL11.glVertex2f((float)botRX, (float)botRY); + GL11.glTexCoord2f(0.75f, 0.25f); + GL11.glVertex2f((float)topRX, (float)topRY); + GL11.glEnd(); + } + + private void renderItemIcon(final IIcon icon) { + Minecraft.getMinecraft().renderEngine.bindTexture( + TextureMap.locationItemsTexture); + GL11.glBegin(7); + GL11.glTexCoord2f(icon.getMinU(), icon.getMinV()); + GL11.glVertex2f(0.0f, 0.0f); + GL11.glTexCoord2f(icon.getMinU(), icon.getMaxV()); + GL11.glVertex2f(0.0f, 16.0f); + GL11.glTexCoord2f(icon.getMaxU(), icon.getMaxV()); + GL11.glVertex2f(16.0f, 16.0f); + GL11.glTexCoord2f(icon.getMaxU(), icon.getMinV()); + GL11.glVertex2f(16.0f, 0.0f); + GL11.glEnd(); + } + + //TODO: WTF + //@Override + private void renderItem3D(final EntityLiving par1EntityLiving, + final ItemStack par2ItemStack, final int par3) { + final IIcon icon = par1EntityLiving.getItemIcon(par2ItemStack, par3); + if (icon == null) { + GL11.glPopMatrix(); + return; + } + if (par2ItemStack.getItemSpriteNumber() == 0) { + this.mc.renderEngine.bindTexture(TextureMap.locationBlocksTexture); + } else { + this.mc.renderEngine.bindTexture(TextureMap.locationItemsTexture); + } + final Tessellator tessellator = Tessellator.instance; + final float f = icon.getMinU(); + final float f2 = icon.getMaxU(); + final float f3 = icon.getMinV(); + final float f4 = icon.getMaxV(); + final float f5 = 0.0f; + final float f6 = 0.3f; + GL11.glEnable(32826); + GL11.glTranslatef(-f5, -f6, 0.0f); + final float f7 = 1.5f; + GL11.glScalef(f7, f7, f7); + GL11.glRotatef(50.0f, 0.0f, 1.0f, 0.0f); + GL11.glRotatef(335.0f, 0.0f, 0.0f, 1.0f); + GL11.glTranslatef(-0.9375f, -0.0625f, 0.0f); + ItemRenderer.renderItemIn2D(tessellator, f2, f3, f, f4, icon.getIconWidth(), + icon.getIconHeight(), 0.0625f); + if (par2ItemStack != null && par2ItemStack.hasEffect(0) && par3 == 0) { + GL11.glDepthFunc(514); + GL11.glDisable(2896); + // TODO: WTF + this.mc.renderEngine.bindTexture(new ResourceLocation( + "%blur%/textures/misc/enchanted_item_glint.png")); + GL11.glEnable(3042); + GL11.glBlendFunc(768, 1); + final float f8 = 0.76f; + GL11.glColor4f(0.5f * f8, 0.25f * f8, 0.8f * f8, 1.0f); + GL11.glMatrixMode(5890); + GL11.glPushMatrix(); + final float f9 = 0.125f; + GL11.glScalef(f9, f9, f9); + float f10 = Minecraft.getSystemTime() % 3000L / 3000.0f * 8.0f; + GL11.glTranslatef(f10, 0.0f, 0.0f); + GL11.glRotatef(-50.0f, 0.0f, 0.0f, 1.0f); + ItemRenderer.renderItemIn2D(tessellator, 0.0f, 0.0f, 1.0f, 1.0f, 256, 256, + 0.0625f); + GL11.glPopMatrix(); + GL11.glPushMatrix(); + GL11.glScalef(f9, f9, f9); + f10 = Minecraft.getSystemTime() % 4873L / 4873.0f * 8.0f; + GL11.glTranslatef(-f10, 0.0f, 0.0f); + GL11.glRotatef(10.0f, 0.0f, 0.0f, 1.0f); + ItemRenderer.renderItemIn2D(tessellator, 0.0f, 0.0f, 1.0f, 1.0f, 256, 256, + 0.0625f); + GL11.glPopMatrix(); + GL11.glMatrixMode(5888); + GL11.glDisable(3042); + GL11.glEnable(2896); + GL11.glDepthFunc(515); + } + GL11.glDisable(32826); + } + + public boolean handleRenderType(final ItemStack item, + final IItemRenderer.ItemRenderType type) { + return true; + } + + public boolean + shouldUseRenderHelper(final IItemRenderer.ItemRenderType type, + final ItemStack item, + final IItemRenderer.ItemRendererHelper helper) { + return false; + } +} diff --git a/src/main/java/mffs/render/model/ModelCoercionDeriver.java b/src/main/java/mffs/render/model/ModelCoercionDeriver.java new file mode 100644 index 0000000..d62eae6 --- /dev/null +++ b/src/main/java/mffs/render/model/ModelCoercionDeriver.java @@ -0,0 +1,125 @@ +package mffs.render.model; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.client.model.ModelBase; +import net.minecraft.client.model.ModelRenderer; +import org.lwjgl.opengl.GL11; + +@SideOnly(Side.CLIENT) +public class ModelCoercionDeriver extends ModelBase { + ModelRenderer corner1; + ModelRenderer corner2; + ModelRenderer corner3; + ModelRenderer corner4; + ModelRenderer Bout; + ModelRenderer Baout; + ModelRenderer Fout; + ModelRenderer Tout; + ModelRenderer Core; + ModelRenderer Movingthingright; + ModelRenderer Movingthingleft; + ModelRenderer bottom; + + public ModelCoercionDeriver() { + super.textureWidth = 64; + super.textureHeight = 32; + (this.corner1 = new ModelRenderer((ModelBase)this, 52, 0)) + .addBox(3.0f, 16.0f, 3.0f, 3, 6, 3); + this.corner1.setRotationPoint(0.0f, 0.0f, 0.0f); + this.corner1.setTextureSize(64, 32); + this.corner1.mirror = true; + this.setRotation(this.corner1, 0.0f, 0.0f, 0.0f); + (this.corner2 = new ModelRenderer((ModelBase)this, 52, 0)) + .addBox(-6.0f, 16.0f, 3.0f, 3, 6, 3); + this.corner2.setRotationPoint(0.0f, 0.0f, 0.0f); + this.corner2.setTextureSize(64, 32); + this.corner2.mirror = true; + this.setRotation(this.corner2, 0.0f, 0.0f, 0.0f); + (this.corner3 = new ModelRenderer((ModelBase)this, 52, 0)) + .addBox(-6.0f, 16.0f, -6.0f, 3, 6, 3); + this.corner3.setRotationPoint(0.0f, 0.0f, 0.0f); + this.corner3.setTextureSize(64, 32); + this.corner3.mirror = true; + this.setRotation(this.corner3, 0.0f, 0.0f, 0.0f); + (this.corner4 = new ModelRenderer((ModelBase)this, 52, 0)) + .addBox(3.0f, 16.0f, -6.0f, 3, 6, 3); + this.corner4.setRotationPoint(0.0f, 0.0f, 0.0f); + this.corner4.setTextureSize(64, 32); + this.corner4.mirror = true; + this.setRotation(this.corner4, 0.0f, 0.0f, 0.0f); + (this.Bout = new ModelRenderer((ModelBase)this, 24, 19)) + .addBox(-2.0f, 21.0f, -2.0f, 4, 1, 4); + this.Bout.setRotationPoint(0.0f, 0.0f, 0.0f); + this.Bout.setTextureSize(64, 32); + this.Bout.mirror = true; + this.setRotation(this.Bout, 0.0f, 0.0f, 0.0f); + (this.Baout = new ModelRenderer((ModelBase)this, 24, 14)) + .addBox(-2.0f, 14.0f, 3.0f, 4, 4, 1); + this.Baout.setRotationPoint(0.0f, 2.0f, 0.0f); + this.Baout.setTextureSize(64, 32); + this.Baout.mirror = true; + this.setRotation(this.Baout, 0.0f, 0.0f, 0.0f); + (this.Fout = new ModelRenderer((ModelBase)this, 24, 14)) + .addBox(-2.0f, 14.0f, -4.0f, 4, 4, 1); + this.Fout.setRotationPoint(0.0f, 2.0f, 0.0f); + this.Fout.setTextureSize(64, 32); + this.Fout.mirror = true; + this.setRotation(this.Fout, 0.0f, 0.0f, 0.0f); + (this.Tout = new ModelRenderer((ModelBase)this, 24, 19)) + .addBox(-2.0f, 14.0f, -2.0f, 4, 1, 4); + this.Tout.setRotationPoint(0.0f, 0.0f, 0.0f); + this.Tout.setTextureSize(64, 32); + this.Tout.mirror = true; + this.setRotation(this.Tout, 0.0f, 0.0f, 0.0f); + (this.Core = new ModelRenderer((ModelBase)this, 0, 14)) + .addBox(-3.0f, 15.0f, -3.0f, 6, 6, 6); + this.Core.setRotationPoint(0.0f, 0.0f, 0.0f); + this.Core.setTextureSize(64, 32); + this.Core.mirror = true; + this.setRotation(this.Core, 0.0f, 0.0f, 0.0f); + (this.Movingthingright = new ModelRenderer((ModelBase)this, 46, 23)) + .addBox(-3.0f, -1.0f, -3.0f, 3, 3, 6); + this.Movingthingright.setRotationPoint(-3.0f, 20.0f, 0.0f); + this.Movingthingright.setTextureSize(64, 32); + this.Movingthingright.mirror = true; + this.setRotation(this.Movingthingright, 0.0f, 0.0f, 0.0f); + (this.Movingthingleft = new ModelRenderer((ModelBase)this, 46, 23)) + .addBox(0.0f, -1.0f, -3.0f, 3, 3, 6); + this.Movingthingleft.setRotationPoint(3.0f, 20.0f, 0.0f); + this.Movingthingleft.setTextureSize(64, 32); + this.Movingthingleft.mirror = true; + this.setRotation(this.Movingthingleft, 0.0f, 0.0f, 0.0f); + (this.bottom = new ModelRenderer((ModelBase)this, 0, 0)) + .addBox(-6.0f, 22.0f, -6.0f, 12, 2, 12); + this.bottom.setRotationPoint(0.0f, 0.0f, 0.0f); + this.bottom.setTextureSize(64, 32); + this.bottom.mirror = true; + this.setRotation(this.bottom, 0.0f, 0.0f, 0.0f); + } + + public void render(final float movement, final float f5) { + this.corner1.render(f5); + this.corner2.render(f5); + this.corner3.render(f5); + this.corner4.render(f5); + this.Bout.render(f5); + this.Baout.render(f5); + this.Fout.render(f5); + GL11.glPushMatrix(); + GL11.glRotatef(movement, 0.0f, 1.0f, 0.0f); + this.Tout.render(f5); + GL11.glPopMatrix(); + this.Core.render(f5); + this.Movingthingright.render(f5); + this.Movingthingleft.render(f5); + this.bottom.render(f5); + } + + private void setRotation(final ModelRenderer model, final float x, + final float y, final float z) { + model.rotateAngleX = x; + model.rotateAngleY = y; + model.rotateAngleZ = z; + } +} diff --git a/src/main/java/mffs/render/model/ModelCube.java b/src/main/java/mffs/render/model/ModelCube.java new file mode 100644 index 0000000..0413477 --- /dev/null +++ b/src/main/java/mffs/render/model/ModelCube.java @@ -0,0 +1,28 @@ +package mffs.render.model; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.client.model.ModelBase; +import net.minecraft.client.model.ModelRenderer; + +@SideOnly(Side.CLIENT) +public class ModelCube extends ModelBase { + public static final ModelCube INSTNACE; + private ModelRenderer cube; + + public ModelCube() { + this.cube = new ModelRenderer((ModelBase)this, 0, 0); + final int size = 16; + this.cube.addBox((float)(-size / 2), (float)(-size / 2), (float)(-size / 2), + size, size, size); + this.cube.setTextureSize(112, 70); + this.cube.mirror = true; + } + + public void render() { + final float f = 0.0625f; + this.cube.render(f); + } + + static { INSTNACE = new ModelCube(); } +} diff --git a/src/main/java/mffs/render/model/ModelForceFieldProjector.java b/src/main/java/mffs/render/model/ModelForceFieldProjector.java new file mode 100644 index 0000000..1c40217 --- /dev/null +++ b/src/main/java/mffs/render/model/ModelForceFieldProjector.java @@ -0,0 +1,237 @@ +package mffs.render.model; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.client.model.ModelBase; +import net.minecraft.client.model.ModelRenderer; +import org.lwjgl.opengl.GL11; + +@SideOnly(Side.CLIENT) +public class ModelForceFieldProjector extends ModelBase { + ModelRenderer top; + ModelRenderer axle; + ModelRenderer bottom; + ModelRenderer thingfront; + ModelRenderer thingback; + ModelRenderer thingright; + ModelRenderer thingleft; + ModelRenderer attacherbig1; + ModelRenderer attacherbig2; + ModelRenderer attachersmall3; + ModelRenderer attachersmall4; + ModelRenderer attachersmall2; + ModelRenderer attachersmall_1; + ModelRenderer corner1; + ModelRenderer corner2; + ModelRenderer corner3; + ModelRenderer corner4; + ModelRenderer lense; + ModelRenderer lensesidefront; + ModelRenderer lensesideback; + ModelRenderer lensesideright; + ModelRenderer lensesideleft; + ModelRenderer lensecorner1; + ModelRenderer lensecorner2; + ModelRenderer lensecorner3; + ModelRenderer lensecorner4; + + public ModelForceFieldProjector() { + super.textureWidth = 128; + super.textureHeight = 64; + (this.top = new ModelRenderer((ModelBase)this, 0, 0)) + .addBox(-8.0f, -4.0f, -8.0f, 16, 2, 16); + this.top.setRotationPoint(0.0f, 16.0f, 0.0f); + this.top.setTextureSize(128, 64); + this.top.mirror = true; + this.setRotation(this.top, 0.0f, 0.0f, 0.0f); + (this.axle = new ModelRenderer((ModelBase)this, 16, 26)) + .addBox(-1.0f, -2.0f, -1.0f, 2, 8, 2); + this.axle.setRotationPoint(0.0f, 16.0f, 0.0f); + this.axle.setTextureSize(128, 64); + this.axle.mirror = true; + this.setRotation(this.axle, 0.0f, 0.0f, 0.0f); + (this.bottom = new ModelRenderer((ModelBase)this, 0, 44)) + .addBox(-8.0f, 6.0f, -8.0f, 16, 2, 16); + this.bottom.setRotationPoint(0.0f, 16.0f, 0.0f); + this.bottom.setTextureSize(128, 64); + this.bottom.mirror = true; + this.setRotation(this.bottom, 0.0f, 0.0f, 0.0f); + (this.thingfront = new ModelRenderer((ModelBase)this, 0, 20)) + .addBox(-2.0f, -2.0f, -7.0f, 4, 8, 4); + this.thingfront.setRotationPoint(0.0f, 16.0f, 0.0f); + this.thingfront.setTextureSize(128, 64); + this.thingfront.mirror = true; + this.setRotation(this.thingfront, 0.0f, 0.0f, 0.0f); + (this.thingback = new ModelRenderer((ModelBase)this, 0, 20)) + .addBox(-2.0f, -2.0f, 3.0f, 4, 8, 4); + this.thingback.setRotationPoint(0.0f, 16.0f, 0.0f); + this.thingback.setTextureSize(128, 64); + this.thingback.mirror = true; + this.setRotation(this.thingback, 0.0f, 0.0f, 0.0f); + (this.thingright = new ModelRenderer((ModelBase)this, 0, 20)) + .addBox(-6.0f, -2.0f, -2.0f, 4, 8, 4); + this.thingright.setRotationPoint(0.0f, 16.0f, 0.0f); + this.thingright.setTextureSize(128, 64); + this.thingright.mirror = true; + this.setRotation(this.thingright, 0.0f, 0.0f, 0.0f); + (this.thingleft = new ModelRenderer((ModelBase)this, 0, 20)) + .addBox(2.0f, -2.0f, -2.0f, 4, 8, 4); + this.thingleft.setRotationPoint(0.0f, 16.0f, 0.0f); + this.thingleft.setTextureSize(128, 64); + this.thingleft.mirror = true; + this.setRotation(this.thingleft, 0.0f, 0.0f, 0.0f); + (this.attacherbig1 = new ModelRenderer((ModelBase)this, 16, 20)) + .addBox(-7.0f, -1.0f, -3.0f, 14, 1, 6); + this.attacherbig1.setRotationPoint(0.0f, 16.0f, 0.0f); + this.attacherbig1.setTextureSize(128, 64); + this.attacherbig1.mirror = true; + this.setRotation(this.attacherbig1, 0.0f, 0.0f, 0.0f); + (this.attacherbig2 = new ModelRenderer((ModelBase)this, 16, 20)) + .addBox(-7.0f, 4.0f, -3.0f, 14, 1, 6); + this.attacherbig2.setRotationPoint(0.0f, 16.0f, 0.0f); + this.attacherbig2.setTextureSize(128, 64); + this.attacherbig2.mirror = true; + this.setRotation(this.attacherbig2, 0.0f, 0.0f, 0.0f); + (this.attachersmall3 = new ModelRenderer((ModelBase)this, 16, 36)) + .addBox(-3.0f, -1.0f, -8.0f, 6, 1, 5); + this.attachersmall3.setRotationPoint(0.0f, 16.0f, 0.0f); + this.attachersmall3.setTextureSize(128, 64); + this.attachersmall3.mirror = true; + this.setRotation(this.attachersmall3, 0.0f, 0.0f, 0.0f); + (this.attachersmall4 = new ModelRenderer((ModelBase)this, 16, 36)) + .addBox(-3.0f, 4.0f, -8.0f, 6, 1, 5); + this.attachersmall4.setRotationPoint(0.0f, 16.0f, 0.0f); + this.attachersmall4.setTextureSize(128, 64); + this.attachersmall4.mirror = true; + this.setRotation(this.attachersmall4, 0.0f, 0.0f, 0.0f); + (this.attachersmall2 = new ModelRenderer((ModelBase)this, 16, 36)) + .addBox(-3.0f, 4.0f, 3.0f, 6, 1, 5); + this.attachersmall2.setRotationPoint(0.0f, 16.0f, 0.0f); + this.attachersmall2.setTextureSize(128, 64); + this.attachersmall2.mirror = true; + this.setRotation(this.attachersmall2, 0.0f, 0.0f, 0.0f); + (this.attachersmall_1 = new ModelRenderer((ModelBase)this, 16, 36)) + .addBox(-3.0f, -1.0f, 3.0f, 6, 1, 5); + this.attachersmall_1.setRotationPoint(0.0f, 16.0f, 0.0f); + this.attachersmall_1.setTextureSize(128, 64); + this.attachersmall_1.mirror = true; + this.setRotation(this.attachersmall_1, 0.0f, 0.0f, 0.0f); + (this.corner1 = new ModelRenderer((ModelBase)this, 38, 32)) + .addBox(6.0f, -2.0f, -8.0f, 2, 8, 2); + this.corner1.setRotationPoint(0.0f, 16.0f, 0.0f); + this.corner1.setTextureSize(128, 64); + this.corner1.mirror = true; + this.setRotation(this.corner1, 0.0f, 0.0f, 0.0f); + (this.corner2 = new ModelRenderer((ModelBase)this, 46, 32)) + .addBox(6.0f, -2.0f, 6.0f, 2, 8, 2); + this.corner2.setRotationPoint(0.0f, 16.0f, 0.0f); + this.corner2.setTextureSize(128, 64); + this.corner2.mirror = true; + this.setRotation(this.corner2, 0.0f, 0.0f, 0.0f); + (this.corner3 = new ModelRenderer((ModelBase)this, 0, 32)) + .addBox(-8.0f, -2.0f, 6.0f, 2, 8, 2); + this.corner3.setRotationPoint(0.0f, 16.0f, 0.0f); + this.corner3.setTextureSize(128, 64); + this.corner3.mirror = true; + this.setRotation(this.corner3, 0.0f, 0.0f, 0.0f); + (this.corner4 = new ModelRenderer((ModelBase)this, 8, 32)) + .addBox(-8.0f, -2.0f, -8.0f, 2, 8, 2); + this.corner4.setRotationPoint(0.0f, 16.0f, 0.0f); + this.corner4.setTextureSize(128, 64); + this.corner4.mirror = true; + this.setRotation(this.corner4, 0.0f, 0.0f, 0.0f); + (this.lense = new ModelRenderer((ModelBase)this, 96, 0)) + .addBox(-4.0f, -5.0f, -4.0f, 8, 1, 8); + this.lense.setRotationPoint(0.0f, 16.0f, 0.0f); + this.lense.setTextureSize(128, 64); + this.lense.mirror = true; + this.setRotation(this.lense, 0.0f, 0.0f, 0.0f); + (this.lensesidefront = new ModelRenderer((ModelBase)this, 64, 5)) + .addBox(-3.0f, -6.0f, -5.0f, 6, 2, 1); + this.lensesidefront.setRotationPoint(0.0f, 16.0f, 0.0f); + this.lensesidefront.setTextureSize(128, 64); + this.lensesidefront.mirror = true; + this.setRotation(this.lensesidefront, 0.0f, 0.0f, 0.0f); + (this.lensesideback = new ModelRenderer((ModelBase)this, 64, 5)) + .addBox(-3.0f, -6.0f, 4.0f, 6, 2, 1); + this.lensesideback.setRotationPoint(0.0f, 16.0f, 0.0f); + this.lensesideback.setTextureSize(128, 64); + this.lensesideback.mirror = true; + this.setRotation(this.lensesideback, 0.0f, 0.0f, 0.0f); + (this.lensesideright = new ModelRenderer((ModelBase)this, 64, 8)) + .addBox(-5.0f, -6.0f, -3.0f, 1, 2, 6); + this.lensesideright.setRotationPoint(0.0f, 16.0f, 0.0f); + this.lensesideright.setTextureSize(128, 64); + this.lensesideright.mirror = true; + this.setRotation(this.lensesideright, 0.0f, 0.0f, 0.0f); + (this.lensesideleft = new ModelRenderer((ModelBase)this, 64, 8)) + .addBox(4.0f, -6.0f, -3.0f, 1, 2, 6); + this.lensesideleft.setRotationPoint(0.0f, 16.0f, 0.0f); + this.lensesideleft.setTextureSize(128, 64); + this.lensesideleft.mirror = true; + this.setRotation(this.lensesideleft, 0.0f, 0.0f, 0.0f); + (this.lensecorner1 = new ModelRenderer((ModelBase)this, 64, 16)) + .addBox(3.0f, -6.0f, -4.0f, 1, 2, 1); + this.lensecorner1.setRotationPoint(0.0f, 16.0f, 0.0f); + this.lensecorner1.setTextureSize(128, 64); + this.lensecorner1.mirror = true; + this.setRotation(this.lensecorner1, 0.0f, 0.0f, 0.0f); + (this.lensecorner2 = new ModelRenderer((ModelBase)this, 64, 16)) + .addBox(3.0f, -6.0f, 3.0f, 1, 2, 1); + this.lensecorner2.setRotationPoint(0.0f, 16.0f, 0.0f); + this.lensecorner2.setTextureSize(128, 64); + this.lensecorner2.mirror = true; + this.setRotation(this.lensecorner2, 0.0f, 0.0f, 0.0f); + (this.lensecorner3 = new ModelRenderer((ModelBase)this, 64, 16)) + .addBox(-4.0f, -6.0f, 3.0f, 1, 2, 1); + this.lensecorner3.setRotationPoint(0.0f, 16.0f, 0.0f); + this.lensecorner3.setTextureSize(128, 64); + this.lensecorner3.mirror = true; + this.setRotation(this.lensecorner3, 0.0f, 0.0f, 0.0f); + (this.lensecorner4 = new ModelRenderer((ModelBase)this, 64, 16)) + .addBox(-4.0f, -6.0f, -4.0f, 1, 2, 1); + this.lensecorner4.setRotationPoint(0.0f, 16.0f, 0.0f); + this.lensecorner4.setTextureSize(128, 64); + this.lensecorner4.mirror = true; + this.setRotation(this.lensecorner4, 0.0f, 0.0f, 0.0f); + } + + public void render(final float rotation, final float f5) { + this.top.render(f5); + this.axle.render(f5); + this.bottom.render(f5); + GL11.glPushMatrix(); + GL11.glRotatef(rotation, 0.0f, 1.0f, 0.0f); + this.thingfront.render(f5); + this.attachersmall3.render(f5); + this.thingback.render(f5); + this.thingright.render(f5); + this.thingleft.render(f5); + this.attacherbig1.render(f5); + this.attacherbig2.render(f5); + this.attachersmall4.render(f5); + this.attachersmall2.render(f5); + this.attachersmall_1.render(f5); + GL11.glPopMatrix(); + this.corner1.render(f5); + this.corner2.render(f5); + this.corner3.render(f5); + this.corner4.render(f5); + this.lense.render(f5); + this.lensesidefront.render(f5); + this.lensesideback.render(f5); + this.lensesideright.render(f5); + this.lensesideleft.render(f5); + this.lensecorner1.render(f5); + this.lensecorner2.render(f5); + this.lensecorner3.render(f5); + this.lensecorner4.render(f5); + } + + private void setRotation(final ModelRenderer model, final float x, + final float y, final float z) { + model.rotateAngleX = x; + model.rotateAngleY = y; + model.rotateAngleZ = z; + } +} diff --git a/src/main/java/mffs/render/model/ModelForceManipulator.java b/src/main/java/mffs/render/model/ModelForceManipulator.java new file mode 100644 index 0000000..5f1cca7 --- /dev/null +++ b/src/main/java/mffs/render/model/ModelForceManipulator.java @@ -0,0 +1,94 @@ +package mffs.render.model; + +import net.minecraft.client.model.ModelBase; +import net.minecraft.client.model.ModelRenderer; + +public class ModelForceManipulator extends ModelBase { + ModelRenderer ElectrodePillar; + ModelRenderer ElectrodeBase; + ModelRenderer ElectrodeNode; + ModelRenderer WallBottom; + ModelRenderer WallFront; + ModelRenderer WallBack; + ModelRenderer WallLeft; + ModelRenderer WallRight; + ModelRenderer WallTop; + + public ModelForceManipulator() { + super.textureWidth = 128; + super.textureHeight = 128; + (this.ElectrodePillar = new ModelRenderer((ModelBase)this, 0, 32)) + .addBox(0.0f, 0.0f, 0.0f, 3, 3, 3); + this.ElectrodePillar.setRotationPoint(-1.5f, 19.0f, -1.5f); + this.ElectrodePillar.setTextureSize(128, 128); + this.ElectrodePillar.mirror = true; + this.setRotation(this.ElectrodePillar, 0.0f, 0.0f, 0.0f); + (this.ElectrodeBase = new ModelRenderer((ModelBase)this, 0, 39)) + .addBox(0.0f, 0.0f, 0.0f, 7, 2, 7); + this.ElectrodeBase.setRotationPoint(-3.5f, 21.5f, -3.5f); + this.ElectrodeBase.setTextureSize(128, 128); + this.ElectrodeBase.mirror = true; + this.setRotation(this.ElectrodeBase, 0.0f, 0.0f, 0.0f); + (this.ElectrodeNode = new ModelRenderer((ModelBase)this, 0, 49)) + .addBox(0.0f, 0.0f, 0.0f, 5, 5, 5); + this.ElectrodeNode.setRotationPoint(-2.5f, 15.0f, -2.5f); + this.ElectrodeNode.setTextureSize(128, 128); + this.ElectrodeNode.mirror = true; + this.setRotation(this.ElectrodeNode, 0.0f, 0.0f, 0.0f); + (this.WallBottom = new ModelRenderer((ModelBase)this, 0, 0)) + .addBox(0.0f, 0.0f, 0.0f, 16, 1, 16); + this.WallBottom.setRotationPoint(-8.0f, 23.0f, -8.0f); + this.WallBottom.setTextureSize(128, 128); + this.WallBottom.mirror = true; + this.setRotation(this.WallBottom, 0.0f, 0.0f, 0.0f); + (this.WallFront = new ModelRenderer((ModelBase)this, 65, 0)) + .addBox(0.0f, 0.0f, 0.0f, 16, 15, 1); + this.WallFront.setRotationPoint(-8.0f, 8.0f, -8.0f); + this.WallFront.setTextureSize(128, 128); + this.WallFront.mirror = true; + this.setRotation(this.WallFront, 0.0f, 0.0f, 0.0f); + (this.WallBack = new ModelRenderer((ModelBase)this, 65, 17)) + .addBox(0.0f, 0.0f, 0.0f, 16, 15, 1); + this.WallBack.setRotationPoint(-8.0f, 8.0f, 7.0f); + this.WallBack.setTextureSize(128, 128); + this.WallBack.mirror = true; + this.setRotation(this.WallBack, 0.0f, 0.0f, 0.0f); + (this.WallLeft = new ModelRenderer((ModelBase)this, 30, 50)) + .addBox(0.0f, 0.0f, 0.0f, 1, 15, 14); + this.WallLeft.setRotationPoint(-8.0f, 8.0f, -7.0f); + this.WallLeft.setTextureSize(128, 128); + this.WallLeft.mirror = true; + this.setRotation(this.WallLeft, 0.0f, 0.0f, 0.0f); + (this.WallRight = new ModelRenderer((ModelBase)this, 30, 19)) + .addBox(0.0f, 0.0f, 0.0f, 1, 15, 14); + this.WallRight.setRotationPoint(7.0f, 8.0f, -7.0f); + this.WallRight.setTextureSize(128, 128); + this.WallRight.mirror = true; + this.setRotation(this.WallRight, 0.0f, 0.0f, 0.0f); + (this.WallTop = new ModelRenderer((ModelBase)this, 61, 36)) + .addBox(0.0f, 0.0f, 0.0f, 14, 1, 14); + this.WallTop.setRotationPoint(-7.0f, 8.0f, -7.0f); + this.WallTop.setTextureSize(128, 128); + this.WallTop.mirror = true; + this.setRotation(this.WallTop, 0.0f, 0.0f, 0.0f); + } + + public void render(final float f5) { + this.ElectrodePillar.render(f5); + this.ElectrodeBase.render(f5); + this.ElectrodeNode.render(f5); + this.WallBottom.render(f5); + this.WallFront.render(f5); + this.WallBack.render(f5); + this.WallLeft.render(f5); + this.WallRight.render(f5); + this.WallTop.render(f5); + } + + private void setRotation(final ModelRenderer model, final float x, + final float y, final float z) { + model.rotateAngleX = x; + model.rotateAngleY = y; + model.rotateAngleZ = z; + } +} diff --git a/src/main/java/mffs/render/model/ModelFortronCapacitor.java b/src/main/java/mffs/render/model/ModelFortronCapacitor.java new file mode 100644 index 0000000..b73e1bb --- /dev/null +++ b/src/main/java/mffs/render/model/ModelFortronCapacitor.java @@ -0,0 +1,129 @@ +package mffs.render.model; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.client.model.ModelBase; +import net.minecraft.client.model.ModelRenderer; + +@SideOnly(Side.CLIENT) +public class ModelFortronCapacitor extends ModelBase { + ModelRenderer corner1; + ModelRenderer bottom; + ModelRenderer top; + ModelRenderer Rout; + ModelRenderer corner2; + ModelRenderer corner3; + ModelRenderer corner4; + ModelRenderer Bout; + ModelRenderer Baout; + ModelRenderer Fout; + ModelRenderer Lout; + ModelRenderer Core; + ModelRenderer Tout; + + public ModelFortronCapacitor() { + super.textureWidth = 64; + super.textureHeight = 32; + (this.corner1 = new ModelRenderer((ModelBase)this, 52, 0)) + .addBox(3.0f, 14.0f, 3.0f, 3, 8, 3); + this.corner1.setRotationPoint(0.0f, 0.0f, 0.0f); + this.corner1.setTextureSize(64, 32); + this.corner1.mirror = true; + this.setRotation(this.corner1, 0.0f, 0.0f, 0.0f); + (this.bottom = new ModelRenderer((ModelBase)this, 0, 0)) + .addBox(-6.0f, 22.0f, -6.0f, 12, 2, 12); + this.bottom.setRotationPoint(0.0f, 0.0f, 0.0f); + this.bottom.setTextureSize(64, 32); + this.bottom.mirror = true; + this.setRotation(this.bottom, 0.0f, 0.0f, 0.0f); + (this.top = new ModelRenderer((ModelBase)this, 0, 0)) + .addBox(-6.0f, 12.0f, -6.0f, 12, 2, 12); + this.top.setRotationPoint(0.0f, 0.0f, 0.0f); + this.top.setTextureSize(64, 32); + this.top.mirror = true; + this.setRotation(this.top, 0.0f, 0.0f, 0.0f); + (this.Rout = new ModelRenderer((ModelBase)this, 40, 14)) + .addBox(-4.0f, 14.0f, -2.0f, 1, 4, 4); + this.Rout.setRotationPoint(0.0f, 2.0f, 0.0f); + this.Rout.setTextureSize(64, 32); + this.Rout.mirror = true; + this.setRotation(this.Rout, 0.0f, 0.0f, 0.0f); + (this.corner2 = new ModelRenderer((ModelBase)this, 52, 0)) + .addBox(-6.0f, 14.0f, 3.0f, 3, 8, 3); + this.corner2.setRotationPoint(0.0f, 0.0f, 0.0f); + this.corner2.setTextureSize(64, 32); + this.corner2.mirror = true; + this.setRotation(this.corner2, 0.0f, 0.0f, 0.0f); + (this.corner3 = new ModelRenderer((ModelBase)this, 52, 0)) + .addBox(-6.0f, 14.0f, -6.0f, 3, 8, 3); + this.corner3.setRotationPoint(0.0f, 0.0f, 0.0f); + this.corner3.setTextureSize(64, 32); + this.corner3.mirror = true; + this.setRotation(this.corner3, 0.0f, 0.0f, 0.0f); + (this.corner4 = new ModelRenderer((ModelBase)this, 52, 0)) + .addBox(3.0f, 14.0f, -6.0f, 3, 8, 3); + this.corner4.setRotationPoint(0.0f, 0.0f, 0.0f); + this.corner4.setTextureSize(64, 32); + this.corner4.mirror = true; + this.setRotation(this.corner4, 0.0f, 0.0f, 0.0f); + (this.Bout = new ModelRenderer((ModelBase)this, 24, 19)) + .addBox(-2.0f, 21.0f, -2.0f, 4, 1, 4); + this.Bout.setRotationPoint(0.0f, 0.0f, 0.0f); + this.Bout.setTextureSize(64, 32); + this.Bout.mirror = true; + this.setRotation(this.Bout, 0.0f, 0.0f, 0.0f); + (this.Baout = new ModelRenderer((ModelBase)this, 24, 14)) + .addBox(-2.0f, 14.0f, 3.0f, 4, 4, 1); + this.Baout.setRotationPoint(0.0f, 2.0f, 0.0f); + this.Baout.setTextureSize(64, 32); + this.Baout.mirror = true; + this.setRotation(this.Baout, 0.0f, 0.0f, 0.0f); + (this.Fout = new ModelRenderer((ModelBase)this, 24, 14)) + .addBox(-2.0f, 14.0f, -4.0f, 4, 4, 1); + this.Fout.setRotationPoint(0.0f, 2.0f, 0.0f); + this.Fout.setTextureSize(64, 32); + this.Fout.mirror = true; + this.setRotation(this.Fout, 0.0f, 0.0f, 0.0f); + (this.Lout = new ModelRenderer((ModelBase)this, 40, 14)) + .addBox(3.0f, 14.0f, -2.0f, 1, 4, 4); + this.Lout.setRotationPoint(0.0f, 2.0f, 0.0f); + this.Lout.setTextureSize(64, 32); + this.Lout.mirror = true; + this.setRotation(this.Lout, 0.0f, 0.0f, 0.0f); + (this.Core = new ModelRenderer((ModelBase)this, 0, 14)) + .addBox(-3.0f, 15.0f, -3.0f, 6, 6, 6); + this.Core.setRotationPoint(0.0f, 0.0f, 0.0f); + this.Core.setTextureSize(64, 32); + this.Core.mirror = true; + this.setRotation(this.Core, 0.0f, 0.0f, 0.0f); + (this.Tout = new ModelRenderer((ModelBase)this, 24, 19)) + .addBox(-2.0f, 14.0f, -2.0f, 4, 1, 4); + this.Tout.setRotationPoint(0.0f, 0.0f, 0.0f); + this.Tout.setTextureSize(64, 32); + this.Tout.mirror = true; + this.setRotation(this.Tout, 0.0f, 0.0f, 0.0f); + } + + public void render(final float f5) { + this.corner1.render(f5); + this.bottom.render(f5); + this.top.render(f5); + this.Rout.render(f5); + this.corner2.render(f5); + this.corner3.render(f5); + this.corner4.render(f5); + this.Bout.render(f5); + this.Baout.render(f5); + this.Fout.render(f5); + this.Lout.render(f5); + this.Core.render(f5); + this.Tout.render(f5); + } + + private void setRotation(final ModelRenderer model, final float x, + final float y, final float z) { + model.rotateAngleX = x; + model.rotateAngleY = y; + model.rotateAngleZ = z; + } +} diff --git a/src/main/java/mffs/render/model/ModelPlane.java b/src/main/java/mffs/render/model/ModelPlane.java new file mode 100644 index 0000000..a1c6449 --- /dev/null +++ b/src/main/java/mffs/render/model/ModelPlane.java @@ -0,0 +1,28 @@ +package mffs.render.model; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.client.model.ModelBase; +import net.minecraft.client.model.ModelRenderer; + +@SideOnly(Side.CLIENT) +public class ModelPlane extends ModelBase { + public static final ModelPlane INSTNACE; + private ModelRenderer cube; + + public ModelPlane() { + this.cube = new ModelRenderer((ModelBase)this, 0, 0); + final int size = 16; + this.cube.addBox((float)(-size / 8), (float)(-size / 2), (float)(-size / 2), + size / 6, size, size); + this.cube.setTextureSize(112, 70); + this.cube.mirror = true; + } + + public void render() { + final float f = 0.0625f; + this.cube.render(f); + } + + static { INSTNACE = new ModelPlane(); } +} diff --git a/src/main/java/mffs/render/model/ModelTriangle.java b/src/main/java/mffs/render/model/ModelTriangle.java new file mode 100644 index 0000000..333594d --- /dev/null +++ b/src/main/java/mffs/render/model/ModelTriangle.java @@ -0,0 +1,28 @@ +package mffs.render.model; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.client.model.ModelBase; +import net.minecraft.client.model.ModelRenderer; + +@SideOnly(Side.CLIENT) +public class ModelTriangle extends ModelBase { + public static final ModelTriangle INSTNACE; + private ModelRenderer cube; + + public ModelTriangle() { + this.cube = new ModelRenderer((ModelBase)this, 0, 0); + final int size = 16; + this.cube.addBox((float)(-size / 8), (float)(-size / 2), (float)(-size / 2), + size / 6, size, size); + this.cube.setTextureSize(112, 70); + this.cube.mirror = true; + } + + public void render() { + final float f = 0.0625f; + this.cube.render(f); + } + + static { INSTNACE = new ModelTriangle(); } +} diff --git a/src/main/java/mffs/slot/SlotActive.java b/src/main/java/mffs/slot/SlotActive.java new file mode 100644 index 0000000..2b15294 --- /dev/null +++ b/src/main/java/mffs/slot/SlotActive.java @@ -0,0 +1,21 @@ +package mffs.slot; + +import mffs.base.TileEntityInventory; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; + +public class SlotActive extends SlotBase { + public SlotActive(final TileEntityInventory tileEntity, final int id, + final int par4, final int par5) { + super(tileEntity, id, par4, par5); + } + + @Override + public boolean isItemValid(final ItemStack itemStack) { + return super.isItemValid(itemStack) && !super.tileEntity.isActive(); + } + + public boolean canTakeStack(final EntityPlayer par1EntityPlayer) { + return !super.tileEntity.isActive(); + } +} diff --git a/src/main/java/mffs/slot/SlotBase.java b/src/main/java/mffs/slot/SlotBase.java new file mode 100644 index 0000000..36d9a29 --- /dev/null +++ b/src/main/java/mffs/slot/SlotBase.java @@ -0,0 +1,29 @@ +package mffs.slot; + +import mffs.base.TileEntityInventory; +import net.minecraft.inventory.IInventory; +import net.minecraft.inventory.Slot; +import net.minecraft.item.ItemStack; + +public class SlotBase extends Slot { + protected TileEntityInventory tileEntity; + + public SlotBase(final TileEntityInventory tileEntity, final int id, + final int par4, final int par5) { + super((IInventory)tileEntity, id, par4, par5); + this.tileEntity = tileEntity; + } + + public boolean isItemValid(final ItemStack itemStack) { + return this.tileEntity.isItemValidForSlot(super.slotNumber, itemStack); + } + + public int getSlotStackLimit() { + final ItemStack itemStack = + this.tileEntity.getStackInSlot(super.slotNumber); + if (itemStack != null) { + return itemStack.getMaxStackSize(); + } + return this.tileEntity.getInventoryStackLimit(); + } +} diff --git a/src/main/java/mffs/slot/SlotCard.java b/src/main/java/mffs/slot/SlotCard.java new file mode 100644 index 0000000..f2848cd --- /dev/null +++ b/src/main/java/mffs/slot/SlotCard.java @@ -0,0 +1,23 @@ +package mffs.slot; + +import icbm.api.IBlockFrequency; +import icbm.api.IItemFrequency; +import mffs.base.TileEntityFrequency; +import net.minecraft.item.ItemStack; + +public class SlotCard extends SlotBase { + public SlotCard(final TileEntityFrequency tileEntity, final int id, + final int par4, final int par5) { + super(tileEntity, id, par4, par5); + } + + public void onSlotChanged() { + super.onSlotChanged(); + final ItemStack itemStack = this.getStack(); + if (itemStack != null && itemStack.getItem() instanceof IItemFrequency) { + ((IItemFrequency)itemStack.getItem()) + .setFrequency(((IBlockFrequency)super.tileEntity).getFrequency(), + itemStack); + } + } +} diff --git a/src/main/java/mffs/tileentity/ManipulatorCalculationThread.java b/src/main/java/mffs/tileentity/ManipulatorCalculationThread.java new file mode 100644 index 0000000..b6cd707 --- /dev/null +++ b/src/main/java/mffs/tileentity/ManipulatorCalculationThread.java @@ -0,0 +1,47 @@ +package mffs.tileentity; + +import java.util.HashSet; +import java.util.Set; +import universalelectricity.core.vector.Vector3; + +public class ManipulatorCalculationThread extends Thread { + private TileEntityForceManipulator manipulator; + private IThreadCallBack callBack; + + public ManipulatorCalculationThread( + final TileEntityForceManipulator projector) { + this.manipulator = projector; + } + + public ManipulatorCalculationThread(final TileEntityForceManipulator + projector, + final IThreadCallBack callBack) { + this(projector); + this.callBack = callBack; + } + + @Override + public void run() { + this.manipulator.isCalculatingManipulation = true; + try { + final Set mobilizationPoints = + this.manipulator.getInteriorPoints(); + if (this.manipulator.canMove()) { + this.manipulator.manipulationVectors = new HashSet<>(); + for (final Vector3 position : mobilizationPoints) { + this.manipulator.manipulationVectors.add(position.clone()); + } + } + } catch (final Exception e) { + e.printStackTrace(); + } + this.manipulator.isCalculatingManipulation = false; + if (this.callBack != null) { + this.callBack.onThreadComplete(); + } + } + + public interface IThreadCallBack { + void onThreadComplete(); + } +} diff --git a/src/main/java/mffs/tileentity/ProjectorCalculationThread.java b/src/main/java/mffs/tileentity/ProjectorCalculationThread.java new file mode 100644 index 0000000..7956f3a --- /dev/null +++ b/src/main/java/mffs/tileentity/ProjectorCalculationThread.java @@ -0,0 +1,71 @@ +package mffs.tileentity; + +import calclavia.lib.CalculationHelper; +import java.util.Set; +import mffs.ModularForceFieldSystem; +import mffs.api.IFieldInteraction; +import mffs.api.modules.IModule; +import net.minecraft.tileentity.TileEntity; +import universalelectricity.core.vector.Vector3; + +public class ProjectorCalculationThread extends Thread { + private IFieldInteraction projector; + private IThreadCallBack callBack; + + public ProjectorCalculationThread(final IFieldInteraction projector) { + this.projector = projector; + } + + public ProjectorCalculationThread(final IFieldInteraction projector, + final IThreadCallBack callBack) { + this(projector); + this.callBack = callBack; + } + + @Override + public void run() { + this.projector.setCalculating(true); + try { + if (this.projector.getMode() != null) { + Set newField; + if (this.projector.getModuleCount( + ModularForceFieldSystem.itemModuleInvert, new int[0]) > 0) { + newField = this.projector.getMode().getInteriorPoints(this.projector); + } else { + newField = this.projector.getMode().getExteriorPoints(this.projector); + } + final Vector3 translation = this.projector.getTranslation(); + final int rotationYaw = this.projector.getRotationYaw(); + final int rotationPitch = this.projector.getRotationPitch(); + for (final Vector3 position : newField) { + if (rotationYaw != 0 || rotationPitch != 0) { + CalculationHelper.rotateByAngle(position, rotationYaw, + rotationPitch); + } + position.add(new Vector3((TileEntity)this.projector)); + position.add(translation); + if (position.intY() <= + ((TileEntity)this.projector).getWorldObj().getHeight()) { + this.projector.getCalculatedField().add(position.round()); + } + } + for (final IModule module : + this.projector.getModules(this.projector.getModuleSlots())) { + module.onCalculate(this.projector, + this.projector.getCalculatedField()); + } + } + } catch (final Exception e) { + e.printStackTrace(); + } + this.projector.setCalculating(false); + this.projector.setCalculated(true); + if (this.callBack != null) { + this.callBack.onThreadComplete(); + } + } + + public interface IThreadCallBack { + void onThreadComplete(); + } +} diff --git a/src/main/java/mffs/tileentity/TileEntityBiometricIdentifier.java b/src/main/java/mffs/tileentity/TileEntityBiometricIdentifier.java new file mode 100644 index 0000000..164cd7f --- /dev/null +++ b/src/main/java/mffs/tileentity/TileEntityBiometricIdentifier.java @@ -0,0 +1,140 @@ +package mffs.tileentity; + +import java.util.HashSet; +import java.util.Set; +import mffs.ModularForceFieldSystem; +import mffs.Settings; +import mffs.api.card.ICardIdentification; +import mffs.api.security.IBiometricIdentifier; +import mffs.api.security.Permission; +import mffs.base.PacketTile; +import mffs.base.TileEntityFrequency; +import mffs.item.card.ItemCardFrequency; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; + +public class TileEntityBiometricIdentifier + extends TileEntityFrequency implements IBiometricIdentifier { + public static final int SLOT_COPY = 12; + + @Override + public boolean isAccessGranted(final String username, + final Permission permission) { + if (!this.isActive()) { + return true; + } + if (ModularForceFieldSystem.proxy.isOp(username) && Settings.OP_OVERRIDE) { + return true; + } + for (int i = 0; i < this.getSizeInventory(); ++i) { + final ItemStack itemStack = this.getStackInSlot(i); + if (itemStack != null && + itemStack.getItem() instanceof ICardIdentification && + username.equalsIgnoreCase(((ICardIdentification)itemStack.getItem()) + .getUsername(itemStack)) && + ((ICardIdentification)itemStack.getItem()) + .hasPermission(itemStack, permission)) { + return true; + } + } + return username.equalsIgnoreCase(this.getOwner()); + } + + @Override + public void onReceivePacket(PacketTile.Type type, final NBTTagCompound nbt) { + super.onReceivePacket(type, nbt); + if (type == PacketTile.Type.TOGGLE_MODE) { + if (this.getManipulatingCard() != null) { + final ICardIdentification idCard = + (ICardIdentification)this.getManipulatingCard().getItem(); + final int id = nbt.getInteger("buttonId"); + final Permission permission = Permission.getPermission(id); + if (permission != null) { + if (!idCard.hasPermission(this.getManipulatingCard(), permission)) { + idCard.addPermission(this.getManipulatingCard(), permission); + } else { + idCard.removePermission(this.getManipulatingCard(), permission); + } + } else { + ModularForceFieldSystem.LOGGER.severe( + "Error handling security station permission packet: " + id + + " - " + permission); + } + } + } else if (type == PacketTile.Type.STRING && + this.getManipulatingCard() != null) { + final ICardIdentification idCard = + (ICardIdentification)this.getManipulatingCard().getItem(); + idCard.setUsername(this.getManipulatingCard(), nbt.getString("s")); + } + } + + @Override + public boolean isItemValidForSlot(final int slotID, + final ItemStack itemStack) { + if (slotID == 0) { + return itemStack.getItem() instanceof ItemCardFrequency; + } + return itemStack.getItem() instanceof ICardIdentification; + } + + @Override + public String getOwner() { + final ItemStack itemStack = this.getStackInSlot(2); + if (itemStack != null && itemStack.getItem() instanceof + ICardIdentification) { + return ((ICardIdentification)itemStack.getItem()).getUsername(itemStack); + } + return null; + } + + @Override + public void markDirty() { + super.markDirty(); + if (this.getManipulatingCard() != null && this.getStackInSlot(12) != null && + this.getStackInSlot(12).getItem() instanceof ICardIdentification) { + final ICardIdentification masterCard = + (ICardIdentification)this.getManipulatingCard().getItem(); + final ICardIdentification copyCard = + (ICardIdentification)this.getStackInSlot(12).getItem(); + for (final Permission permission : Permission.getPermissions()) { + if (masterCard.hasPermission(this.getManipulatingCard(), permission)) { + copyCard.addPermission(this.getStackInSlot(12), permission); + } else { + copyCard.removePermission(this.getStackInSlot(12), permission); + } + } + } + } + + @Override + public int getSizeInventory() { return 13; } + + @Override + public int getInventoryStackLimit() { + return 1; + } + + @Override + public ItemStack getManipulatingCard() { + if (this.getStackInSlot(1) != null && + this.getStackInSlot(1).getItem() instanceof ICardIdentification) { + return this.getStackInSlot(1); + } + return null; + } + + @Override + public void setActive(final boolean flag) { + if (this.getOwner() != null || !flag) { + super.setActive(flag); + } + } + + @Override + public Set getBiometricIdentifiers() { + final Set set = new HashSet<>(); + set.add(this); + return set; + } +} diff --git a/src/main/java/mffs/tileentity/TileEntityCoercionDeriver.java b/src/main/java/mffs/tileentity/TileEntityCoercionDeriver.java new file mode 100644 index 0000000..9c28110 --- /dev/null +++ b/src/main/java/mffs/tileentity/TileEntityCoercionDeriver.java @@ -0,0 +1,200 @@ +package mffs.tileentity; + +import mffs.ModularForceFieldSystem; +import mffs.Settings; +import mffs.api.modules.IModule; +import mffs.base.PacketTile; +import mffs.base.TileEntityUniversalEnergy; +import mffs.fortron.FortronHelper; +import mffs.item.card.ItemCardFrequency; +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.NetworkManager; +import net.minecraft.network.Packet; +import net.minecraft.network.play.server.S35PacketUpdateTileEntity; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidStack; +import universalelectricity.core.electricity.ElectricityPack; +import universalelectricity.core.item.ElectricItemHelper; +import universalelectricity.core.item.IItemElectric; + +public class TileEntityCoercionDeriver extends TileEntityUniversalEnergy { + public static final int WATTAGE = 1000; + public static final int REQUIRED_TIME = 200; + public static final int MULTIPLE_PRODUCTION = 4; + public static final float FORTRON_UE_RATIO = 6.0f; + public static final int SLOT_FREQUENCY = 0; + public static final int SLOT_BATTERY = 1; + public static final int SLOT_FUEL = 2; + public int processTime; + public boolean isInversed; + + public TileEntityCoercionDeriver() { + this.processTime = 0; + this.isInversed = false; + super.capacityBase = 30; + super.startModuleIndex = 3; + } + + @Override + public void updateEntity() { + super.updateEntity(); + if (!this.getWorldObj().isRemote) { + if (!this.isDisabled() && this.isActive()) { + if (this.isInversed && Settings.ENABLE_ELECTRICITY) { + final double watts = + Math.min(this.getFortronEnergy() * 6.0f, 1000.0f); + final ElectricityPack remainder = this.produce(watts); + double electricItemGiven = 0.0; + if (remainder.getWatts() > 0.0) { + electricItemGiven = ElectricItemHelper.chargeItem( + this.getStackInSlot(1), remainder.getWatts(), + this.getVoltage()); + } + this.requestFortron( + (int)((watts - (remainder.getWatts() - electricItemGiven)) / 6.0), + true); + } else { + super.wattsReceived += ElectricItemHelper.dechargeItem( + this.getStackInSlot(1), 1000.0, this.getVoltage()); + if (super.wattsReceived >= 1000.0 || + (!Settings.ENABLE_ELECTRICITY && + this.isItemValidForSlot(2, this.getStackInSlot(2)))) { + final int production = this.getProductionRate(); + super.fortronTank.fill( + FortronHelper.getFortron( + production + this.getWorldObj().rand.nextInt(production)), + true); + if (this.processTime == 0 && + this.isItemValidForSlot(2, this.getStackInSlot(2))) { + this.decrStackSize(2, 1); + this.processTime = + 200 * Math.max(this.getModuleCount( + ModularForceFieldSystem.itemModuleSpeed, + new int[0]) / + 20, + 1); + } + if (this.processTime > 0) { + --this.processTime; + if (this.processTime < 1) { + this.processTime = 0; + } + } else { + this.processTime = 0; + } + super.wattsReceived -= 1000.0; + } + } + } + } else if (this.isActive()) { + ++super.animation; + } + } + + public int getProductionRate() { + if (!this.isDisabled() && this.isActive() && !this.isInversed) { + int production = 40; + if (this.processTime > 0) { + production *= 4; + } + return production; + } + return 0; + } + + @Override + public int getSizeInventory() { + return 6; + } + + @Override + public ElectricityPack getRequest() { + if (this.canConsume()) { + return new ElectricityPack(1000.0 / this.getVoltage(), this.getVoltage()); + } + return super.getRequest(); + } + + public boolean canConsume() { + return this.isActive() && !this.isInversed && + FortronHelper.getAmount(super.fortronTank) < + super.fortronTank.getCapacity(); + } + + @Override + public Packet getDescriptionPacket() { + NBTTagCompound nbt = new NBTTagCompound(); + + nbt.setBoolean("isInversed", this.isInversed); + nbt.setDouble("wattsReceived", super.wattsReceived); + nbt.setBoolean("isActive", super.isActive); + nbt.setInteger("fortron", this.fortronTank.getFluidAmount()); + + return new S35PacketUpdateTileEntity(this.xCoord, this.yCoord, this.zCoord, + this.getBlockMetadata(), nbt); + } + + @Override + public void onDataPacket(NetworkManager arg0, + S35PacketUpdateTileEntity arg1) { + NBTTagCompound nbt = arg1.func_148857_g(); + + this.isInversed = nbt.getBoolean("isInversed"); + super.wattsReceived = nbt.getDouble("wattsReceived"); + + this.isActive = nbt.getBoolean("isActive"); + this.fortronTank.setFluid(new FluidStack(FortronHelper.FLUID_FORTRON, nbt.getInteger("fortron"))); + } + + @Override + public void onReceivePacket(PacketTile.Type type, final NBTTagCompound nbt) { + super.onReceivePacket(type, nbt); + if (type == PacketTile.Type.TOGGLE_MODE) { + this.isInversed = !this.isInversed; + } + } + + @Override + public void readFromNBT(final NBTTagCompound nbt) { + super.readFromNBT(nbt); + this.processTime = nbt.getInteger("processTime"); + this.isInversed = nbt.getBoolean("isInversed"); + } + + @Override + public void writeToNBT(final NBTTagCompound nbt) { + super.writeToNBT(nbt); + nbt.setInteger("processTime", this.processTime); + nbt.setBoolean("isInversed", this.isInversed); + } + + @Override + public boolean isItemValidForSlot(final int slotID, + final ItemStack itemStack) { + if (itemStack != null) { + if (slotID >= super.startModuleIndex) { + return itemStack.getItem() instanceof IModule; + } + switch (slotID) { + case 0: { + return itemStack.getItem() instanceof ItemCardFrequency; + } + case 1: { + return itemStack.getItem() instanceof IItemElectric; + } + case 2: { + return itemStack.isItemEqual(new ItemStack(Items.dye, 1, 4)) || + itemStack.isItemEqual(new ItemStack(Items.quartz)); + } + } + } + return false; + } + + @Override + public boolean canConnect(final ForgeDirection direction) { + return true; + } +} diff --git a/src/main/java/mffs/tileentity/TileEntityFieldInteraction.java b/src/main/java/mffs/tileentity/TileEntityFieldInteraction.java new file mode 100644 index 0000000..44d2fb0 --- /dev/null +++ b/src/main/java/mffs/tileentity/TileEntityFieldInteraction.java @@ -0,0 +1,367 @@ +package mffs.tileentity; + +import calclavia.lib.CalculationHelper; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import mffs.DelayedEvent; +import mffs.IDelayedEventHandler; +import mffs.ModularForceFieldSystem; +import mffs.Settings; +import mffs.api.ICache; +import mffs.api.IFieldInteraction; +import mffs.api.modules.IModule; +import mffs.api.modules.IProjectorMode; +import mffs.base.TileEntityModuleAcceptor; +import net.minecraft.item.ItemStack; +import net.minecraft.world.IBlockAccess; +import net.minecraftforge.common.util.ForgeDirection; +import universalelectricity.core.vector.Vector3; +import universalelectricity.core.vector.VectorHelper; + +public abstract class TileEntityFieldInteraction + extends TileEntityModuleAcceptor + implements IFieldInteraction, IDelayedEventHandler { + protected static final int MODULE_SLOT_ID = 2; + protected boolean isCalculating; + protected boolean isCalculated; + protected final Set calculatedField; + private final List delayedEvents; + private final List quedDelayedEvents; + + public TileEntityFieldInteraction() { + this.isCalculating = false; + this.isCalculated = false; + this.calculatedField = Collections.synchronizedSet(new HashSet<>()); + this.delayedEvents = new ArrayList<>(); + this.quedDelayedEvents = new ArrayList<>(); + } + + @Override + public void updateEntity() { + super.updateEntity(); + if (this.delayedEvents.size() > 0) { + do { + this.quedDelayedEvents.clear(); + final Iterator it = this.delayedEvents.iterator(); + while (it.hasNext()) { + final DelayedEvent evt = it.next(); + evt.update(); + if (evt.ticks <= 0) { + it.remove(); + } + } + this.delayedEvents.addAll(this.quedDelayedEvents); + } while (!this.quedDelayedEvents.isEmpty()); + } + } + + protected void calculateForceField( + final ProjectorCalculationThread.IThreadCallBack callBack) { + if (!this.getWorldObj().isRemote && !this.isCalculating && + this.getMode() != null) { + if (this.getModeStack().getItem() instanceof ICache) { + ((ICache)this.getModeStack().getItem()).clearCache(); + } + this.calculatedField.clear(); + new ProjectorCalculationThread(this, callBack).start(); + } + } + + protected void calculateForceField() { this.calculateForceField(null); } + + @Override + public ItemStack getModeStack() { + if (this.getStackInSlot(2) != null && this.getStackInSlot(2).getItem() + instanceof IProjectorMode) { + return this.getStackInSlot(2); + } + return null; + } + + @Override + public IProjectorMode getMode() { + if (this.getModeStack() != null) { + return (IProjectorMode)this.getModeStack().getItem(); + } + return null; + } + + @Override + public int getSidedModuleCount(final IModule module, + final ForgeDirection... direction) { + int count = 0; + if (direction != null && direction.length > 0) { + for (final ForgeDirection checkDir : direction) { + count += this.getModuleCount(module, + this.getSlotsBasedOnDirection(checkDir)); + } + } else { + for (int i = 0; i < 6; ++i) { + final ForgeDirection checkDir2 = ForgeDirection.getOrientation(i); + count += this.getModuleCount(module, + this.getSlotsBasedOnDirection(checkDir2)); + } + } + return count; + } + + @Override + public int[] getModuleSlots() { + return new int[] {15, 16, 17, 18, 19, 20}; + } + + @Override + public Vector3 getTranslation() { + final String cacheID = "getTranslation"; + if (Settings.USE_CACHE && super.cache.containsKey(cacheID) && + super.cache.get(cacheID) instanceof Vector3) { + return (Vector3) super.cache.get(cacheID); + } + ForgeDirection direction = + this.getDirection((IBlockAccess)this.getWorldObj(), this.xCoord, + this.yCoord, this.zCoord); + if (direction == ForgeDirection.UP || direction == ForgeDirection.DOWN) { + direction = ForgeDirection.NORTH; + } + final int zTranslationNeg = this.getModuleCount( + ModularForceFieldSystem.itemModuleTranslate, + this.getSlotsBasedOnDirection(VectorHelper.getOrientationFromSide( + direction, ForgeDirection.NORTH))); + final int zTranslationPos = this.getModuleCount( + ModularForceFieldSystem.itemModuleTranslate, + this.getSlotsBasedOnDirection(VectorHelper.getOrientationFromSide( + direction, ForgeDirection.SOUTH))); + final int xTranslationNeg = this.getModuleCount( + ModularForceFieldSystem.itemModuleTranslate, + this.getSlotsBasedOnDirection(VectorHelper.getOrientationFromSide( + direction, ForgeDirection.WEST))); + final int xTranslationPos = this.getModuleCount( + ModularForceFieldSystem.itemModuleTranslate, + this.getSlotsBasedOnDirection(VectorHelper.getOrientationFromSide( + direction, ForgeDirection.EAST))); + final int yTranslationPos = + this.getModuleCount(ModularForceFieldSystem.itemModuleTranslate, + this.getSlotsBasedOnDirection(ForgeDirection.UP)); + final int yTranslationNeg = + this.getModuleCount(ModularForceFieldSystem.itemModuleTranslate, + this.getSlotsBasedOnDirection(ForgeDirection.DOWN)); + final Vector3 translation = new Vector3(xTranslationPos - xTranslationNeg, + yTranslationPos - yTranslationNeg, + zTranslationPos - zTranslationNeg); + if (Settings.USE_CACHE) { + super.cache.put(cacheID, translation); + } + return translation; + } + + @Override + public Vector3 getPositiveScale() { + final String cacheID = "getPositiveScale"; + if (Settings.USE_CACHE && super.cache.containsKey(cacheID) && + super.cache.get(cacheID) instanceof Vector3) { + return (Vector3) super.cache.get(cacheID); + } + ForgeDirection direction = + this.getDirection((IBlockAccess)this.getWorldObj(), this.xCoord, + this.yCoord, this.zCoord); + if (direction == ForgeDirection.UP || direction == ForgeDirection.DOWN) { + direction = ForgeDirection.NORTH; + } + int zScalePos = this.getModuleCount( + ModularForceFieldSystem.itemModuleScale, + this.getSlotsBasedOnDirection(VectorHelper.getOrientationFromSide( + direction, ForgeDirection.SOUTH))); + int xScalePos = this.getModuleCount( + ModularForceFieldSystem.itemModuleScale, + this.getSlotsBasedOnDirection(VectorHelper.getOrientationFromSide( + direction, ForgeDirection.EAST))); + int yScalePos = + this.getModuleCount(ModularForceFieldSystem.itemModuleScale, + this.getSlotsBasedOnDirection(ForgeDirection.UP)); + final int omnidirectionalScale = this.getModuleCount( + ModularForceFieldSystem.itemModuleScale, this.getModuleSlots()); + zScalePos += omnidirectionalScale; + xScalePos += omnidirectionalScale; + yScalePos += omnidirectionalScale; + final Vector3 positiveScale = new Vector3(xScalePos, yScalePos, zScalePos); + if (Settings.USE_CACHE) { + super.cache.put(cacheID, positiveScale); + } + return positiveScale; + } + + @Override + public Vector3 getNegativeScale() { + final String cacheID = "getNegativeScale"; + if (Settings.USE_CACHE && super.cache.containsKey(cacheID) && + super.cache.get(cacheID) instanceof Vector3) { + return (Vector3) super.cache.get(cacheID); + } + ForgeDirection direction = + this.getDirection((IBlockAccess)this.getWorldObj(), this.xCoord, + this.yCoord, this.zCoord); + if (direction == ForgeDirection.UP || direction == ForgeDirection.DOWN) { + direction = ForgeDirection.NORTH; + } + int zScaleNeg = this.getModuleCount( + ModularForceFieldSystem.itemModuleScale, + this.getSlotsBasedOnDirection(VectorHelper.getOrientationFromSide( + direction, ForgeDirection.NORTH))); + int xScaleNeg = this.getModuleCount( + ModularForceFieldSystem.itemModuleScale, + this.getSlotsBasedOnDirection(VectorHelper.getOrientationFromSide( + direction, ForgeDirection.WEST))); + int yScaleNeg = + this.getModuleCount(ModularForceFieldSystem.itemModuleScale, + this.getSlotsBasedOnDirection(ForgeDirection.DOWN)); + final int omnidirectionalScale = this.getModuleCount( + ModularForceFieldSystem.itemModuleScale, this.getModuleSlots()); + zScaleNeg += omnidirectionalScale; + xScaleNeg += omnidirectionalScale; + yScaleNeg += omnidirectionalScale; + final Vector3 negativeScale = new Vector3(xScaleNeg, yScaleNeg, zScaleNeg); + if (Settings.USE_CACHE) { + super.cache.put(cacheID, negativeScale); + } + return negativeScale; + } + + @Override + public int getRotationYaw() { + final String cacheID = "getRotationYaw"; + if (Settings.USE_CACHE && super.cache.containsKey(cacheID) && + super.cache.get(cacheID) instanceof Integer) { + return (int) super.cache.get(cacheID); + } + final ForgeDirection direction = + this.getDirection((IBlockAccess)this.getWorldObj(), this.xCoord, + this.yCoord, this.zCoord); + int horizontalRotation = + this.getModuleCount( + ModularForceFieldSystem.itemModuleRotate, + this.getSlotsBasedOnDirection(VectorHelper.getOrientationFromSide( + direction, ForgeDirection.EAST))) - + this.getModuleCount( + ModularForceFieldSystem.itemModuleRotate, + this.getSlotsBasedOnDirection(VectorHelper.getOrientationFromSide( + direction, ForgeDirection.WEST))) + + this.getModuleCount( + ModularForceFieldSystem.itemModuleRotate, + this.getSlotsBasedOnDirection(VectorHelper.getOrientationFromSide( + direction, ForgeDirection.SOUTH))) - + this.getModuleCount( + ModularForceFieldSystem.itemModuleRotate, + this.getSlotsBasedOnDirection(VectorHelper.getOrientationFromSide( + direction, ForgeDirection.NORTH))); + horizontalRotation *= 2; + if (Settings.USE_CACHE) { + super.cache.put(cacheID, horizontalRotation); + } + return horizontalRotation; + } + + @Override + public int getRotationPitch() { + final String cacheID = "getRotationPitch"; + if (Settings.USE_CACHE && super.cache.containsKey(cacheID) && + super.cache.get(cacheID) instanceof Integer) { + return (int) super.cache.get(cacheID); + } + int verticleRotation = + this.getModuleCount(ModularForceFieldSystem.itemModuleRotate, + this.getSlotsBasedOnDirection(ForgeDirection.UP)) - + this.getModuleCount(ModularForceFieldSystem.itemModuleRotate, + this.getSlotsBasedOnDirection(ForgeDirection.DOWN)); + verticleRotation *= 2; + if (Settings.USE_CACHE) { + super.cache.put(cacheID, verticleRotation); + } + return verticleRotation; + } + + @Override + public Set getInteriorPoints() { + if (Settings.USE_CACHE && super.cache.containsKey("getInteriorPoints") && + super.cache.get("getInteriorPoints") instanceof Set) { + return (Set) super.cache.get("getInteriorPoints"); + } + if (this.getModeStack().getItem() instanceof ICache) { + ((ICache)this.getModeStack().getItem()).clearCache(); + } + final Set newField = this.getMode().getInteriorPoints(this); + final Set returnField = new HashSet<>(); + final Vector3 translation = this.getTranslation(); + final int rotationYaw = this.getRotationYaw(); + final int rotationPitch = this.getRotationPitch(); + for (final Vector3 position : newField) { + final Vector3 newPosition = position.clone(); + if (rotationYaw != 0 || rotationPitch != 0) { + CalculationHelper.rotateByAngle(newPosition, rotationYaw, + rotationPitch); + } + newPosition.add(new Vector3(this)); + newPosition.add(translation); + returnField.add(newPosition); + } + if (Settings.USE_CACHE) { + super.cache.put("getInteriorPoints", returnField); + } + return returnField; + } + + @Override + public int[] getSlotsBasedOnDirection(final ForgeDirection direction) { + switch (direction) { + default: { + return new int[0]; + } + case UP: { + return new int[] {3, 11}; + } + case DOWN: { + return new int[] {6, 14}; + } + case NORTH: { + return new int[] {8, 10}; + } + case SOUTH: { + return new int[] {7, 9}; + } + case WEST: { + return new int[] {4, 5}; + } + case EAST: { + return new int[] {12, 13}; + } + } + } + + @Override + public void setCalculating(final boolean bool) { + this.isCalculating = bool; + } + + @Override + public void setCalculated(final boolean bool) { + this.isCalculated = bool; + } + + @Override + public Set getCalculatedField() { + return this.calculatedField; + } + + @Override + public List getDelayedEvents() { + return this.delayedEvents; + } + + @Override + public List getQuedDelayedEvents() { + return this.quedDelayedEvents; + } +} diff --git a/src/main/java/mffs/tileentity/TileEntityForceField.java b/src/main/java/mffs/tileentity/TileEntityForceField.java new file mode 100644 index 0000000..5e952af --- /dev/null +++ b/src/main/java/mffs/tileentity/TileEntityForceField.java @@ -0,0 +1,107 @@ +package mffs.tileentity; + +import mffs.MFFSHelper; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.NetworkManager; +import net.minecraft.network.Packet; +import net.minecraft.network.play.server.S35PacketUpdateTileEntity; +import net.minecraft.world.IBlockAccess; +import universalelectricity.core.vector.Vector3; +import universalelectricity.prefab.tile.TileEntityAdvanced; + +public class TileEntityForceField extends TileEntityAdvanced { + private Vector3 projector; + public ItemStack camoStack; + + public TileEntityForceField() { + this.projector = null; + this.camoStack = null; + } + + public boolean canUpdate() { return false; } + + @Override + public Packet getDescriptionPacket() { + if (this.getProjector() != null) { + NBTTagCompound nbt = new NBTTagCompound(); + + if (this.camoStack != null) { + nbt.setTag("projector", + this.projector.writeToNBT(new NBTTagCompound())); + nbt.setInteger("itemID", Item.getIdFromItem(this.camoStack.getItem())); + nbt.setInteger("itemMetadata", this.camoStack.getItemDamage()); + } + return new S35PacketUpdateTileEntity( + this.xCoord, this.yCoord, this.zCoord, this.getBlockMetadata(), nbt); + } + return null; + } + + @Override + public void onDataPacket(NetworkManager arg0, + S35PacketUpdateTileEntity arg1) { + NBTTagCompound nbt = arg1.func_148857_g(); + + this.setProjector(Vector3.readFromNBT(nbt.getCompoundTag("projector"))); + if (nbt.hasKey("itemID") && nbt.hasKey("itemMetadata")) { + this.camoStack = new ItemStack(Item.getItemById(nbt.getInteger("itemID")), + 1, nbt.getInteger("itemMetadata")); + } + this.getWorldObj().markBlockRangeForRenderUpdate(this.xCoord, this.yCoord, + this.zCoord, this.xCoord, + this.yCoord, this.zCoord); + } + + public void setProjector(final Vector3 position) { + this.projector = position; + if (!this.getWorldObj().isRemote) { + this.refreshCamoBlock(); + } + } + + public TileEntityForceFieldProjector getProjector() { + if (this.getProjectorSafe() != null) { + return this.getProjectorSafe(); + } + if (!this.getWorldObj().isRemote) { + this.getWorldObj().setBlockToAir(this.xCoord, this.yCoord, this.zCoord); + } + return null; + } + + public TileEntityForceFieldProjector getProjectorSafe() { + if (this.projector != null && + this.projector.getTileEntity((IBlockAccess)this.getWorldObj()) + instanceof TileEntityForceFieldProjector && + (this.getWorldObj().isRemote || + ((TileEntityForceFieldProjector)this.projector.getTileEntity( + (IBlockAccess)this.getWorldObj())) + .getCalculatedField() + .contains(new Vector3(this)))) { + return (TileEntityForceFieldProjector)this.projector.getTileEntity( + (IBlockAccess)this.getWorldObj()); + } + return null; + } + + public void refreshCamoBlock() { + if (this.getProjectorSafe() != null) { + this.camoStack = + MFFSHelper.getCamoBlock(this.getProjector(), new Vector3(this)); + } + } + + public void readFromNBT(final NBTTagCompound nbt) { + super.readFromNBT(nbt); + this.projector = Vector3.readFromNBT(nbt.getCompoundTag("projector")); + } + + public void writeToNBT(final NBTTagCompound nbt) { + super.writeToNBT(nbt); + if (this.getProjector() != null) { + nbt.setTag("projector", this.projector.writeToNBT(new NBTTagCompound())); + } + } +} diff --git a/src/main/java/mffs/tileentity/TileEntityForceFieldProjector.java b/src/main/java/mffs/tileentity/TileEntityForceFieldProjector.java new file mode 100644 index 0000000..bbcf623 --- /dev/null +++ b/src/main/java/mffs/tileentity/TileEntityForceFieldProjector.java @@ -0,0 +1,272 @@ +package mffs.tileentity; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import java.util.HashSet; +import java.util.Set; +import mffs.ModularForceFieldSystem; +import mffs.Settings; +import mffs.api.ICache; +import mffs.api.IProjector; +import mffs.api.modules.IModule; +import mffs.api.modules.IProjectorMode; +import mffs.block.BlockForceField; +import mffs.card.ItemCard; +import net.minecraft.block.Block; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.world.IBlockAccess; +import universalelectricity.core.vector.Vector3; + +public class TileEntityForceFieldProjector extends TileEntityFieldInteraction + implements IProjector, ProjectorCalculationThread.IThreadCallBack { + protected final Set forceFields; + + public TileEntityForceFieldProjector() { + this.forceFields = new HashSet<>(); + super.capacityBase = 50; + super.startModuleIndex = 1; + } + + @Override + public void initiate() { + super.initiate(); + this.calculateForceField(); + } + + @Override + public void onFxsPacket(NBTTagCompound data) { + Vector3 otherPos = Vector3.readFromNBT(data); + int type = data.getInteger("type"); + + Vector3 vector = otherPos.add(0.5); + final Vector3 root = new Vector3(this).add(0.5); + if (type == 1) { + ModularForceFieldSystem.proxy.renderBeam(this.getWorldObj(), root, vector, + 0.6f, 0.6f, 1.0f, 40); + ModularForceFieldSystem.proxy.renderHologramMoving( + this.getWorldObj(), vector, 1.0f, 1.0f, 1.0f, 50); + } else if (type == 2) { + ModularForceFieldSystem.proxy.renderBeam(this.getWorldObj(), vector, root, + 1.0f, 0.0f, 0.0f, 40); + ModularForceFieldSystem.proxy.renderHologramMoving( + this.getWorldObj(), vector, 1.0f, 0.0f, 0.0f, 50); + } + } + + @Override + protected void calculateForceField( + final ProjectorCalculationThread.IThreadCallBack callBack) { + if (!this.getWorldObj().isRemote && !super.isCalculating && + this.getMode() != null) { + this.forceFields.clear(); + } + super.calculateForceField(callBack); + } + + @Override + public void onThreadComplete() { + this.destroyField(); + } + + @Override + public void updateEntity() { + super.updateEntity(); + if (this.isActive() && this.getMode() != null && + this.requestFortron(this.getFortronCost(), false) >= this.getFortronCost()) { + this.consumeCost(); + if (!this.getWorldObj().isRemote) { + if (super.ticks % 10L == 0L) { + if (!super.isCalculated) { + this.calculateForceField(); + } else { + this.projectField(); + } + } + } else if (this.isActive()) { + super.animation += this.getFortronCost() / 3; + } + if (super.ticks % 40L == 0L && + this.getModuleCount(ModularForceFieldSystem.itemModuleSilence, + new int[0]) <= 0) { + this.getWorldObj().playSoundEffect( + this.xCoord + 0.5, this.yCoord + 0.5, this.zCoord + 0.5, + "mffs:field", 0.6f, + 1.0f - this.getWorldObj().rand.nextFloat() * 0.1f); + } + } else if (!this.getWorldObj().isRemote) { + this.destroyField(); + } + } + + @Override + public int getFortronCost() { + return super.getFortronCost() + 5; + } + + @Override + public float getAmplifier() { + return (float) Math.max( + Math.min(this.getCalculatedField().size() / 1000, 10), 1); + } + + @Override + public void markDirty() { + super.markDirty(); + this.destroyField(); + } + + @Override + public void projectField() { + Label_0636: { + if (!this.getWorldObj().isRemote && super.isCalculated && + !super.isCalculating) { + if (this.forceFields.size() <= 0 && this.getModeStack().getItem() instanceof ICache) { + ((ICache) this.getModeStack().getItem()).clearCache(); + } + int constructionCount = 0; + final int constructionSpeed = Math.min( + this.getProjectionSpeed(), Settings.MAX_FORCE_FIELDS_PER_TICK); + final HashSet fieldToBeProjected = new HashSet<>(); + fieldToBeProjected.addAll(super.calculatedField); + for (final IModule module : this.getModules(this.getModuleSlots())) { + if (module.onProject(this, fieldToBeProjected)) { + return; + } + } + Label_0158: for (final Vector3 vector : super.calculatedField) { + if (fieldToBeProjected.contains(vector)) { + if (constructionCount > constructionSpeed) { + break; + } + final Block block = vector.getBlock((IBlockAccess) this.getWorldObj()); + if ((block != null && + (this.getModuleCount( + ModularForceFieldSystem.itemModuleDisintegration, + new int[0]) <= 0 || + block.getBlockHardness(this.getWorldObj(), vector.intX(), + vector.intY(), + vector.intZ()) == -1.0f) + && + !block.getMaterial().isLiquid() && block != Blocks.snow && + block != Blocks.vine && block != Blocks.tallgrass && + block != Blocks.deadbush && + !block.isReplaceable(this.getWorldObj(), vector.intX(), + vector.intY(), vector.intZ())) + || + block == ModularForceFieldSystem.blockForceField || + vector.equals(new Vector3(this)) || + !this.getWorldObj() + .getChunkFromBlockCoords(vector.intX(), vector.intZ()).isChunkLoaded) { + continue; + } + for (final IModule module2 : this.getModules(this.getModuleSlots())) { + final int flag = module2.onProject(this, vector.clone()); + if (flag == 1) { + continue Label_0158; + } + if (flag == 2) { + break Label_0636; + } + } + this.getWorldObj().setBlock( + vector.intX(), vector.intY(), vector.intZ(), + ModularForceFieldSystem.blockForceField, 0, 2); + final TileEntity tileEntity = this.getWorldObj().getTileEntity( + vector.intX(), vector.intY(), vector.intZ()); + if (tileEntity instanceof TileEntityForceField) { + ((TileEntityForceField) tileEntity).setProjector(new Vector3(this)); + } + this.requestFortron(1, true); + this.forceFields.add(vector); + ++constructionCount; + } else { + final Block block = vector.getBlock((IBlockAccess) this.getWorldObj()); + if (block != ModularForceFieldSystem.blockForceField || + ((BlockForceField) block) + .getProjector((IBlockAccess) this.getWorldObj(), + vector.intX(), vector.intY(), + vector.intZ()) != this) { + continue; + } + this.getWorldObj().setBlockToAir(vector.intX(), vector.intY(), + vector.intZ()); + } + } + } + } + } + + @Override + public void destroyField() { + if (!this.getWorldObj().isRemote && super.isCalculated && + !super.isCalculating) { + final HashSet copiedSet = new HashSet<>(); + copiedSet.addAll(super.calculatedField); + for (final Vector3 vector : copiedSet) { + final Block block = vector.getBlock((IBlockAccess) this.getWorldObj()); + if (block == ModularForceFieldSystem.blockForceField) { + this.getWorldObj().setBlock(vector.intX(), vector.intY(), + vector.intZ(), Blocks.air, 0, 3); + } + } + } + this.forceFields.clear(); + super.calculatedField.clear(); + super.isCalculated = false; + } + + @Override + public void invalidate() { + this.destroyField(); + super.invalidate(); + } + + @Override + public int getProjectionSpeed() { + return 28 + + 28 * this.getModuleCount(ModularForceFieldSystem.itemModuleSpeed, + this.getModuleSlots()); + } + + @Override + public int getSizeInventory() { + return 21; + } + + @Override + public boolean isItemValidForSlot(final int slotID, + final ItemStack itemStack) { + if (slotID == 0 || slotID == 1) { + return itemStack.getItem() instanceof ItemCard; + } + if (slotID == 2) { + return itemStack.getItem() instanceof IProjectorMode; + } + return slotID >= 15 || itemStack.getItem() instanceof IModule; + } + + @Override + public Set getCards() { + final Set cards = new HashSet<>(); + cards.add(super.getCard()); + cards.add(this.getStackInSlot(1)); + return cards; + } + + @SideOnly(Side.CLIENT) + public AxisAlignedBB getRenderBoundingBox() { + return AxisAlignedBB.getBoundingBox( + (double) this.xCoord, (double) this.yCoord, (double) this.zCoord, + (double) (this.xCoord + 1), (double) (this.yCoord + 2), + (double) (this.zCoord + 1)); + } + + @Override + public long getTicks() { + return super.ticks; + } +} diff --git a/src/main/java/mffs/tileentity/TileEntityForceManipulator.java b/src/main/java/mffs/tileentity/TileEntityForceManipulator.java new file mode 100644 index 0000000..f9b6550 --- /dev/null +++ b/src/main/java/mffs/tileentity/TileEntityForceManipulator.java @@ -0,0 +1,381 @@ +package mffs.tileentity; + +import dan200.computercraft.api.lua.ILuaContext; +import dan200.computercraft.api.lua.LuaException; +import dan200.computercraft.api.peripheral.IComputerAccess; +import java.util.List; +import java.util.Set; +import mffs.ModularForceFieldSystem; +import mffs.Settings; +import mffs.api.Blacklist; +import mffs.api.ISpecialForceManipulation; +import mffs.api.modules.IModule; +import mffs.api.modules.IProjectorMode; +import mffs.base.PacketFxs; +import mffs.base.PacketTile; +import mffs.card.ItemCard; +import mffs.event.BlockPreMoveDelayedEvent; +import mffs.fortron.FortronHelper; +import net.minecraft.block.Block; +import net.minecraft.block.BlockLiquid; +import net.minecraft.entity.Entity; +import net.minecraft.init.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTBase; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.nbt.NBTTagList; +import net.minecraft.network.NetworkManager; +import net.minecraft.network.Packet; +import net.minecraft.network.play.server.S35PacketUpdateTileEntity; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.world.IBlockAccess; +import net.minecraftforge.common.util.ForgeDirection; +import net.minecraftforge.fluids.FluidStack; +import universalelectricity.core.vector.Vector3; + +public class TileEntityForceManipulator extends TileEntityFieldInteraction { + public static final int ANIMATION_TIME = 20; + public Vector3 anchor; + public int displayMode; + public boolean isCalculatingManipulation; + public Set manipulationVectors; + public boolean doAnchor; + + public TileEntityForceManipulator() { + this.anchor = null; + this.displayMode = 1; + this.isCalculatingManipulation = false; + this.manipulationVectors = null; + this.doAnchor = true; + } + + @Override + public void updateEntity() { + super.updateEntity(); + if (this.anchor == null) { + this.anchor = new Vector3(); + } + if (this.getMode() != null && Settings.ENABLE_MANIPULATOR) { + if (!this.getWorldObj().isRemote && this.manipulationVectors != null && + !this.isCalculatingManipulation) { + final ForgeDirection dir = this.getDirection((IBlockAccess) this.getWorldObj(), this.xCoord, + this.yCoord, this.zCoord); + final NBTTagCompound nbt = new NBTTagCompound(); + final NBTTagList nbtList = new NBTTagList(); + int i = 0; + for (final Vector3 position : this.manipulationVectors) { + if (this.moveBlock(position, dir) && this.isBlockVisible(position) && + i < Settings.MAX_FORCE_FIELDS_PER_TICK) { + nbtList.appendTag( + (NBTBase) position.writeToNBT(new NBTTagCompound())); + ++i; + } + } + nbt.setByte("type", (byte) 2); + nbt.setTag("list", (NBTBase) nbtList); + ModularForceFieldSystem.channel.sendToAll( + new PacketFxs(new Vector3(this), nbt)); + if (this.doAnchor) { + this.anchor = this.anchor.modifyPositionFromSide(dir); + } + this.updatePushedObjects(0.022f); + this.manipulationVectors = null; + this.markDirty(); + } + if (this.isActive() && super.ticks % 20L == 0L && + this.requestFortron(this.getFortronCost(), false) > 0) { + if (!this.getWorldObj().isRemote) { + this.requestFortron(this.getFortronCost(), true); + new ManipulatorCalculationThread(this).start(); + } + if (this.getModuleCount(ModularForceFieldSystem.itemModuleSilence, + new int[0]) <= 0) { + this.getWorldObj().playSoundEffect( + this.xCoord + 0.5, this.yCoord + 0.5, this.zCoord + 0.5, + "mffs:fieldmove", 0.6f, + 1.0f - this.getWorldObj().rand.nextFloat() * 0.1f); + } + this.setActive(false); + } + if (!this.getWorldObj().isRemote) { + if (!super.isCalculated) { + this.calculateForceField(); + } + if (super.ticks % 120L == 0L && !super.isCalculating && + Settings.HIGH_GRAPHICS && this.getDelayedEvents().size() <= 0 && + this.displayMode > 0) { + final NBTTagCompound nbt2 = new NBTTagCompound(); + final NBTTagList nbtList2 = new NBTTagList(); + int j = 0; + for (final Vector3 position2 : this.getInteriorPoints()) { + if (this.isBlockVisible(position2) && + (this.displayMode == 2 || + position2.getBlock((IBlockAccess) this.getWorldObj()) != Blocks.air) + && + j < Settings.MAX_FORCE_FIELDS_PER_TICK) { + nbtList2.appendTag( + (NBTBase) position2.writeToNBT(new NBTTagCompound())); + ++j; + } + } + nbt2.setByte("type", (byte) 1); + nbt2.setTag("list", (NBTBase) nbtList2); + + ModularForceFieldSystem.channel.sendToAll( + new PacketFxs(new Vector3(this), nbt2)); + } + } + } + } + + public boolean isBlockVisible(final Vector3 position) { + int i = 0; + for (final ForgeDirection direction : ForgeDirection.VALID_DIRECTIONS) { + final Vector3 checkPos = position.clone().modifyPositionFromSide(direction); + final Block block = checkPos.getBlock((IBlockAccess) this.getWorldObj()); + if (block != Blocks.air && block.isOpaqueCube()) { + ++i; + } + } + return i < ForgeDirection.VALID_DIRECTIONS.length; + } + + @Override + public void onFxsPacket(NBTTagCompound nbt) { + final byte type = nbt.getByte("type"); + final NBTTagList nbtList = (NBTTagList) nbt.getTag("list"); + for (int i = 0; i < nbtList.tagCount(); ++i) { + final Vector3 vector = Vector3.readFromNBT(nbtList.getCompoundTagAt(i)).add(0.5); + if (type == 1) { + ModularForceFieldSystem.proxy.renderHologram( + this.getWorldObj(), vector, 1.0f, 1.0f, 1.0f, 30, + vector.clone().modifyPositionFromSide( + this.getDirection((IBlockAccess) this.getWorldObj(), this.xCoord, + this.yCoord, this.zCoord))); + } else if (type == 2) { + ModularForceFieldSystem.proxy.renderHologram( + this.getWorldObj(), vector, 1.0f, 0.0f, 0.0f, 30, + vector.clone().modifyPositionFromSide( + this.getDirection((IBlockAccess) this.getWorldObj(), this.xCoord, + this.yCoord, this.zCoord))); + this.updatePushedObjects(0.022f); + } + } + } + + @Override + public void onReceivePacket(PacketTile.Type type, + final NBTTagCompound dataStream) { + super.onReceivePacket(type, dataStream); + if (type == PacketTile.Type.TOGGLE_MODE && !this.getWorldObj().isRemote) { + switch (dataStream.getInteger("buttonId")) { + case 1: + this.anchor = null; + this.markDirty(); + break; + + case 2: + this.displayMode = (this.displayMode + 1) % 3; + break; + + case 3: + this.doAnchor = !this.doAnchor; + break; + default: + break; + } + } + } + + @Override + public int getFortronCost() { + return (int) ((super.getFortronCost() + this.anchor.getMagnitude()) * + 1000.0); + } + + @Override + public void markDirty() { + super.markDirty(); + super.isCalculated = false; + } + + protected boolean canMove() { + final Set mobilizationPoints = this.getInteriorPoints(); + final ForgeDirection dir = this.getDirection((IBlockAccess) this.getWorldObj(), this.xCoord, + this.yCoord, this.zCoord); + Label_0033: for (final Vector3 position : mobilizationPoints) { + if (position.getBlock((IBlockAccess) this.getWorldObj()) != Blocks.air) { + if (Blacklist.forceManipulationBlacklist.contains( + position.getBlock((IBlockAccess) this.getWorldObj()))) { + return false; + } + final TileEntity tileEntity = position.getTileEntity((IBlockAccess) this.getWorldObj()); + if (tileEntity instanceof ISpecialForceManipulation && + !((ISpecialForceManipulation) tileEntity) + .preMove(position.intX(), position.intY(), position.intZ())) { + return false; + } + final Vector3 targetPosition = position.clone().modifyPositionFromSide(dir); + if (targetPosition.getTileEntity((IBlockAccess) this.getWorldObj()) == this) { + return false; + } + for (final Vector3 checkPos : mobilizationPoints) { + if (checkPos.equals(targetPosition)) { + continue Label_0033; + } + } + final Block blockID = targetPosition.getBlock((IBlockAccess) this.getWorldObj()); + if (blockID != Blocks.air && + (!blockID.isReplaceable(this.getWorldObj(), targetPosition.intX(), + targetPosition.intY(), + targetPosition.intZ()) && + !(blockID instanceof BlockLiquid))) { + return false; + } + continue; + } + } + return true; + } + + protected boolean moveBlock(final Vector3 position, + final ForgeDirection direction) { + if (!this.getWorldObj().isRemote) { + final Vector3 newPosition = position.clone().modifyPositionFromSide(direction); + final TileEntity tileEntity = position.getTileEntity((IBlockAccess) this.getWorldObj()); + final Block blockID = position.getBlock((IBlockAccess) this.getWorldObj()); + if (blockID != Blocks.air && tileEntity != this) { + this.getDelayedEvents().add(new BlockPreMoveDelayedEvent( + this, 20, this.getWorldObj(), position, newPosition)); + return true; + } + } + return false; + } + + public void updatePushedObjects(final float amount) { + final ForgeDirection dir = this.getDirection((IBlockAccess) this.getWorldObj(), this.xCoord, + this.yCoord, this.zCoord); + final AxisAlignedBB axisalignedbb = this.getSearchAxisAlignedBB(); + if (axisalignedbb != null) { + final List entities = this.getWorldObj().getEntitiesWithinAABB(Entity.class, axisalignedbb); + for (final Entity entity : entities) { + entity.addVelocity((double) (amount * dir.offsetX), + (double) (amount * dir.offsetY), + (double) (amount * dir.offsetZ)); + } + } + } + + public AxisAlignedBB getSearchAxisAlignedBB() { + final Vector3 positiveScale = new Vector3(this) + .add(this.getTranslation()) + .add(this.getPositiveScale()); + final Vector3 negativeScale = new Vector3(this) + .add(this.getTranslation()) + .subtract(this.getNegativeScale()); + final Vector3 minScale = new Vector3(Math.min(positiveScale.x, negativeScale.x), + Math.min(positiveScale.y, negativeScale.y), + Math.min(positiveScale.z, negativeScale.z)); + final Vector3 maxScale = new Vector3(Math.max(positiveScale.x, negativeScale.x), + Math.max(positiveScale.y, negativeScale.y), + Math.max(positiveScale.z, negativeScale.z)); + return AxisAlignedBB.getBoundingBox( + (double) minScale.intX(), (double) minScale.intY(), + (double) minScale.intZ(), (double) maxScale.intX(), + (double) maxScale.intY(), (double) maxScale.intZ()); + } + + @Override + public boolean isItemValidForSlot(final int slotID, + final ItemStack itemStack) { + if (slotID == 0 || slotID == 1) { + return itemStack.getItem() instanceof ItemCard; + } + if (slotID == 2) { + return itemStack.getItem() instanceof IProjectorMode; + } + return slotID >= 15 || itemStack.getItem() instanceof IModule; + } + + @Override + public void readFromNBT(final NBTTagCompound nbt) { + super.readFromNBT(nbt); + this.anchor = Vector3.readFromNBT(nbt.getCompoundTag("anchor")); + this.displayMode = nbt.getInteger("displayMode"); + this.doAnchor = nbt.getBoolean("doAnchor"); + } + + @Override + public void writeToNBT(final NBTTagCompound nbt) { + super.writeToNBT(nbt); + if (this.anchor != null) { + nbt.setTag("anchor", this.anchor.writeToNBT(new NBTTagCompound())); + } + nbt.setInteger("displayMode", this.displayMode); + nbt.setBoolean("doAnchor", this.doAnchor); + } + + @Override + public Vector3 getTranslation() { + return super.getTranslation().clone().add(this.anchor); + } + + @Override + public int getSizeInventory() { + return 21; + } + + @Override + public String[] getMethodNames() { + return new String[] { "isActivate", "setActivate", "resetAnchor" }; + } + + @Override + public Object[] callMethod(IComputerAccess computer, ILuaContext context, + int method, Object[] arguments) + throws LuaException, InterruptedException { + switch (method) { + case 0: + case 1: + return super.callMethod(computer, context, method, arguments); + + case 2: + this.anchor = null; + return null; + + default: + return null; + } + } + + @Override + public Packet getDescriptionPacket() { + NBTTagCompound nbt = new NBTTagCompound(); + + nbt.setBoolean("isActive", this.isActive); + nbt.setInteger("fortron", this.fortronTank.getFluidAmount()); + if (this.anchor != null) { + nbt.setTag("anchor", this.anchor.writeToNBT(new NBTTagCompound())); + } + nbt.setInteger("displayMode", this.displayMode); + nbt.setBoolean("doAnchor", this.doAnchor); + + return new S35PacketUpdateTileEntity(this.xCoord, this.yCoord, this.zCoord, + this.getBlockMetadata(), nbt); + } + + @Override + public void onDataPacket(NetworkManager arg0, S35PacketUpdateTileEntity arg1) { + NBTTagCompound nbt = arg1.func_148857_g(); + + this.isActive = nbt.getBoolean("isActive"); + this.fortronTank.setFluid(new FluidStack(FortronHelper.FLUID_FORTRON, nbt.getInteger("fortron"))); + if (nbt.hasKey("anchor")) { + this.anchor = Vector3.readFromNBT(nbt.getCompoundTag("anchor")); + } + this.displayMode = nbt.getInteger("displayMode"); + this.doAnchor = nbt.getBoolean("doAnchor"); + } +} diff --git a/src/main/java/mffs/tileentity/TileEntityFortronCapacitor.java b/src/main/java/mffs/tileentity/TileEntityFortronCapacitor.java new file mode 100644 index 0000000..be6431e --- /dev/null +++ b/src/main/java/mffs/tileentity/TileEntityFortronCapacitor.java @@ -0,0 +1,164 @@ +package mffs.tileentity; + +import icbm.api.IBlockFrequency; +import java.util.HashSet; +import java.util.Set; +import mffs.MFFSHelper; +import mffs.ModularForceFieldSystem; +import mffs.TransferMode; +import mffs.api.card.ICard; +import mffs.api.card.ICardInfinite; +import mffs.api.card.ICardLink; +import mffs.api.fortron.IFortronCapacitor; +import mffs.api.fortron.IFortronFrequency; +import mffs.api.modules.IModule; +import mffs.base.PacketTile; +import mffs.base.TileEntityModuleAcceptor; +import mffs.fortron.FortronHelper; +import mffs.fortron.FrequencyGrid; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.NetworkManager; +import net.minecraft.network.Packet; +import net.minecraft.network.play.server.S35PacketUpdateTileEntity; +import net.minecraft.world.IBlockAccess; +import net.minecraftforge.fluids.FluidStack; +import universalelectricity.core.vector.Vector3; + +public class TileEntityFortronCapacitor + extends TileEntityModuleAcceptor implements IFortronCapacitor { + private TransferMode transferMode; + + public TileEntityFortronCapacitor() { + this.transferMode = TransferMode.EQUALIZE; + super.capacityBase = 700; + super.capacityBoost = 10; + super.startModuleIndex = 2; + } + + @Override + public void updateEntity() { + super.updateEntity(); + this.consumeCost(); + if (!this.isDisabled() && this.isActive() && super.ticks % 10L == 0L) { + Set machines = new HashSet<>(); + for (final ItemStack itemStack : this.getCards()) { + if (itemStack != null) { + if (itemStack.getItem() instanceof ICardInfinite) { + this.setFortronEnergy(this.getFortronCapacity()); + } else { + if (!(itemStack.getItem() instanceof ICardLink)) { + continue; + } + final Vector3 linkPosition = + ((ICardLink)itemStack.getItem()).getLink(itemStack); + if (linkPosition == null || + !(linkPosition.getTileEntity((IBlockAccess)this.getWorldObj()) + instanceof IFortronFrequency)) { + continue; + } + machines.add(this); + machines.add((IFortronFrequency)linkPosition.getTileEntity( + (IBlockAccess)this.getWorldObj())); + } + } + } + if (machines.size() < 1) { + machines = this.getLinkedDevices(); + } + MFFSHelper.transferFortron(this, machines, this.transferMode, + this.getTransmissionRate()); + } + } + + public float getAmplifier() { return 0.001f; } + + @Override + public Packet getDescriptionPacket() { + NBTTagCompound nbt = new NBTTagCompound(); + + nbt.setInteger("transferMode", this.transferMode.ordinal()); + nbt.setBoolean("isActive", this.isActive); + nbt.setInteger("fortron", this.fortronTank.getFluidAmount()); + + return new S35PacketUpdateTileEntity(this.xCoord, this.yCoord, this.zCoord, + this.getBlockMetadata(), nbt); + } + + @Override + public void onDataPacket(NetworkManager arg0, + S35PacketUpdateTileEntity arg1) { + NBTTagCompound nbt = arg1.func_148857_g(); + + this.transferMode = TransferMode.values()[nbt.getInteger("transferMode")]; + this.isActive = nbt.getBoolean("isActive"); + this.fortronTank.setFluid( + new FluidStack(FortronHelper.FLUID_FORTRON, nbt.getInteger("fortron"))); + } + + @Override + public void onReceivePacket(PacketTile.Type type, + final NBTTagCompound dataStream) { + super.onReceivePacket(type, dataStream); + if (type == PacketTile.Type.TOGGLE_MODE) { + this.transferMode = this.transferMode.toggle(); + } + } + + public int getSizeInventory() { return 5; } + + @Override + public void readFromNBT(final NBTTagCompound nbt) { + super.readFromNBT(nbt); + this.transferMode = TransferMode.values()[nbt.getInteger("transferMode")]; + } + + @Override + public void writeToNBT(final NBTTagCompound nbttagcompound) { + super.writeToNBT(nbttagcompound); + nbttagcompound.setInteger("transferMode", this.transferMode.ordinal()); + } + + @Override + public Set getLinkedDevices() { + final Set fortronBlocks = new HashSet<>(); + final Set frequencyBlocks = FrequencyGrid.instance().get( + this.getWorldObj(), new Vector3(this), this.getTransmissionRange(), + this.getFrequency()); + for (final IBlockFrequency frequencyBlock : frequencyBlocks) { + if (frequencyBlock instanceof IFortronFrequency) { + fortronBlocks.add((IFortronFrequency)frequencyBlock); + } + } + return fortronBlocks; + } + + public boolean isItemValidForSlot(final int slotID, + final ItemStack itemStack) { + if (slotID == 0 || slotID == 1) { + return itemStack.getItem() instanceof ICard; + } + return itemStack.getItem() instanceof IModule; + } + + public Set getCards() { + final Set cards = new HashSet<>(); + cards.add(super.getCard()); + cards.add(this.getStackInSlot(1)); + return cards; + } + + public TransferMode getTransferMode() { return this.transferMode; } + + @Override + public int getTransmissionRange() { + return 15 + this.getModuleCount(ModularForceFieldSystem.itemModuleScale, + new int[0]); + } + + @Override + public int getTransmissionRate() { + return 250 + 50 * this.getModuleCount( + ModularForceFieldSystem.itemModuleSpeed, new int[0]); + } +} diff --git a/src/main/java/mffs/tileentity/TileEntityInterdictionMatrix.java b/src/main/java/mffs/tileentity/TileEntityInterdictionMatrix.java new file mode 100644 index 0000000..a34637b --- /dev/null +++ b/src/main/java/mffs/tileentity/TileEntityInterdictionMatrix.java @@ -0,0 +1,233 @@ +package mffs.tileentity; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import mffs.ModularForceFieldSystem; +import mffs.Settings; +import mffs.api.modules.IInterdictionMatrixModule; +import mffs.api.modules.IModule; +import mffs.api.security.IBiometricIdentifier; +import mffs.api.security.IInterdictionMatrix; +import mffs.api.security.Permission; +import mffs.base.PacketTile; +import mffs.base.TileEntityModuleAcceptor; +import mffs.card.ItemCard; +import mffs.fortron.FortronHelper; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityLivingBase; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.NetworkManager; +import net.minecraft.network.Packet; +import net.minecraft.network.play.server.S35PacketUpdateTileEntity; +import net.minecraft.util.AxisAlignedBB; +import net.minecraft.util.ChatComponentText; +import net.minecraftforge.fluids.FluidStack; + +public class TileEntityInterdictionMatrix + extends TileEntityModuleAcceptor implements IInterdictionMatrix { + private boolean isBanMode; + + public TileEntityInterdictionMatrix() { + this.isBanMode = true; + super.capacityBase = 30; + super.startModuleIndex = 2; + super.endModuleIndex = 9; + } + + @Override + public void updateEntity() { + super.updateEntity(); + if (!this.getWorldObj().isRemote && + (this.isActive() || (this.getStackInSlot(0) != null && + this.getStackInSlot(0).getItem() == + ModularForceFieldSystem.itemCardInfinite)) && + super.ticks % 10L == 0L && + this.requestFortron(this.getFortronCost() * 10, false) > 0) { + this.requestFortron(this.getFortronCost() * 10, true); + this.scan(); + } + } + + public float getAmplifier() { + return (float)Math.max(Math.min(this.getActionRange() / 20, 10), 1); + } + + public void scan() { + try { + final IBiometricIdentifier biometricIdentifier = + this.getBiometricIdentifier(); + final AxisAlignedBB emptyBounds = AxisAlignedBB.getBoundingBox( + (double)this.xCoord, (double)this.yCoord, (double)this.zCoord, + (double)(this.xCoord + 1), (double)(this.yCoord + 1), + (double)(this.zCoord + 1)); + final List warningList = + this.getWorldObj().getEntitiesWithinAABB( + EntityLivingBase.class, + emptyBounds.expand((double)this.getWarningRange(), + (double)this.getWarningRange(), + (double)this.getWarningRange())); + final List actionList = + this.getWorldObj().getEntitiesWithinAABB( + EntityLivingBase.class, + emptyBounds.expand((double)this.getActionRange(), + (double)this.getActionRange(), + (double)this.getActionRange())); + for (final EntityLivingBase entityLiving : warningList) { + if (entityLiving instanceof EntityPlayer && + !actionList.contains(entityLiving)) { + final EntityPlayer player = (EntityPlayer)entityLiving; + boolean isGranted = false; + if (biometricIdentifier != null && + biometricIdentifier.isAccessGranted( + player.getDisplayName(), + Permission.BYPASS_INTERDICTION_MATRIX)) { + isGranted = true; + } + if (isGranted || this.getWorldObj().rand.nextInt(3) != 0) { + continue; + } + player.addChatMessage(new ChatComponentText( + "[" + this.getInventoryName() + + "] Warning! You are near the scanning range!")); + } + } + if (this.getWorldObj().rand.nextInt(3) == 0) { + for (final EntityLivingBase entityLiving : actionList) { + this.applyAction(entityLiving); + } + } + } catch (final Exception e) { + ModularForceFieldSystem.LOGGER.severe("Defense Station has an error!"); + e.printStackTrace(); + } + } + + public void applyAction(final EntityLivingBase entityLivingBase) { + if (entityLivingBase instanceof EntityPlayer) { + final EntityPlayer player = (EntityPlayer)entityLivingBase; + final IBiometricIdentifier biometricIdentifier = + this.getBiometricIdentifier(); + if (biometricIdentifier != null && + biometricIdentifier.isAccessGranted( + player.getDisplayName(), Permission.BYPASS_INTERDICTION_MATRIX)) { + return; + } + if (!Settings.INTERACT_CREATIVE && player.capabilities.isCreativeMode) { + return; + } + } + for (final ItemStack itemStack : this.getModuleStacks(new int[0])) { + if (itemStack.getItem() instanceof IInterdictionMatrixModule) { + final IInterdictionMatrixModule module = + (IInterdictionMatrixModule)itemStack.getItem(); + if (module.onDefend(this, entityLivingBase)) { + break; + } + if (((Entity)entityLivingBase).isDead) { + break; + } + continue; + } + } + } + + @Override + public Packet getDescriptionPacket() { + NBTTagCompound nbt = new NBTTagCompound(); + + nbt.setBoolean("isBanMode", this.isBanMode); + nbt.setBoolean("isActive", this.isActive); + nbt.setInteger("fortron", this.fortronTank.getFluidAmount()); + + return new S35PacketUpdateTileEntity(this.xCoord, this.yCoord, this.zCoord, + this.getBlockMetadata(), nbt); + } + + @Override + public void onDataPacket(NetworkManager arg0, + S35PacketUpdateTileEntity arg1) { + NBTTagCompound nbt = arg1.func_148857_g(); + + this.isBanMode = nbt.getBoolean("isBanMode"); + this.isActive = nbt.getBoolean("isActive"); + this.fortronTank.setFluid(new FluidStack(FortronHelper.FLUID_FORTRON, nbt.getInteger("fortron"))); + } + + @Override + public void onReceivePacket(PacketTile.Type type, + final NBTTagCompound dataStream) { + super.onReceivePacket(type, dataStream); + if (type == PacketTile.Type.TOGGLE_MODE) { + this.isBanMode = !this.isBanMode; + } + } + + public boolean isBanMode() { return this.isBanMode; } + + @Override + public int getActionRange() { + return this.getModuleCount(ModularForceFieldSystem.itemModuleScale, + new int[0]); + } + + @Override + public int getWarningRange() { + return this.getModuleCount(ModularForceFieldSystem.itemModuleWarn, + new int[0]) + + this.getActionRange() + 3; + } + + @Override + public int getSizeInventory() { + return 19; + } + + @Override + public Set getFilteredItems() { + final Set stacks = new HashSet<>(); + for (int i = super.endModuleIndex; i < this.getSizeInventory() - 1; ++i) { + if (this.getStackInSlot(i) != null) { + stacks.add(this.getStackInSlot(i)); + } + } + return stacks; + } + + @Override + public boolean getFilterMode() { + return this.isBanMode; + } + + @Override + public boolean isItemValidForSlot(final int slotID, + final ItemStack itemStack) { + if (slotID == 0 || slotID == 1) { + return itemStack.getItem() instanceof ItemCard; + } + return slotID > super.endModuleIndex || itemStack.getItem() instanceof + IModule; + } + + @Override + public Set getCards() { + final Set cards = new HashSet<>(); + cards.add(super.getCard()); + cards.add(this.getStackInSlot(1)); + return cards; + } + + @Override + public void readFromNBT(final NBTTagCompound nbt) { + super.readFromNBT(nbt); + this.isBanMode = nbt.getBoolean("isBanMode"); + } + + @Override + public void writeToNBT(final NBTTagCompound nbt) { + super.writeToNBT(nbt); + nbt.setBoolean("isBanMode", this.isBanMode); + } +} diff --git a/src/main/java/micdoodle8/mods/galacticraft/api/block/IPartialSealableBlock.java b/src/main/java/micdoodle8/mods/galacticraft/api/block/IPartialSealableBlock.java new file mode 100644 index 0000000..97efdcb --- /dev/null +++ b/src/main/java/micdoodle8/mods/galacticraft/api/block/IPartialSealableBlock.java @@ -0,0 +1,9 @@ +package micdoodle8.mods.galacticraft.api.block; + +import net.minecraft.world.World; +import net.minecraftforge.common.util.ForgeDirection; + +public interface IPartialSealableBlock +{ + public boolean isSealed(World world, int x, int y, int z, ForgeDirection direction); +} diff --git a/src/main/resources/assets/mffs/lang/de_DE.properties b/src/main/resources/assets/mffs/lang/de_DE.properties new file mode 100644 index 0000000..c58560a --- /dev/null +++ b/src/main/resources/assets/mffs/lang/de_DE.properties @@ -0,0 +1,155 @@ +# Modular Force Field System Language Properties +# @author Calclavia and Vexatos + +itemGroup.MFFS=Modular Force Field System + +# Death Messages +death.attack.areaDefense=%1$s ignorierte Warnungen und wurde disintegriert. +death.attack.fieldShock=%1$s wurde von einem Kraftfeld disintegriert. + +# Blocks +tile.mffs\:fortronite.name=Fortronit +tile.mffs\:biometricIdentifier.name=Biometrischer Identifikator +tile.mffs\:interdictionMatrix.name=Interdiktionsmatrix +tile.mffs\:fortronCapacitor.name=Fortron-Speicher +tile.mffs\:projector.name=Kraftfeldprojektor +tile.mffs\:coercionDeriver.name=Zwangsansammler +tile.mffs\:manipulator.name=Kraftmanipulator +tile.mffs\:forceField.name=Kraftfeld + + +# Cards +item.mffs\:cardBlank.name=Leere Karte +item.mffs\:cardInfinite.name=Unendliche Energiekarte +item.mffs\:cardInfinite.tooltip=Die Unendliche Energiekarte ist ein Gegenstand, der nur im Kreativ-Modus zu erhalten ist. Er kann f\u00FCr endlose Energie innerhalb eines Speichers platziert werden. +item.mffs\:cardFrequency.name=Frequenzkarte +item.mffs\:cardFrequency.tooltip=Die Frequenzkarte wird f\u00FCr m\u00FChelose Frequenz\u00FCbertragung genutzt. Mit Shift-rechtsklicken wird die Karte eine zuf\u00E4llige Frequenz generieren. +item.mffs\:cardLink.name=Verbindungskarte +item.mffs\:cardLink.tooltip=Das Rechtsklicken auf einen Block mit dieser Karte wird eine Verbindung zu dieser spezifischen Position kreieren. +item.mffs\:cardIdentification.name=Identificationskarte +item.mffs\:cardIdentification.tooltip=Rechtsklicke mit dieser Karte, um sie biometrisch auf deinen Namen zu sperren. + +#Items +item.mffs\:remoteController.name=Fernbedienung +item.mffs\:fortron.name=Fortron +item.mffs\:focusMatrix.name=Fokusmatrix + +#Fluids +fluid.fortron=Fortron + +#Projection Modes +item.mffs\:modeCube.name=W\u00FCrfelmodus +item.mffs\:modeTube.name=R\u00F6hrenmodus +item.mffs\:modeSphere.name=Kugelmodus +item.mffs\:modePyramid.name=Pyramidenmodus +item.mffs\:modeCylinder.name=Zylindermodus +item.mffs\:modeCustom.name=Spezifischer Modus +item.mffs\:modeCustom.tooltip=Kreiere deinen eigenen Modus, indem du zwei Punkte rechtsklickst, um einen Bereich zu definieren. Shift-rechtsklicke, um den Bereich zu speichern. + +# Modules +## General Modules +item.mffs\:moduleScale.name=Skalierungsmodul +item.mffs\:moduleScale.tooltip=Das Skalierungsmodul erh\u00F6ht die Gr\u00F6\u00DFe oder Reichweite einer bestimmten Komponente. +item.mffs\:moduleTranslate.name=Translationsmodul +item.mffs\:moduleTranslate.tooltip=Das Translationsmodul setzt das Kraftfeld um, platziert es vom Ursprungsort entfernt. +item.mffs\:moduleRotate.name=Rotationsmodul +item.mffs\:moduleRotate.tooltip=Das Rotationsmodul rotiert das Kraftfeld mit einem bestimmten Winkel. + +item.mffs\:moduleCapacity.name=Kapazit\u00E4tsmodul +item.mffs\:moduleCapacity.tooltip=Erh\u00F6ht die Kapazit\u00E4t eines Ger\u00E4ts. +item.mffs\:moduleSpeed.name=Geschwindigkeitsmodul +item.mffs\:moduleSpeed.tooltip=Erh\u00F6ht die Geschwindigkeit eines Ger\u00E4ts. + +## Force Field Projector Modules +item.mffs\:moduleShock.name=Schockmodul +item.mffs\:moduleSponge.name=Schwammmodul +item.mffs\:moduleManipulator.name=Feldmanipulatormodul +item.mffs\:moduleFusion.name=Feldfusionsmodul +item.mffs\:moduleCamouflage.name=Tarnungsmodul +item.mffs\:moduleDisintegration.name=Disintegrationsmodul +item.mffs\:moduleGlow.name=Leuchtmodul +item.mffs\:moduleStabilize.name=Feldstabilisatormodul +item.mffs\:moduleStabilize.tooltip=Stabilisiert das projezierte Kraftfeld und kristallisiert das Feld zu soliden Bl\u00F6cken. Platziere eine Kiste mit Bl\u00F6cken neben dem Projektor, um das Feld zu stabilisieren. +item.mffs\:moduleCollection.name=Sammelmodul +item.mffs\:moduleCollection.tooltip=Das Sammelmodul erlaubt es, die vom Disintegrationsmodul fallen gelassenen Bl\u00F6cke zu sammeln. +item.mffs\:moduleInvert.name=Umkehrmodul +item.mffs\:moduleInvert.tooltip=Kehrt das Feld um, um negativen Raum statt positiven zu nutzen. +item.mffs\:moduleSilence.name=Stillemodul +item.mffs\:moduleSilence.tooltip=Macht das Kraftfeld lautlos und bewahrt es davor, T\u00F6ne zu erzeugen. + +## Interdiction Matrix Modules +item.mffs\:moduleAntiPersonnel.name=Anti-Spieler-Modul +item.mffs\:moduleAntiPersonnel.tooltip=Wird die Interdiktionsmatrix dazu bringen, alle Spieler zu t\u00F6ten. +item.mffs\:moduleAntiFriendly.name=Anti-Friedlich-Modul +item.mffs\:moduleAntiFriendly.tooltip=Wird die Interdiktionsmatrix dazu bringen, alle friedlichen Mobs zu t\u00F6ten. +item.mffs\:moduleAntiHostile.name=Anti-Feindlich-Modul +item.mffs\:moduleAntiHostile.tooltip=Wird die Interdiktionsmatrix dazu bringen, alle feindlichen Mobs zu t\u00F6ten. +item.mffs\:moduleWarn.name=Warnungsmodul +item.mffs\:moduleWarn.tooltip=Sendet dem Eindringling eine Warnung. +item.mffs\:moduleConfiscate.name=Konfiszierungsmodul +item.mffs\:moduleConfiscate.tooltip=Konfisziert die Gegenst\u00E4nde des Eindringlings. +item.mffs\:moduleBlockAccess.name=Blockzugriffsmodul +item.mffs\:moduleBlockAccess.tooltip=Hindert einen Eindringling am Rechtsklicken von Bl\u00F6cken. +item.mffs\:moduleBlockAlter.name=Block\u00E4nderungsmodul +item.mffs\:moduleBlockAlter.tooltip=Hindert einen Eindringling am Platzieren und Zerst\u00F6ren von Bl\u00F6cken. +item.mffs\:moduleAntiSpawn.name=Anti-Spawn-Modul +item.mffs\:moduleAntiSpawn.tooltip=Hindert Dinge am Spawnen in einer bestimmten Region. + +# Multitool +item.mffs\:itemMultiTool.name=Multi-Tool + +# GUI +gui.frequency.name=Frequenz +gui.frequency.tooltip=Maschinen mit der selben Frequenz werden Fortronenergie teilen. +gui.progress.name=Fortschitt +gui.fortron.name=Fortron +gui.fortron.tooltip=Fortron ist der Typ von Energie, der in MFFS-Maschinen genutzt wird. +gui.upgrade.name=Upgrade +gui.matrix.name=Matrix +gui.matrix.tooltip=Die Projektionsmatrix wird genutzt, um festzulegen, wie die Projektion kreiert werden soll. +gui.master.name=Master +gui.master.tooltip=Die Master-Karte wird den Spieler auf der Karte als Besitzer des Biometrischen Identifikators bezeichnen. + +# Capacitor +gui.linkedDevice.name=Verbundene Ger\u00E4te +gui.linkedDevice.tooltip=Die Anzahl der Ger\u00E4te, die mit dieser Maschine verbunden sind. +gui.range.name=Reichweite +gui.range.tooltip=Die Reichweite kann mit einem Skalierungsmodul erh\u00F6ht werden. +gui.transmissionRate.name=\u00DCbertragungsrate +gui.transmissionRate.tooltip=Die Rate, mit der dieser Speicher Fortronenergie \u00FCbertragen kann. + +## Transfer Modes +gui.transferModeEqualize.name=Angleichen +gui.transferModeEqualize.tooltip=Teile Fortronenergie mit Maschinen basierend auf dem Prozentsatz des Speichers der Maschine. +gui.transferModeDistribute.name=Aufteilen +gui.transferModeDistribute.tooltip=Teile Fortronenergie mit Maschinen basierend auf der gespeicherten Menge der Maschine. +gui.transferModeDrain.name=Leeren +gui.transferModeDrain.tooltip=Leert die Energie aus dem Speicher und teilt sie gleichm\u00E4\u00DFig mit verbundenen Maschinen. +gui.transferModeFill.name=F\u00FCllen +gui.transferModeFill.tooltip=F\u00FCllt die Energie des Speichers. Teilt \u00FCberlaufende Energie gleichm\u00E4\u00DFig auf. + +# Permissions +gui.rights.name=Rechte +gui.rights.tooltip=Weise hier der Karte links Rechte zu. +gui.warp.name=Warp +gui.warp.tooltip=Erlaubt es dem Spieler, das Kraftfeld zu durchqueren und zu \u00FCbergehen. +gui.blockPlaceAccess.name=Block\u00E4nderung +gui.blockPlaceAccess.tooltip=Erlaubt es dem Spieler, Bl\u00F6cke zu platzieren und zu zerst\u00F6ren. +gui.blockAccess.name=Blockzugriff +gui.blockAccess.tooltip=Erlaubt es dem Spieler, mit Bl\u00F6cken zu interagieren und ihre GUIs zu \u00F6ffnen. +gui.configure.name=Konfigurieren +gui.configure.tooltip=Erlaubt es dem Spieler, den Biometrischen Identifikator zu konfigurieren. +gui.bypassDefense.name=Verteidigung umgehen +gui.bypassDefense.tooltip=Erlaubt es dem Spieler, die Einschr\u00E4nkungen der Interdiktionsmatrix zu umgehen. +gui.bypassConfiscation.name=Konfiszierung umgehen +gui.bypassConfiscation.tooltip=Erlaubt es dem Spieler, die Konfiszierung der Interdiktionsmatrix zu Umgehen. +gui.remoteControl.name=Fernsteuerung +gui.remoteControl.tooltip=Erlaubt es dem Spieler, eine Fernbedienung in der defensiven Region zu nutzen. + +# Interdiction Matrix +gui.filterMode.name=Filtermodus +gui.filterMode.tooltip=Der Modus, in dem Gegenst\u00E4nde und Bl\u00F6cke gefiltert werden. +gui.warn.name=Warnung +gui.warn.tooltip=Die Reichweite, in der die Interdiktionsmatrix dem Spieler eine Warnung geben wird. +gui.action.name=Aktion +gui.action.tooltip=Die Reichweite, in der die Interdiktionsmatrix die angepassten Aktionen auf einen Spieler anwenden wird. diff --git a/src/main/resources/assets/mffs/lang/en_US.properties b/src/main/resources/assets/mffs/lang/en_US.properties new file mode 100644 index 0000000..6281e03 --- /dev/null +++ b/src/main/resources/assets/mffs/lang/en_US.properties @@ -0,0 +1,155 @@ +# Modular Force Field System Language Properties +# @author Calclavia, LordMZTE + +itemGroup.MFFS=Modular Force Field System + +# Death Messages +death.attack.areaDefense=%1$s disregarded warnings and was disintegrated. +death.attack.fieldShock=%1$s was disintegrated by a force field. + +# Blocks +tile.mffs\:fortronite.name=Fortronite +tile.mffs\:biometricIdentifier.name=Biometric Identifier +tile.mffs\:interdictionMatrix.name=Interdiction Matrix +tile.mffs\:fortronCapacitor.name=Fortron Capacitor +tile.mffs\:projector.name=Force Field Projector +tile.mffs\:coercionDeriver.name=Coercion Deriver +tile.mffs\:manipulator.name=Force Manipulator +tile.mffs\:forceField.name=Force Field + + +# Cards +item.mffs\:cardBlank.name=Blank Card +item.mffs\:cardInfinite.name=Infinite Power Card +item.mffs\:cardInfinite.tooltip=The infinite power card is a creative-only item that can be placed inside a capacitor for infinite energy. +item.mffs\:cardFrequency.name=Frequency Card +item.mffs\:cardFrequency.tooltip=The frequency card is used for ease of frequency transmission. Shift-right clicking the card will generate a random frequency. +item.mffs\:cardLink.name=Link Card +item.mffs\:cardLink.tooltip=Right clicking the link card on a block will create a link to that specific position. +item.mffs\:cardIdentification.name=Identification Card +item.mffs\:cardIdentification.tooltip=Right click on the ID card to biometrically lock it to your name. + +#Items +item.mffs\:remoteController.name=Remote Controller +item.mffs\:fortron.name=Fortron +item.mffs\:focusMatrix.name=Focus Matrix + +#Fluids +fluid.fortron=Fortron + +#Projection Modes +item.mffs\:modeCube.name=Cube Mode +item.mffs\:modeTube.name=Tube Mode +item.mffs\:modeSphere.name=Sphere Mode +item.mffs\:modePyramid.name=Pyramid Mode +item.mffs\:modeCylinder.name=Cylinder Mode +item.mffs\:modeCustom.name=Custom Mode +item.mffs\:modeCustom.tooltip=Create your own mode by right clicking two points to define an area. Shift right click to save the area. + +# Modules +## General Modules +item.mffs\:moduleScale.name=Scale Module +item.mffs\:moduleScale.tooltip=The scale module increases the scale of a certain component. +item.mffs\:moduleTranslate.name=Translation Module +item.mffs\:moduleTranslate.tooltip=The translation module translates the field, displacing it away from the origin. +item.mffs\:moduleRotate.name=Rotation Module +item.mffs\:moduleRotate.tooltip=The rotation module rotates a field with a specific angle. + +item.mffs\:moduleCapacity.name=Capacity Module +item.mffs\:moduleCapacity.tooltip=Increases the capacity of a device. +item.mffs\:moduleSpeed.name=Speed Module +item.mffs\:moduleSpeed.tooltip=Increases the speed of a device. + +## Force Field Projector Modules +item.mffs\:moduleShock.name=Shock Module +item.mffs\:moduleSponge.name=Sponge Module +item.mffs\:moduleManipulator.name=Dome Module +item.mffs\:moduleFusion.name=Field Fusion Module +item.mffs\:moduleCamouflage.name=Camouflage Module +item.mffs\:moduleDisintegration.name=Disintegration Module +item.mffs\:moduleGlow.name=Glow Module +item.mffs\:moduleStabilize.name=Field Stabilizer Module +item.mffs\:moduleStabilize.tooltip=Stabilizes the projected force field and crystallizes the field into solid blocks. Place a chest next the projector with blocks to stablize the field. +item.mffs\:moduleCollection.name=Collection Module +item.mffs\:moduleCollection.tooltip=Collection module allows you to collect dropped blocks from the disintegration module. +item.mffs\:moduleInvert.name=Invert Module +item.mffs\:moduleInvert.tooltip=Inverts the field to use negative space instead of the positive space. +item.mffs\:moduleSilence.name=Silence Module +item.mffs\:moduleSilence.tooltip=Silences the force field and prevents it from making sound. + +## Interdiction Matrix Modules +item.mffs\:moduleAntiPersonnel.name=Anti-Personnel Module +item.mffs\:moduleAntiPersonnel.tooltip=Will cause Interdiction Matrix to kill all players. +item.mffs\:moduleAntiFriendly.name=Anti-Friendly Module +item.mffs\:moduleAntiFriendly.tooltip=Will cause Interdiction Matrix to kill all friendly mobs. +item.mffs\:moduleAntiHostile.name=Anti-Hostile Module +item.mffs\:moduleAntiHostile.tooltip=Will cause Interdiction Matrix to kill all hostile mobs. +item.mffs\:moduleWarn.name=Warn Module +item.mffs\:moduleWarn.tooltip=Sends a warning to the intruder. +item.mffs\:moduleConfiscate.name=Confiscate Module +item.mffs\:moduleConfiscate.tooltip=Confiscates the intruder's items. +item.mffs\:moduleBlockAccess.name=Block Access Module +item.mffs\:moduleBlockAccess.tooltip=Prevents an intruder from right clicking on blocks. +item.mffs\:moduleBlockAlter.name=Block Alter Module +item.mffs\:moduleBlockAlter.tooltip=Prevents an intruder from placing or breaking blocks. +item.mffs\:moduleAntiSpawn.name=Anti-Spawn Module +item.mffs\:moduleAntiSpawn.tooltip=Prevents entities from spawning in a specific region. + +# Multitool +item.mffs\:itemMultiTool.name=Multi-Tool + +# GUI +gui.frequency.name=Frequency +gui.frequency.tooltip=Machines with the same frequency will share Fortron energy. +gui.progress.name=Progress +gui.fortron.name=Fortron +gui.fortron.tooltip=Fortron is the type of force energy used in MFFS machines. +gui.upgrade.name=Upgrade +gui.matrix.name=Matrix +gui.matrix.tooltip=The projection matrix is used to determine how the projection should be created. +gui.master.name=Master +gui.master.tooltip=The Master Card will denote the player in the card owner of the Biometric Identifier. + +# Capacitor +gui.linkedDevice.name=Linked Device +gui.linkedDevice.tooltip=The amount of devices linked to this machine. +gui.range.name=Range +gui.range.tooltip=The range can be upgraded with a range module. +gui.transmissionRate.name=Transmission Rate +gui.transmissionRate.tooltip=The rate in which this capacitor can transfer fortron energy. + +## Transfer Modes +gui.transferModeEqualize.name=Equalize +gui.transferModeEqualize.tooltip=Spread fortron energy with machines based on the machine's capacity percentage. +gui.transferModeDistribute.name=Distribute +gui.transferModeDistribute.tooltip=Spread fortron energy evenly based on the energy amount. +gui.transferModeDrain.name=Drain +gui.transferModeDrain.tooltip=Drains out the capacitor's energy and equalizes them to linked machines. +gui.transferModeFill.name=Fill +gui.transferModeFill.tooltip=Fills up the capacitor's energy. Equalizes the overflowing energy. + +# Permissions +gui.rights.name=Rights +gui.rights.tooltip=Assign rights to the card to your left here. +gui.warp.name=Warp +gui.warp.tooltip=Allow the player to go through and bypass force fields. +gui.blockPlaceAccess.name=Block Alter +gui.blockPlaceAccess.tooltip=Allow the player to place and break blocks. +gui.blockAccess.name=Block Access +gui.blockAccess.tooltip=Allow the player to interact and open GUIs in blocks. +gui.configure.name=Configure +gui.configure.tooltip=Allow the player to configure the Biometric Identifier. +gui.bypassDefense.name=Bypass Defense +gui.bypassDefense.tooltip=Allow the player to bypass Interdiction Matrix restrictions. +gui.bypassConfiscation.name=Bypass Confiscation +gui.bypassConfiscation.tooltip=Allow the player to bypass the Interdiction Matrix confiscation. +gui.remoteControl.name=Remote Control +gui.remoteControl.tooltip=Allow the player to use the remote control within defensive region. + +# Interdiction Matrix +gui.filterMode.name=Filter Mode +gui.filterMode.tooltip=The mode in which to filter out items and blocks. +gui.warn.name=Warning +gui.warn.tooltip=The range in which the Interdiction Matrix will give the player a warning. +gui.action.name=Action +gui.action.tooltip=The range in which the Interdiction Matrix will apply the modulated actions to the player. diff --git a/src/main/resources/assets/mffs/lang/zh_CN.properties b/src/main/resources/assets/mffs/lang/zh_CN.properties new file mode 100644 index 0000000..9725749 --- /dev/null +++ b/src/main/resources/assets/mffs/lang/zh_CN.properties @@ -0,0 +1,144 @@ +# Modular Force Field System Language Properties for zh_CN +# @author Fr0stbyteR + +itemGroup.MFFS=\u529B\u573A\u62A4\u76FE + +# Death Messages +death.attack.areaDefense=%1$s \u65E0\u89C6\u8B66\u544A \u76EE\u6807\u5DF2\u88AB\u6467\u6BC1 +death.attack.fieldShock=%1$s \u5DF2\u88AB\u7ACB\u573A\u62A4\u76FE\u6467\u6BC1 + +# Blocks +tile.mffs\:fortronite.name=\u529B\u573A\u7535\u5B50\u77FF +tile.mffs\:biometricIdentifier.name=\u751F\u7269\u8BC6\u522B\u5668 +tile.mffs\:interdictionMatrix.name=\u9632\u5FA1\u77E9\u9635 +tile.mffs\:fortronCapacitor.name=\u529b\u573a\u7535\u5b58\u7535\u7bb1 +tile.mffs\:projector.name=\u529B\u573A\u6620\u5C04\u5668 +tile.mffs\:coercionDeriver.name=\u529B\u573A\u7535\u5B50\u8F6C\u6362\u5668 +tile.mffs\:forceField.name=\u529B\u573A + +# Cards +item.mffs\:cardBlank.name=\u7A7A\u767D\u5361 +item.mffs\:cardInfinite.name=\u65E0\u9650\u80FD\u91CF\u5361 +item.mffs\:cardInfinite.tooltip=\u53EA\u80FD\u5728\u521B\u9020\u6A21\u5F0F\u4E0B\u5F97\u5230 \u653e\u5165\u5b58\u7535\u7bb1\u53ef\u4ee5\u5f97\u5230\u65e0\u9650\u80fd\u91cf +item.mffs\:cardFrequency.name=\u9891\u7387\u5361 +item.mffs\:cardFrequency.tooltip=\u7528\u4E8E\u8F6C\u6362\u9891\u7387 Shift+\u9F20\u6807\u5DE6\u952E\u751F\u6210\u968F\u673A\u9891\u7387 +item.mffs\:cardLink.name=\u94FE\u63A5\u5361 +item.mffs\:cardLink.tooltip=\u9F20\u6807\u53F3\u952E\u70B9\u51FB\u65B9\u5757\u4E0A\u7684\u94FE\u63A5\u5361\u4EE5\u94FE\u63A5\u5230\u6B64\u4F4D\u7F6E +item.mffs\:cardIdentification.name=ID\u5361 +item.mffs\:cardIdentification.tooltip=\u9F20\u6807\u53F3\u952E\u4EE5\u9501\u5B9A\u73A9\u5BB6\u8EAB\u4EFD + +#Items +item.mffs\:remoteController.name=\u9065\u63A7\u5668 +item.mffs\:fortron.name=\u529B\u573A\u7535\u5B50 +item.mffs\:focusMatrix.name=\u805A\u7126\u77E9\u9635 + +#Projection Modes +item.mffs\:modeCube.name=\u7ACB\u65B9\u4F53\u6A21\u5F0F +item.mffs\:modeTube.name=\u7BA1\u9053\u6A21\u5F0F +item.mffs\:modeSphere.name=\u7403\u72B6\u6A21\u5F0F +item.mffs\:modePyramid.name=\u91D1\u5B57\u5854\u6A21\u5F0F +item.mffs\:modeCylinder.name=\u5706\u67F1\u4F53\u6A21\u5F0F +item.mffs\:modeCustom.name=\u81EA\u5B9A\u4E49\u6A21\u5F0F +item.mffs\:modeCustom.tooltip=\u9F20\u6807\u53F3\u952E\u4EFB\u610F\u4E24\u70B9\u9009\u5B9A\u533A\u57DF Shift+\u9F20\u6807\u53F3\u952E\u70B9\u51FB\u6765\u4FDD\u5B58\u533A\u57DF + +# Modules +## General Modules +item.mffs\:moduleScale.name=\u62D3\u5C55\u6A21\u5757 +item.mffs\:moduleScale.tooltip=\u62D3\u5C55\u76EE\u6807\u7EC4\u4EF6\u7684\u89C4\u6A21 +item.mffs\:moduleTranslate.name=\u5E73\u79FB\u6A21\u5757 +item.mffs\:moduleTranslate.tooltip=\u5E73\u79FB\u4E00\u5757\u7ACB\u573A\u533A\u57DF +item.mffs\:moduleRotate.name=\u65CB\u8F6C\u6A21\u5757 +item.mffs\:moduleRotate.tooltip=\u5C06\u4E00\u5757\u533A\u57DF\u65CB\u8F6C\u6307\u5B9A\u89D2\u5EA6 + +item.mffs\:moduleCapacity.name=\u5BB9\u91CF\u6A21\u5757 +item.mffs\:moduleCapacity.tooltip=\u589E\u52A0\u8BBE\u5907\u5BB9\u91CF +item.mffs\:moduleSpeed.name=\u901F\u5EA6\u6A21\u5757 +item.mffs\:moduleSpeed.tooltip=\u52A0\u5FEB\u8BBE\u5907\u901F\u5EA6 + +## Force Field Projector Modules +item.mffs\:moduleShock.name=\u9707\u8361\u6A21\u5757 +item.mffs\:moduleSponge.name=\u6D41\u4F53\u6A21\u5757 +item.mffs\:moduleManipulator.name=\u529B\u573A\u64CD\u4F5C\u6A21\u5757 +item.mffs\:moduleFusion.name=\u529B\u573A\u878D\u5408\u6A21\u5757 +item.mffs\:moduleCamouflage.name=\u4F2A\u88C5\u6A21\u5757 +item.mffs\:moduleDisintegration.name=\u5206\u89E3\u6A21\u5757 +item.mffs\:moduleGlow.name=\u53D1\u5149\u6A21\u5757 +item.mffs\:moduleStabilize.name=\u529B\u573A\u56FA\u5316\u6A21\u5757 +item.mffs\:moduleStabilize.tooltip=\u5C06\u529B\u573A\u56FA\u5316 \u5728\u751F\u6210\u5668\u8FB9\u653E\u7F6E\u7BB1\u5B50\u6765\u63D0\u4F9B\u56FA\u5316\u7528\u7684\u65B9\u5757 + +## Interdiction Matrix Modules +item.mffs\:moduleAntiPersonnel.name=\u7981\u6B62\u73A9\u5BB6\u6A21\u5757 +item.mffs\:moduleAntiPersonnel.tooltip=\u4F7F\u9632\u5FA1\u77E9\u9635\u7981\u6B62\u73A9\u5BB6\u8FDB\u5165 +item.mffs\:moduleAntiFriendly.name=\u7981\u6B62\u52A8\u7269\u6A21\u5757 +item.mffs\:moduleAntiFriendly.tooltip=\u4F7F\u9632\u5FA1\u77E9\u9635\u7981\u6B62\u52A8\u7269\u8FDB\u5165 +item.mffs\:moduleAntiHostile.name=\u7981\u6B62\u602A\u7269\u6A21\u5757 +item.mffs\:moduleAntiHostile.tooltip=\u4F7F\u9632\u5FA1\u77E9\u9635\u7981\u6B62\u602A\u7269\u8FDB\u5165 +item.mffs\:moduleWarn.name=\u8B66\u544A\u6A21\u5757 +item.mffs\:moduleWarn.tooltip=\u5411\u5165\u4FB5\u8005\u53D1\u9001\u8B66\u544A +item.mffs\:moduleConfiscate.name=\u6536\u7F34\u6A21\u5757 +item.mffs\:moduleConfiscate.tooltip=\u6536\u7F34\u5165\u4FB5\u8005\u7684\u7269\u54C1 +item.mffs\:moduleBlockAccess.name=\u7981\u6B62\u4F7F\u7528\u6A21\u5757 +item.mffs\:moduleBlockAccess.tooltip=\u7981\u6B62\u5165\u4FB5\u8005\u4F7F\u7528\u65B9\u5757 +item.mffs\:moduleBlockAlter.name=\u7981\u6B62\u64CD\u4F5C\u6A21\u5757 +item.mffs\:moduleBlockAlter.tooltip=\u7981\u6B62\u5165\u4FB5\u8005\u653E\u7F6E\u6216\u7834\u574F\u65B9\u5757 +item.mffs\:moduleAntiSpawn.name=\u7981\u6B62\u751F\u6210\u6A21\u5757 +item.mffs\:moduleAntiSpawn.tooltip=\u7981\u6B62\u751F\u6210\u52A8\u7269/\u602A\u7269 + +# Multitool +item.mffs\:itemMultiTool.name=\u591A\u529F\u80FD\u5DE5\u5177 + +# GUI +gui.frequency.name=\u9891\u7387 +gui.frequency.tooltip=\u540C\u9891\u7387\u7684\u8BBE\u5907\u5C06\u5171\u7528\u529B\u573A\u7535\u5B50 +gui.progress.name=\u8FDB\u5EA6 +gui.fortron.name=\u529B\u573A\u7535\u5B50 +gui.fortron.tooltip=\u529B\u573A\u7535\u5B50\u662F\u7ACB\u573A\u62A4\u76FE\u4F7F\u7528\u7684\u80FD\u6E90 +gui.upgrade.name=\u5347\u7EA7 +gui.matrix.name=\u77E9\u9635 +gui.matrix.tooltip=\u6620\u5C04\u77E9\u9635\u80FD\u51B3\u5B9A\u529B\u573A\u7684\u751F\u6210\u65B9\u5F0F +gui.master.name=\u62E5\u6709\u8005 +gui.master.tooltip=\u62E5\u6709\u8005\u5361\u53EF\u4EE5\u8BB0\u5F55\u751F\u7269\u8BC6\u522B\u5668\u4E2D\u5361\u7247\u7684\u62E5\u6709\u8005 + +# Capacitor +gui.linkedDevice.name=\u8FDE\u63A5\u6570 +gui.linkedDevice.tooltip=\u8FDE\u63A5\u7684\u8BBE\u5907\u6570 +gui.range.name=\u8303\u56F4 +gui.range.tooltip=\u53EF\u4F7F\u7528\u8303\u56F4\u6A21\u5757\u5347\u7EA7 +gui.transmissionRate.name=\u4F20\u8F93\u5EF6\u8FDF +gui.transmissionRate.tooltip=\u5B58\u7535\u5668\u4F20\u8F93\u529B\u573A\u7535\u5B50\u7684\u5EF6\u8FDF + +## Transfer Modes +gui.transferModeEqualize.name=\u5E73\u8861 +gui.transferModeEqualize.tooltip=\u6839\u636E\u8BBE\u5907\u7684\u5BB9\u91CF\u767E\u5206\u6BD4\u4F20\u8F93\u529B\u573A\u7535\u5B50\u80FD\u91CF +gui.transferModeDistribute.name=\u5747\u4E00 +gui.transferModeDistribute.tooltip=\u5411\u6240\u6709\u8BBE\u5907\u4F20\u8F93\u76F8\u7B49\u80FD\u91CF +gui.transferModeDrain.name=\u5FEB\u901F +gui.transferModeDrain.tooltip=\u5FEB\u901F\u8F93\u51FA\u80FD\u91CF\u5E76\u5E73\u8861\u5206\u914D\u7ED9\u8BBE\u5907 +gui.transferModeFill.name=\u586B\u5145 +gui.transferModeFill.tooltip=\u5145\u6ee1\u5b58\u7535\u7bb1 \u518D\u8F93\u51FA\u591A\u4F59\u80FD\u91CF + +# Permissions +gui.rights.name=\u6743\u9650 +gui.rights.tooltip=\u5411\u5361\u7247\u5199\u5165\u6743\u9650 +gui.warp.name=\u5141\u8BB8 +gui.warp.tooltip=\u5141\u8BB8\u73A9\u5BB6\u7A7F\u8FC7\u529B\u573A +gui.blockPlaceAccess.name=\u65B9\u5757\u64CD\u4F5C +gui.blockPlaceAccess.tooltip=\u5141\u8BB8\u73A9\u5BB6\u9632\u6B62\u548C\u7834\u574F\u65B9\u5757 +gui.blockAccess.name=\u4F7F\u7528\u65B9\u5757 +gui.blockAccess.tooltip=\u5141\u8BB8\u73A9\u5BB6\u4F7F\u7528\u65B9\u5757 +gui.configure.name=\u8C03\u6574 +gui.configure.tooltip=\u5141\u8BB8\u73A9\u5BB6\u8BBE\u7F6E\u751F\u7269\u8BC6\u522B\u5668 +gui.bypassDefense.name=\u9632\u5FA1\u5FFD\u7565 +gui.bypassDefense.tooltip=\u751F\u7269\u9650\u5236\u5C06\u5FFD\u7565\u8BE5\u73A9\u5BB6 +gui.bypassConfiscation.name=\u6536\u7F34\u5FFD\u7565 +gui.bypassConfiscation.tooltip=\u6536\u7F34\u7CFB\u7EDF\u5C06\u5FFD\u7565\u8BE5\u73A9\u5BB6 +gui.remoteControl.name=\u9065\u63A7 +gui.remoteControl.tooltip=\u5141\u8BB8\u73A9\u5BB6\u5728\u529B\u573A\u5185\u9065\u63A7 + +# Interdiction Matrix +gui.filterMode.name=\u7B5B\u9009 +gui.filterMode.tooltip=\u7B5B\u9009\u51FA\u7269\u54C1\u548C\u65B9\u5757 +gui.warn.name=\u8B66\u544A +gui.warn.tooltip=\u7ED9\u73A9\u5BB6\u8B66\u544A +gui.action.name=\u884C\u52A8 +gui.action.tooltip=\u5C06\u5BF9\u73A9\u5BB6\u8FDB\u884C\u6240\u914D\u7F6E\u7684\u884C\u52A8 \ No newline at end of file diff --git a/src/main/resources/assets/mffs/sounds.json b/src/main/resources/assets/mffs/sounds.json new file mode 100644 index 0000000..adb629d --- /dev/null +++ b/src/main/resources/assets/mffs/sounds.json @@ -0,0 +1,52 @@ +{ + "field": { + "category": "master", + "sounds": [ + { + "name": "field1", + "stream": false + }, + { + "name": "field2", + "stream": false + }, + { + "name": "field3", + "stream": false + }, + { + "name": "field4", + "stream": false + }, + { + "name": "field5", + "stream": false + } + ] + }, + "fieldmove": { + "category": "master", + "sounds": [ + { + "name": "fieldmove1", + "stream": false + }, + { + "name": "fieldmove2", + "stream": false + }, + { + "name": "fieldmove3", + "stream": false + }, + { + "name": "fieldmove4", + "stream": false + }, + { + "name": "fieldmove5", + "stream": false + } + ] + } +} diff --git a/src/main/resources/assets/mffs/sounds/field1.ogg b/src/main/resources/assets/mffs/sounds/field1.ogg new file mode 100644 index 0000000000000000000000000000000000000000..52a972048632b64ff5c567877ef476e0e7001203 GIT binary patch literal 38935 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/mffs/sounds/field2.ogg b/src/main/resources/assets/mffs/sounds/field2.ogg new file mode 100644 index 0000000000000000000000000000000000000000..75c83a53dc2536ca1cd43108acf422a0d7f00549 GIT binary patch literal 37185 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/mffs/sounds/field3.ogg b/src/main/resources/assets/mffs/sounds/field3.ogg new file mode 100644 index 0000000000000000000000000000000000000000..8b993744b3e0421e5414ea282c389c93ee571fcd GIT binary patch literal 34970 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 F{{v^`_+tP7 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/mffs/sounds/field4.ogg b/src/main/resources/assets/mffs/sounds/field4.ogg new file mode 100644 index 0000000000000000000000000000000000000000..61d77d8d1fac6d5a5fe5bb8e6c8d94e55378be43 GIT binary patch literal 41407 zcmeFYbyQT}`zX8zhVE`0kaj>)Le!xfX@`{VE)`UUZlt9J1SA9pkX9T(x*J3gL_|_i z!36FZ{d~Xo`~KeFy7yh{uJ^xt*5Rw!ozz^n4gr&oCw+|Kxy(sGaBI^_HjHhtk5Ht(|>^HQGq|XNM&&Z zx#R#MQde@TEJI&mtMXxr!nV-U31te=r&HRx60>Fwbgv`wIq#;8@#I9$&;I>~qSGt!VjW>QMc*hJ41x`M2) z1v||L2h9iHG0%y%Y`tUN8g01{ZT&6Ujy2|=`}>_Y-|+XJts`Kd_^f>Px^O8kd+A&G zQo^X1#{|F;j}in~IvlHJ zcKYAnDAxfIfP!$@@5kBi$ERk**YA%c`GesB0MQg>gzWW~)(DX94^V_|jX>4GOx@A1 zx-|bH0-o#upd>hZ{Wu39Y#517`^#JlxHKQ2HxHo#kCFfN75;}`ppEbpI%m6MNTpKk z{-6Z|P0LzBszUj9C8$GO$vZ^eMBbNCdFs54;wr}c>8^N_e8IM=ocuo&^c-VbhiEB0 zl-paJJCPSKrbU@o{CDb zRU&5lBP207{zJl#AgTCI!hPZ!r{kLZk9+)p(~zDYx+f(?jioM`nwVY-_A8oF)CmGZXrS*)NtS6a*rkS0LFIZ2@I8B>6%?3LyHal6i+%a$dM_~Sn&71k4 z|BxKKi15m%tZSyj|EJ^>3#Gi3OF65R&S#!3a4Xv-KCddbXsfD}{J%(!Yr>Z@!4+idDU&DoBsf(dX=*^~efhh`OOp^n z1JzjmlK=qVQYm%*=n+FB(ODyzStC(XlS}_=iGf;YrS+zzA;e|@zy`p(vWl4yYI^%r z`FJH)QmvPqy;cfa1rM!~VpGqmYwhtEkI=%KawfE*8E4*FxN`-VBqrB7YAT5~_ZjhQ zRFXhyj}(-!0qTAjrye1v4k09Y_)BXV=rO`Z8SvHux^R=yD27WY2DQJh|7TBVA!$Q6 zbpJCAw9uppY*PB4wV+jSQfeq^$dde@U;oWohBC0L|FITIS`THS_kX_9|DECgV&H#^ z0f@z6)X*QZatY5l0*o9C#IB>#5n7+5F%IUR6mPQYGOVJR6>0KFrvD`!kb(UyeUn>} zrh+V0nx=?kJkssoo*+Qnf*OjT&YJj!&8~m(H3Y~fU4{y>$tZUM#px)wZfU#f{~kCD z02mkvzyO9J)W2bRs7ViiT)Lw<o}JHY_P$-IaJfOMx@-2eSF|KDr>%YrbB5CE~I zXl7r|VS*F~b5uH#!qyz<5#D4+F~abj3GmQyNb@t32uVBg16m@m>dQDhC2jalF1y^V zbifa(Gp(BD1UW(RywXsSu4waC1=;u)Xx~B!rEUa}d4bSQgh%@YS8XJ@xCB{o~N7@a&M{_9q>L*X1WCA zC+lku=0J6V<&IFlf(#=CsE!(PI0B(AWtm3G9|{5>|DzD<0t2YO*iP`&7pFJ*gKj2( zTg8*BNDxA|R(i#)B0K=?*)8FbztfI`@E+vE)`~aZND2V1`T`(=wF`>MD6PjqhK>MlFQX(# zg(07dn5T?ZSyMPV_5aEKFbp&XL;FvJav{m?pOPQ>e?~3;Gk*F1v$SC0QQKq&SjVCX zQRY#}QjhrxnNo;Z*c<2pDH%j{r8tQXe3|Lm+Dytx@q;?xrSKrI( zk*p?^Z;5a9sFe}k2+*mYwQzXcB=9gP9bfmjX^uD3NV1R77%JsOiT8bDb$BeXX^}zS z{hixb6zc2&@xoch;l}(SOdAwK zLaf(^=P*298I`dHKx~GH!bf6dq<{_>f>BZTmt zuy)nI8_F{?jsA=!{o^7-p(x%{rH6Po(+C5tiip0{m#R}F&|s9*Mg5UkC_qR#%lxNJd- zgr^Cu&kCvR2mlD_BpFB< zQQ_f~Kn|suN&v_yD7kvnP$)5;hqz*2T{*$R3jip^{YfPJ2P$rIU6P7kY z8z0w;kSJjn5~(1>^b*C~1_KidnjNheF+!_}UTYF%Qf1l*G$#s1CMUNRBe?P@ild;| z*kl_8O#uKmScO#EBH-mM&0YWS={q2!W8)E)kXNGn(|i$p2SC#Z6Bp)!T< z_d9!^K7QTU{@}=UW{}|1Y-`Zmf#LGB-5W>bJ;9whADaAHIU-yO^Q)x0RXJi0Imh+} z>)85NMs^eP$14`{HwO!?TOM%SfA;oe#(m7dDoI}4@33$D+arOo@gdPGO7BhwF4a)% z@tmH2cXQtdU}|J)U7N^5HEK05dI!#i$>K8Qe2{hDy?ccLVIL^_iR1FjTHa^?^$geT z>kJ|V$=+%LLl;KHUz%+#-z_XDuuzc_Gl)&|WxxUdW^Je_aeJbqIj|+OmQk5ts+NlArGeti8C5dlkL zJMW*;-ce1}crKkn*b( zY>n@eF6ZwpBj3n|EmhF8aEb4;(WHHxL3&JQ?Vd*-tV@o!ODOW%4spGce)Uk(q~;;q zQffk(`b>~r2Adg{T8J0NqY4Tgq~;`T%EAXLYk5BSZ+q+3A8k)WHhs&mqns!uPX!!c zLiuv$f{y`X(+2l}CX7lC7P7Bwfi1NUHOrh3_J%#=24ZDWZzAVy_ETQ&&iOR^WPWo>w&<^Wli0yt@r4jBA0I`C!N%IXU*vZ> zGu)&saX^1d*DCPodpZB1Wf)vYpeNLdP%Nf3WHizLTz|D&j>ClsWPIK(0@kIk2?v=; zOfgTj_#`v6MXetO>LhA?5fHx+^Y2*aYOseuQ;0WCm;w#8ve0Jr6Fe}&Wu zTgy7}k>0p5@-R$7xQp$B%M3+ywNk#KK=|cw8cgbBjWe!c(C9DwM!Q zUw*Q&9@=oY-*Dl>oiCmWJK<6nTNg;I$dTZ2kUf`fc$zV!8I*#fG2E9hOqB z2i9qtzZEsr+t;&Jqy_5RTL$T&%T))Ossjd_q8c{@dD{hicDJYK*TmkNXOiBR>~nW| zs<4YA=b*2zx6W&u{`@pypMdB>b|^wBB&? z#)>&-96cn^!~jPPo&lBh6j64_9;xFLp25K7{Nw8t@_VcS&pj9$d_Dw*9QXGYg(Ph$ zbf2Vfy?_DtoH&SG+iX$iuMAu|GiIvp88<4xN7t#^u7(1D+uC$aUrA?r;+ z>aZK%i&mXW=&!T!mb$j;H=Ogn;xZ?+^RX-K+~SJBU4{2opAB`6BR5&@wyn*rO^QCE zHag-v-+N0iK+>vkUEO{+X4}&3zH8sPB!g}~-a2N@C~b;1)4_KWT|y>AMiTAblL*Ny z(rE5;ntf!kP^K9~93*tN-XHm7hq)k{FlI=XI)(P-m$(z66-VcXm01qM%tmm!z(_O3ui7}y$%D-Db*PahzrVqhc@cZM!yCV z&{kFR3#zH9`oEQe2^qe@_2#{Bb|&^x?t% z>pup*?~j>Z3>EdhRK2Z}*fLZ1V#-n4`rZch_y!hb>`HIDRiPKEk`bGWXud_UI@(0w zL?1miEaPnc@@BX#<9QJgpy;aLVJ<$evozU|4sx?3Kv7`g1f_D%S80H$rY0E@w?AvH z1b6D;S`dc9O%fa@DG(;42eu4I6Dl<1B-9*hY-qko?&!3Nd)RQKy;*hi^Xe_fOMSc7 zgSC%7%H4xDTNltk`p~9>QyOC9KjALsHX(*Ge|E87CBJ3=_B**ka}S%3)gFmWpMp4M ze=6$v@79uu33wF51dVO17IutlBujYZ50xnB#rcU3<+(Z4 z!cIFPBDQadY2Xax)wQ!20{Ego1rrH@6jyKxOGwa}Rwtx}=PoUwK?P*j5p-g4+qQ1! zi%Wm0=ii6IPXJ^Ng;0z{fPr#|FO`f1G79Km3JhC^c(oA>NEKVUT`C5hzm9Lb%EEN- z1_xy~EDt0v@4h$~_?>J%F6;D5cYJzha%Vge0(RSa)_7ijM7Xoo!MaCqJ@iw77?AmV55m(2WQl18shpVukZuut9v-)1@Wy_tSQ{8Ly|QrM=y z4m0O*-xHktRy?ho%N-MKBw$-W}GPWTgD zc9CSsIQ`7^TSm?2$V>S#lbgq}Ye+D`OFaInYArpoLeY(?RbhrTRwbgcH(h2-IB-*K zE3;DAeneQ2v2jPPQZQ;n`~sD#R$dn-vnPp#)lpNTtd7wHSKUlY0~t> z%8Hl(ABaCG0R;uX5ZTrzBY^=FRVLMLAh;t!0J!_>xTWskUR&XH>Zac~u^Rya72bAo z)@SrgHh<%O%^SaXrN*A?Yts>I)ZPh8n#(g{hp1_&gx_hU{Fhd$`Dv>#X$E6c534AL z^X+>pls7Ww4x1+5?e?jkpUHDR=h<@B<#zMJ_vZWOkAoIlh|`u6si&$0>Hoy z0v1(xvG(ra42|25yOP>A$zB&Se14rtvrJylr{t0edvmDn>_(mH@X}e3T6p}?FXJN- z3ZAd!uf^c?9m3KzuRG!&n$PJIR=_Wfi3GF6)2QQqIB+7}RO%+-GA z&dUGNxyuchJf_jA;@DKvMZk*8j2Un<4ZTQbs`YKp#eZiFf`>LrVgP+{N{|Y>M^X6-kY^654Xt>6V(G zL|y%;A$$3$#y)j@-CVY3kl(GRQPk7Bq{WMj2-P^mA8qU#!PYrelgoYTJ9|21VXE3c zwkSxpeqh}pPW(oHetjA{Azo2iX+o(JM>`wx%{=Yqk3r906PAxho~wM|($lYJTZvC8 z-R6`{ZZh^T2)MOQTVvEF#8^z3FG9(+63&s;Vkflyn4ULIx@=ok%@s%RJaH=lC-<3+ zo<@wGziy>a2MAT}zb|ewJ$xKkZEr*zt~x;SNQf5LP9t#yAhptnFeVzJIR!w4Q$YEr z&T}izMAz&VhPyh`Ia-#&7P-Tcw|*;ow%lodqyGi~ovG#<(!BZPwA9KLc*>#_Wni>^ zzbrNeeG6=)#(mDSH#im6J$pRus(6$2>NvfA=WmG@@=MB2DyN;`S%n1F|r)OhX;FXPxq5=O=wb3inpcB>G1z&@%GD$(LSIU$qyC2z(~3 zq@ZfJMt1Ei`4FoyQ;8jMr7s+9YC`!kM*Vox{$brywCedg=T`9iW?%+{rHO)Dp2n3l zM7^&%Q=dm} z_U^(V*~6mq8gX~py>Al&gq+(w!^9C?+9<*j0A*&t2QN@YYy8M2R6XQNV-U%klBK(! z!y^tyCmkXqT4UV&S;)^=+;I9mTh&M<8GqfezV?ep*t3a+C^TtZi%NPI^Wp~@W>uRWN^Z`e(+2~W;!UxhpdW(Yo$ZYod)gE$ZqT@P>ow1X3! zlj)QXqMYB>yE+fv&HtkDzxT2Gz#$;2`3cDvDu5}X=HB}$)#WOaErapJL9zfqst=$& z>4@Ihy%HwD{#&2*nPSt?w{c2=kT1O*rg@jH3D&iwlMZ9Mnk*ek}M%7yb~@ullY`U;sOvRNoy)n&M?36pDze z@K?P{{II{3uo%JaQCg+jK-U#_onRq3Dy_Am^S#wba_@TxAWb&4c;Q+H%RoX!Fz`+r z4`XX9J*HmhF{G$~uha8r5~#qfyMjC>eSq^*T-Y1??Jt|yAzGC( z3nk?d6y4Me-QgI{Ly)rYm679T(!3q??ScFf)5;D53x(7>m-kcg8GCB>VM#R1>J>Ke zM+1Vx@;fiT&J7=R-p>9MVJ&rDK38M93+Y`vwc33{m8UWF-nu6L)g}km=;{Fi%>jEd zED6sBMu)B{4sF!lpV**A0kbu47ICm0X@7-mG)e^|3WiKlOU*i^>h>-Ay-W}cx^nCi z%Z;v%Eh7Ldw4eV;4CnzQrM`x;_*e$$Tna2901kR=01XlOpA^VlJn(<>HF#!zTg+d~ z{`-{T$I&U>Ddj26DZ?q#so*K|Dg7zf-#NXETzOWv)nUMWeV*i3%#E+Xr{Uag8m;s9 zcODLOrfaP9zR5brkXq~5U-ZrI)aSjuYRv=ye61 zTE<9Q)<=(dV?g*@^}62j1k!8DamsIPYg2?&&lv;$R(?Xqa*=qiIBE=W`OOL1j+K0S zO-qZ$fg=b8bQ-1d+^dfc+`w0bA38uF1DFY8obYDJ*Uu0`1dssN0I6~`2B7Nj`5;V3 zYX+PaSKlFOFokLt*;^Nvp1Z(xMyyXO+|%-m>_hiBzFdo~{wFy|5`EzpmSs<- z8ruyV{XW#tJn*!ndQfm{)_17)h{VJ4tzolu-vL2!D#w*!>i#3voC$|Zz)Ug zPOHq5z4J89yK;|bSfQqDHa@Ux*Cqy>>Kul;TZk;UEsK1gG0y65EPa?Gmb zWXtSb2x6l%eB+UDg#`(c>Gn59s&FQvAmHsYIwu)NIl`3v z!*oX1@2EEHcHHRsjJn9}hm=R!OMfZ`p1bKjDFk6a4NR97jD zcB9GRR~4XWd^aI~y&ip%r{{z1Og}j4Id#p5>n&1#*G~De_R-q=XJg?yvwF$76T zXMz0%(uYb?&GyxHK51Rm_IOx8>IRyb_&h`ilAE8jK1Y;7DgjN2gTCBDngP0TYXHh; zP%;B7f(+Od!T_r?Xdq&3g+`uuoRC~mi!!+UajB&9=EIf_`3^_o>A9U&YeDZfLXcHg zs!a>Mz_A#iTc({;Jqllg;ue6t&H(JrZtqN&+>?@0?5OW-xoprhO%)U@F|<>7Kc1iH zis;GF&)>%bc`8R7<6ci31u4EHEv)ggy?f>q!}TDBmoS#U@6b3OJ*>_ewzSB-Qt6pY zm?rA{$j^+aSIpdE40a!Dz8=3f!LAyFQ=N1LgnZdee8Pb{SOiKSZk1)UhSQHtD*bFl zuH~?2CPa<_SCy+(uiq}M!!UerWyk>i2mwTLyyiy(oCl5r`tkq{k%W+^4%C^lP|ml{ zK^Y*>x^t5fyp19g&wmUmXu_^FwV{GrRg$ZwsD^?&*C^ZGYm zv(Fs;C!=m}-l=#xmdU!H$ChsTjsHkh?9plNrz26X9pQ@M8eHZ4+DyzO?{_}ywQ|pZ z`sk2-X?ckz<9P#2c`!`zk!9rPY?v0qD{#q1Pnrj@FfScsT;?CzQI<>J9X zp!wL0NnG6PO_)jdtIugE;k6)`vk$k!MMT>@YNkX2a5MS#MFL!&Js@PY6&DAr4z`-~ zh_y^LRRSX5yBXxCV)Rl3V@ComTdgRLZs~m5*$6SdetRALOXE%B`4Yvkc@5yA0j#@E@m zpKp8(xY&90W8j75PrsxdYL9(UY-J@Oc$Oc5EHZsUb3|rfjMvpUi-qpT`S1JjQb9!Uhnb_ zG6Q-KJKxPw_Huv z^{8tKonN2kUq2o`u+yEhb_nQuU~|>}#tWnHje;c2(ZyeL3$dFtAsMlhPfZ>@$Yc>4 z+E}YQThZ{E@}?Hws^?KzpV3>^Yn#&ESqGoKHi#rB&xyy3EJ(y%ZlXK=5 zm)U)fl1?8tILrB{?o$O?P0dNuuxZ?LWFbjh#Y+)@6!f?!Yx(4>%Mu*nX+4A}f%_PO zVhjw61-7DCX6KxGWKUj`Q=bVx*{x+OweYGl!xpwMhh*3cjRzK)4XZ>Bj0h1Rpf7uG zBF+M*qEaDJRtiYpfEgkd$PKqXdCnbw&DUBiR-ud}rRl}ULwOChojv#Jx{D92!sMbu zJ?=E74;{aDZ{wtB{N#tm zXO--9oqM9p3Z2&3Pfjb;*hYt_%ysJQQjHOlbg0CNruL=cq<0~tk@n>}x%C-otR;Cg zC5&wo-p6*nCFtCC9I{RShOk?>BdwHL8?%J>8POajPCrsyG>rp4b8h)#G9AUI)auKB zl5MD3&0-to4w|1^7Qo<|^BW?-h}WmYBN$<394fNwt2XkNJH_ zFZCpqW^8$1@%w%wK5)i!`o@mgw4{&NRkuZZ&)77?RI*Xf;-b8J8i7E+J8wfmQ)o(2 zJ7@emN5a|J1o)cXSe&WOl~g-kf+YGIuWO`dUO9QFwg}ZGCA%J;8gS3u-1R zFO^jTUwS9y^1P0dpddtn$}aiWULDUQQW=&+u-zh_o`{*o`{NzM3If!%pK zDWdB0h0m75T31}24-|iE#VNI_V&*i4MkphyCmrLN&RS@>G$AqTGk;~MI->r{HG?L>Tcgah?wx)`jz&9QH zTHV4oFuGk)JfG3fM~8B(!Pd`;lp@YXlZZYy9A}AwU{&^+NF^=@NqHyUN58BpOSie1 zMB*gy0HE5ulbSs}4AJB>tkN@Hs*#Y-NeM+Emd23DB?PFalLX{gBrVFnG?fvJ2bo)M zMfcZ*V3*cpl3$S-b{~EGw2-Q4iMN_t>}7j1Vp{Z$}bqN#GQE0g{bS6TpGKtb^JNm z2Y@Ql`TH;h_eK941Z5O^1RkBM&y)$|&glOPnX8e$g&^_r=RKIN2`u+k`)Oa=y14a$ zI^putjgg{Zo9eT}eEgpe>&8THU-*2P|AsxLIeS)l$cb&O+W?7KTKvJhK2S@_$Rh}^ zo^s8#nR;mlmy3}@uXYo}itR5PYwdq+OP5Mk7GL1lD;C&O>lewWhH2#d;|@Yp6jZ02 zP?_UY2zm#E+`3SRHek&dDLwVxkw`h9Qh(>3R=FgfY$IbTf6 zoy#MA22N@9!P(6_<&piwuS(|bS(i}c#hWw5nNB}%=-vuxb9&p#wkqVOBARPd?@T1h zA|k-o!Kt&;NMJZ!;`EC{*}-;*$fzK@^hyd4SY<=IF@R7)U*=Z(qMi1{MLDW*^CdGq3Wg|zbY$F<@ARpq2S16 zF4MsF!^?2X{tQtV)3Q6uYoV+l5r!dX z6~-U|1#1L+BD$bbi`}+1B8rH>R&Ny#`U>)7`W`lC!um-Hx?}(MfaHzFb^evCr#9DP zEPm;FTYb#+BPu+a)41TSt;tszfIrU!Fi(TdH8b4Fn@Hq+BP(&y`>-R(= zY_q3B`6u97Yy~%GLNqE+rN3KRAVwQ9yOi#SLl%$_1FIylh4N8|^;E4+Wp-A`H(&n-L6mhOR-Qy0R;A~!M?+jee z>Bv2H5V%P9bGSVIaE@#7SKgh^tuEI$2Uf-%e4eM68$+STpLiXUQSk2WkE55D=AKJE z@3=Qzbb360`oev5_&pbrrZ&lC%}5m4c%;eRO8xGgx$2kR;?6Lgs(hJU;pd7bsTEY` z3cc-Ftv~Xio)vRm@vacL>ZC3l{j@upoWe<-FWKCrAS5KuG-|x&r$$6(RTcspc;ON; z&KmKK$k)qhi^$`CNMUI$ktGI7p@f@GZS&_4-I5r!A9f8fOc@uF>S&lNA-auM1W+ap z(gl4H1P$92l}IRYgMnds32>~DBmldjM#n^F4=P>sRkgxvh2Tc)&nzJZDnhP|Y|z(7 zeU-CmZa9wQ7=8WbByAc;Qe9Vc50#s(_ zbB_vKceT~9M%vGK1A9f33TPTG5?ktIHs9BFDUgcUl_B%1RFwfqiM*liy7c0SAy4Zb zyE7Bglj^1dX4;6_r_ZDOXo;03lo(&{u>ln6B3mD;xmT4R!qOsJKMyuoD7(0bgRp=h zLPNS9k?VF zcm(9Y%wR)&iW zz!KXcSt%*`7;pFqLa$H;2jIjs=NMHDoYyoh&$vle6k|m86^ati@|GIKNrVqkqSA2{ zFf0PEOHH2~2tU0y9b8lQ;x?cBucc>_9Sv7#&g-RAKPY%xdv~EB-_LFlNo6~QYsSf#%X?8~6hUlGPQ&ouV#d+?jqL}mJ8=w}VAi7;`n4HHLqwAsQPX*GCP(rt0CKnx7WPRNX92CR$(I_#o}qskHV z80Gr(q=4jejKQAds>%dp6u^daMfbqWou&LvL9=nw^JtB{mi*pJMm$gF*WBawnp-|q zep-33(ij^z%-8WH#qMI@F(z0wd$w4ha*_5Af)?I){@%Fr z#m~Bd{L(3fD~EHdGM1DcbLuZ~1sRl;EW$)N>gQ?uOwMaRX+>ta2q35g3bN~2GWmob zoh_%fu$(Du@tEgjtS2drFA=bTJ}~rO?kkIbJgjAr!{+<;nWL2mjC{w;GssBwk?U^l z7l1(NYA~E-Bpy<&hx96;FIN6VX1 zjm{oBrmnfH8>`dn+wCYVhJsK_2|6KEY%$kUEUksuhrLU4+&_P;%lW?bnR~>}u+M(Y zVZSd|!@W79ifg6}su%Fze1NS_&s=zvV|%dJIghccG%viGuGn?@?juuNLoAOLPL~%h z4Zl`!*}v>CgUjFa_vRb zCU`GFwxnm3nzPL7VNj%+;?`iS4R^(k&raBrEL;tnHfnyj3JP z);Q(VIPvmkU`~;AK+9Qfp{+nALBXMMnN0-C2t&lT^b0hiHRnF6YBAyAU^~K7Ajq76C=$&62Srr^@&Npj0vxKj%`Kkh4xX z7a7tO9Dj3gyU+0=j#7vC#_r%QQ`#bf=H=^4oCzEi;Y73&@PrQ-r!BY;QWin`lHO_i zm2q`+Pkuv%0z?~(N+zjN(_B)NJ%>}4tjFv%g~XaFEespDzyc`6nJI7$ecga!9cbCy zaCY{}>4|`Z2%lBJu=WG#4n`(A$^_fz4)JaTl->d>lq-+#a$Hxw zRd}5}7&0>wT8d|8&Os!3EOSpMC%-GB8&6+&KO9>D!{B)xAc4X)0 zi=CJck8kVTDR0vmKFms+_3pjWRO@8oG8AAIlG&ajSZb-ES^oN&1-+(oAi(O}kQJ}j zXtk~#xb!e(wLm03yD8iIYqQy!k>jF!DpPr@L$ar~;k94Eean5?G7#m&mS{>iEP}2P z8Z*bTi^8Rw(v?QWsv|YC<$vT5M#7MohOv@n`=uREoE@P?CDNs2CnD4p+~fwf5|BFv zbYaBAj?DSOh$m&q(IqiZRDuR00x9YiPQoU{?4sSU*y!fQ)7u-0Y@ss!c`sZrH>+eaQ-4L+#Q=XDou@TX-~Vx1I2t_gM+EWRen z!SP1(&6x1`(^pp!3!HP)gfDPq5|oO*%u=g5TbhTb4Gv&>l9ZXsA`pT1(m3DV)VYWF za?zR*5F-I{7;WHVOPfDT7AH!BQsRC0E`RQ8r*^mZFA)FSj199K{CQheFQ(CRtZp`O#O3aW*68mx4Yxek zANDtzWiu%44qU~(WL}1*v1%*Pvgv)RDMDW=yeU#p^vb4`(r1R{5&4tWf!5)kgv|F!wK8Y^lo)f&<2IIQj~In69@+hRzI z0<-64&U%=cHN>vE$W`-|)h8lECv(o=6HXF3`y?TQc7GIOXNyg00_4^DQPtZgR#;nx zIa_gvZzwP?&+1EMPZoF0uwsbCgg&WfvuBne`;Q`Gm<@1*04EC=@g8vJ@8b=ht&3~* zHFnlFI&a0cf*U1V#2OP~07doxlN70Y?TGj)a%k5aI?s+}GX1OiVDC~bRX|P+Al8wLp3YkOgfPZfj zF8Q&Of?ECR2sag~+3%~e;Ig~3wQ{?olILLs)Lklep@h=AEI7vlB?U=#p;Ar3)DgP^Y_9cvl z88SXZzBo~AKIJgijl0!C`xLAR(hkPH(D@q}!~!*0nIdiObz5j>F@=9pBR`?ZpbP&q z8z^1`+~=Gfx#&(AenHs~#3?CsYJ&^PiJXD{$e^qU0?LjYKtU53UCrY(k+KMSLLdr? zAUwV=LPy>EqSMpa9eE??m&WUd(NE_OLTulBqV2kNn>A~>5#IO7%gk6tiHi+Eih+aT zkKUo_0(^oOq!W^_+f=TX-Pd-e(^V-=r@4Bgy6fYLy`amscSTe1)uy4(bu&W=A;R5n z;nK}g&<`Kr1L_Pllf3=PWySYPNv>I&n%rZGVKt0;*pSDVJ0eXs+wF*e8+ zN019r>M=MA5LU3VqLL^dM{0_Coi9+k@2qzTigQM~FH|RGMm1AOrt{Yp?0xSW@O_b6 zG|HzQEsJYJ7x?*%_Pl`M0#*UmTKZ9=ruQllh5$o^6{qFGuylA-$(R}lGV-Ae`8+uX z%O-?wPBF!jLE#e$c5-n=_b2@UDQ6wc5!F3pm~23MY$039JmIgi>m0y#3U~QcT&96? zL=-66 zyy88pVqq6Um%Bb_>Ycnxhz|?F?N};+W(Bq-ba5Y690)nzgwqgYmgYCO8W7K-lnBHz zFz(;WBVY3ta+|rY>unGFaQetL-mM5OtqrxVJbxwTgU9CG{9x^uCC@@AlBg3i@zK!V zkGV$kE>0J3g_aH0cs`Cb>Q)_d54LICTbB6n7VGDcSCHmtSE0Amq(_obQCNAY#3HWM z;;k4nEt-OHf+$jfafMOhKh;#n?o#Vv+QD0}RV~ zN12CPWcm9e!b2$IHf>sIUVDD)$vAyODB|N3sbj6D)k;qi0=5cT=~wwlC~pva`g9Z8 zE|Qr9N{N`6Q4b0ue1F^y0-aZ-EB($6C+D zOeMArISyO($vg_;0;%krO)LEG%xftWz2KUZk1gDy(iK%nc6sZ)k^lWQ^O{PZ?2vg( z%7)zXB1N1QWLOvz4HuH_yPaeLFU0ikh*bqJHC>yem))(+is~-HJKn`qrnJ6hXmcTi z3fnNLO50a9){Tvnn0@vNt^%SMBIJSuGLXEchJo*u)2F@};%$P>}=m!go~IP5z~;~0EBx_c(RkaWH- z5xsblGX1N8<|^_|s^j4+p#EGYpI1pnN%<_HCIk~g@OjJksiBpfS%J->;E_vbubGZW zik04VwLYp-xVbsjb7GQacVi0MZl-3jSV;LgGK#r_azyCt@GOB%wF_0j!?_=U32wDn zW&9;c*+!z>s*dL$M@w28zGCPTk>WZ>9Vw_6)V3kcPZvF%*8mH|NR}etAr)0SY-}cz z<;*gl834fX&hcka*E6vtvF=oq8AaW{_^F137v>8==Kw4r=LHF@&J+iyLyV&^T1_L| zNUELK)XGQ-n>N_wj(@f%&CfK2l9xz{A_ScjE4tq+NE!2fjT>W^Q%DjT!@genNn6!< zn>%7p-G}EF6IfNmq%<#zE4xQPKZzk#f))WjqzK;ngxq^j;eIS+)krb=kkJwJb zU`uop@Aul5i!^N;_(Sj{iL%piEa@zH+c6|`uWA^o+zlrHw&b{oa3@;^3RW|s%6_pVv?Ue4g? zeLeba#auQm`?-5V;vG4;vKLTh-)*n9h1y4Zz@(ox$^n`b^NAc+pLs{;*QeR`sSep4 z*^uP%QbOwFET0B_@`rAm$ImD%oi86PKDf#y73t=;SShyKU_sa16U?4bmS~22Ea?5h zv6M~2a300`4L-&?xub$1U$TiaFr^kCGc9|SXLW#Rt*9&(foFeKnTae>T2EM_GmGQ@ zA4GixRF%#5^+ShrNnToz?(XjHl5UVr(JS2{jevA_w-@Q|4iQA8K~fO-9^T)7t?#a- zEQNLN%rJ9ipS|}v51QqiMhGIY)F;BR`DUc1F|ATZC+~6qN;E77dYqYXRH~7>G6ojI zITqigMQg-e;9HVvav8YOnq@ZK6Zz_TGGeA zoSyS5E!si6--pMTV#?RC%A_MXz(DHuj)}^^MGt}Hg`1TalI`0_J#}`y2*uaTukVdW zQY@GX;W}zLGs{dhZjRsSPx{nTB$k4C2pv8W&U(uQa@8zqXcKRLq&xi-4b96%=6)ZBY3Xze?Tc75diy$DY7Laj6{K@;G$%Tbmmv>Nn^rQEk4Y&dqX_11Wa1~f~q z`IZXW@@Dezl&0}0=?3{4xa{*STBj{=C}qhW6i4L`9%}F{&wow_#r(D{t44G|h@W z{57S2A%Lkc#Zx#=@b4bi*LVScYfG*hi{z**YKIw@9X= zEU|^7JS6wyh9cK(Nus!gG|@0E&J*aANre=bMe;D|PjH)OWResQWeNaqRN)bU$A245 zzbNW6_T4t>YGuNHog{paJ?g*oTPSm~J#9Xea<&2yPlbl0X*yT{3%=ZpexYj~&B;;5 zB#J68r@X$n?#sQZaqXmVN=q2JT~;4t5^jDao8YK|Td6zauVWN(vY2cHA5Fk?z(Q5+ zn9*e*GjU*e?dmWIlP&t(`+0mX-gCCmE4^!JPQo zyM!*GOeJqPb!B=nMt@rW>l#KO9AlnnFh2&XSQX_;o4hv5S}b^*I$*4H(NXuLz-0~s zvIt<{k4)ScH!y!h08+NtM(yM{%P*rV${eg^<_RhYNLED!l5yt?g%x$?n$cwHtvO>+ zB;d(&F+flT`HqD3IqIR$;PKIY?KiE;Qo76V`;j=|RVoI_=7e~+rG=D4bUe~bs^<~# z2uucX@t8?}DBqwr{z3T;HKElBemW>2d3uib74Z__3dI|a<8aWZ#MxW!1cEdi1 z+ZLDx-fv*s#(y98X(wIQCmq0cKVD5zNgXIHma@Y&$i3sU)QKgz}3r2sj?y@}2wO6p1Ca3tq%RK1#7p}f<;$2aR<@6AEfOx}j;`EH`%6~YJt8*+sfxpb znvz(FODeR|nKPb42*(W7620wM9%}{lJ5qo7O8%-zNvE<3>$k_-m5-r*gQY#mtMMBz z5B{BGZ?qL3E6EM&;F%U!XZ+|5+sk*@R?a=j5&~hW$Gw(``mxY4vwe&}=ch%Zuv%fr z36ILUk49lf@@SB?e6y`^d6CTcnyPiM25y)eH}J>b|1ibBNQuPf+ER&2ZlDQd5y6au z0vDY_qBpN>e9|~-)+{4O){-;<1?meE2GV{DnPbPR!u)SnJMJ4#r(D6l3tb3+NR?=y zG72H#!c4Iq2J2OE29>d~jIMWSVNo^1Cv*x_0E!3?<)+p^+8o=!IH&Ll-t#Wdx}$zM z{vi8iMp|Vmoo2WvA?){1d3-SqP3DAMyBb91R|AjWQDF~fX+=ezt#%^xd7+>zYoqVi zlpVibgwNRd9ynCywm)8`2y%32O6G2?w%3<~67%L833>E+96kG`REHD> zGCaoj_6CvE-de_XvVEk}&zTiig+pk};6(776mT9}#VE#dy_z%2P(~2}P#{oc1Q-Gq zf`|dodBs`z`O*Ct0UNl74uEC8mLc9o^7)k2)JV&mzMmi^IJM123!yWSxWus%fdDW~ zj|>l4-)Oqb$r!%&b6Eah68Y%E|Dt=~rTdY0-^q5!&1RbHDAHO+v)e&gMTM>Of4-@$ zRSe9pdXth>uY73S4B_Kauv~S$S37E~_CfYEG;NCRG1&36 z=O))?Hi=H8b8GTxN0-!q@51{mc=Bljjthso_;=1+10R|ZLtlJaBv#mF07G_X$zzFN z>t|pN2Zs<443*4~<{$p!=YmQ8L*cSO;rD`+l_{tP_8VYZ>Fpp!OGzc>8Dx+!PGC>- zgusgcBET)kM2dh_lUsk0Uc%s@C}$wK4_ry0m9Pv5jYhX^1Sp@l?HUWo$<+QIe<1V> zF8;?KJYUKJwZfqgERZHZ0jUFc@DB-Stsr=MdH;m)MDv6W)_*__K1EaUf(1peC=@C| zc(JMtm0ND3ey>|5t*<8iWQ(r0*J>==SP|?gN8)U=rj11POW^~-D!Qt?%%}>;V7n-D zYT*zeyMiJMf}x>ki=(A4MpX^&IsFA|CN*6hC-+T;sTRJ%!QKlN*D3y{!iRgAzoY|? zOtOPgwROIVTIaq(Ix|ebCzqB+g%tL*-dO=-N4Pl1;SLYnkn0eo~c56vWCx;;YCdiBXJ1% z>Bk!Zl$0B>f4%0=FUn0qUGz( zPu*W$)C5uMyQ?iNrfT>EbVZ>J;G2VQzfQ2|Uw&03H>OTO`*rh12Ij$Tir`jY?K6$G2EBGe+YD3V}()?9}=)SB4AgRE$->p2PG z1B!Ut^?)ZkvpHzYVvv&(+#oSUcogeyHkEu&84#PKwCjwn4 zugCbZn#UZ1D}r0d0W>HgXf(Du6O`@?P2y1&TAH3H*`;Vfj<~oQ0j2ghPQ~!g36(c% zkj2gI>y;!nET>Ax-GsaI?`K^#9eBIjX7joPOZ1|P&(Xegyh(NL~FI<`@+o(i+OKfsaR0>}f~x@y%%Mz0d3l2%#8 z52AyJ7Ez+<_bb^t1tcrxB5I4-+duFdbKtB&rxgrLWPnYQ8LRLNW`X4!Cv2o{ ztYp(~N0c+iN%6Je;ZMyx@|GDnYiT4&1zuyM|9IRtZf~M(H%NC317yaH?qUbBPYg{9 zynTG_*q1(6y2Bu2`X>~MLOJ@2%x~Wf$yW2Kr_m>v2jOPU(Q@CcRR|cHjZ8-CEO-_3 zF-ljOqGE8ty+RV^t?LgXXh1D>OxzCU`c@{b%r30_>pa_SP=`T6TZUzZDg|jKji}ry zaH0X-1>6r%W~U|ubJPr#&N{B5TMl~JTjA>;6j(zN+z^lm09EA7MVrR4Mt@g-aeR2Me>Kn?IdECM zirM^WnAGV*cFxRt=XaIm=I5j)_7!^|ukq=Gj@79f6>id$qkPH54tOh;%NPOYQceH-n6JUn75FlK`lvqgwnv z>7<)e8frVz98wyT;g2v2;POyv#uur#UqIw!75AwIYwOs5ffsnV2i=Y>O)L%`-Y4Yi6{yIAanpS zWc`7U5;vJqj6F_MxVZCd=UDjXgz!xYD-plJgkBQ zw$%IIagn6p{7YX7sT{p*RsOJf@xJi|Whb5Rclo_Qv=<}t)6D^*{nF!e{vK6Vdt8ZQ zTDT8vV*@e>lcY!VL4zYb>;%3te1)8nCOP40`7C?NgE8`E7M5icPN*2}9PYyP8FC8* zk+VwamdsXR{b)Q25Z`{fVXooV8cO@Q8cNz|>(8tJ;MR>t_|aKknANVUPHUymV?&dO zKJWfD2yDrryU?pMVEp40MUUHC01PHCP)=*|)MKb-cQv{6#I6UaaOQzL6ophX*V!4S zxO@Pe+77S<5Z&D1HpdS&MtB`>}L&Gb5&Sf8K1d zISbB(;0A0R@U@d3MAou6Dpz%OEaLxyG9CSbxy zcUY5p#yHr!XVg(;M+@}XKaJz5|@3jBmHCdcKPk$2Fq<4UuKJ04Zru0 zeAG=1iOWvUTg#vWx5UIrys|jk7vU9IjxAvC<4*vz_j3yS&;t91jRJ3OwM;ksjqVx0 zO9!i;d}+tpQ=7;80yF+g46+fs8+|PlFE=^}>7{Thu*fXK+DkSa>{d(><2!19tu?fp zUd3}{7*U5AH+{l}^oSZnFOhcI`HmbbE))HzBaAso^5k19Cf<*O>J(8NjHaNeH^~M$m!ri({Oi#s0TJkU1Zfq~t>?~X%a6_Sh*!n31QtiQQZcl)t)aKW3K&Aw z>4she_Qza%VA_YUfyf&6F&llAt07F;vNPoc>%TM3FJUkQ96u1-CJcedbBMkmM8UX1 z`9?$%k*MTjetU4Gu33d%QhrmS0A@!In6-uxXB}Ox%b1&8eOuy3vAz}}Y)jhh zo0r3tZL4qW5|E5@`Jt0DY?T%0W6ui!Y{dpNAGN7X6&&v3yp0wReZ4GSsMvfPeN$6w zQ*}@L$=l0SR9LF$z3<=k9;2b(qq69A4BR`@zs$2-U-`@%P;PW;$FF$E(g@6AF}!+H z?#l>2lIAQ<%7w->m&C}xg^^#yWQe>o3`MrI_=X%+lJ5W@W?0f_4h*+c`&fQ?&CMoR zevoMhfDF56ry^hp$oDR#N}<_Ns<~pcq3vcmBBX90&ETQ}lo8Mp%Ov4Zfu5rW+uC`{ z_%+?W$G(YfmdEO;-?$~Fd_I(79&ap2$ASAZm#RJ;w3l=|Y0sm94%Y4ju2>;j_IYw?85dfib+n7`9EdE&of%>|r17zWi7q!rfL*-^w*Vb+`quE9paPVOL=`)f@%Yu)b zr?9ZXi&;dWL8zTsP!L`bziP*;i8;~^4o4yySAt-PQ1K&zwW2}X*Fy1rey6XP6TH*V zAp{VE_ySu1HXra|%fTGX@RoNrwSmq&Ehoy_oX1nO99otCe(1{CO-YBxJh;m@ag1EZ zMn8=FV5`>a>R`(EbPOuge?vg5F(zoFAce0`<3^u38Jb~@%E@Ku+hRtCI5Y>}yRSlA z;Y5J>N`)ZQXwkDzD=nHUo@2-n{$n_qp*@4z%Y8P03VoY*86d7>p}Cy<22;(uv+}Hf zwSff}AT5uTfU*T9omd;#eP=xHM7Qt(a^Oq==yD|{(qM9wB=8|g#on~TL|f1>2ym(1 zGJX=7!2%Cj4@ga4W*YRn1*F!AkK%Uz+faE-Y9oPwt0MpQB(Tu04mAj230Tw{n$=$b zMGQJnjswhxzp}EKeRtU`P34J`t)HB+pU-brz2f2_oBFr6IxUn|G*$dIwBLa&P_4)A zbKgo}8Jj2HUb1G$(RYlMpCYQ3I&H4L`zsV!D%jU5K52;t?l#(jh|<~0MX(V>BLZ!U zdAK^wz4h}kTDfSa=B(1H$r2n6glP`NZA5|&0WnK1rjdd+6x+%Pkp3|?)AXStoT>PP zifnBe3hf<;WXWhP?ZAiepSS^KaA28LU+>@Kdl(#+hIF6t8D-lZ90Z&JkT(~qsloG` ztr3+ZN&&|i+SkTXI;0hbr>g>%zyoPv2mm_W|Fw+p`2XC&bM-3bjwmI?6CzlJfdi5T zh+t*LOOQTzb{$ZIf0Ka!-aOi9`a`=JmV~X38TgAJZQ%2YDNTnPIUiZz81}mR`@aZA zML}K$7@CBkFB~x>!S@7+1J*j9zNnaqCpt2X$P9AV=NlYdI#^q(@*U3(z46{VIgfhx z`LZo%VbnY=YSWe2C*a!Rs?PqkDoT`{7gKWdPr~w@@qF~eQ8OV6My(=bOI*#W86qi_ zU-e4C4h6bZ5tfN%8z-yy7)``<)i^jZy7;KEFkzx&T6ZfK>T**u8R`t(N-(#xCwQ3C zI=4USrQV&v3?pj-iAzSdJb2ZP$49MiNQ@vR31 zhK}?bEB0JS$7Ef?IiWHx1<5%TO;tXH@i;bKW}_yYYC^eKPKsHR=VTudGA-1nV5BgY{GCQg^-F&ilJJWhC4>B58-O$ zUwK~UzC00lIaHjM4mO=&wYaS5X{Zm>Q6_{6e+~dE#Q{a# zpBzo2tBG`TK9Pf%70i7d3m9X~ZOnn-{`DRd&OL{Y`*E#tj1j;ODvsrcwFS6M*3kNi ziBb|j=gBY%oT!u*D&=ZIiUV-l0RT6Q1A{o{HF4}anM6`^ID*_N@B(*;m=^y^ca-k& z6Dj6tn46s1Ye-)^@_`|tYcTSOA`Zdru_8mqnp4mc3vjZ>r11Zn$g zpPW>$j$h>TJbcmL$^6C77XqDo7EbCmes}IPQn)CjU43acc~P63o@#@S`)YO5E0Sk7 zkyd7>Ba5M2v5yvG;oM44S7nI`(^PZ4Qe%)43kc0A9N39ncTa&fb`&z^cNC%7Sz6Ru zaiE1qEno}9O2}Xcr%ubvyQ-$OJ_8iSie}0FGBRf>9AZEYd&|0y_uJ z$OTT|_C(01G1oEA*!Mx03qv^5I!i>QDkw?v{+?&vyA_$`>D5GN#r_G!9&TI$0S1;d z8g8s5;jH3Kdaih7`G$oXHC z8oFs_wr<^boDrBvC)0KD&8qo2o~TY8?ygKRI_z2Rnxcgpj?t;Y2=5>m2} zv~aiq4A?Q66KJ#_ap%UJ=VJXfsL9VdttCM$5w7-;Ho|-i=~}^af82Omo}{@{0YO*UUKKgC)>lwkJ83YalfXkV2852qIfQ-~b*N zw<8r{D zybTWiRM=NtBRa6_))U*%E7n9qoC2s*v&JwQsvQd3plYnl)}L}^N!r+Bkg0vgSmy=o zry9aD216Ec+Z6i&BAId2-;uEj`2``Wi(@7rRgh=7kyt>bgq9skpRS5@H)0$P7mWm* z0dBAl@K6h{8HBetZcsxI-a+@E`jqTpi0GQU@};a^*5(4?q!R8+6=u~#VTjR91{gk| zfwXF4{4QrPswG#9-*b0F{<_|;v7h@9)x?bQ=(E__bt4iCaaeVnd;hi8%n*5&YDoO1j?dWZKC5SyQuIoh#^2|rIz3r-F=wm=+pwmJ zgpw^HG1YWTnqXkfg9W<)l9GUmN0fZ5+u{53veMb{&kx#zPUSD$t|_r4iu?4JNGJ`= z47@DiYedpq-Hb_Ns8o799E*4>Hu`G$G`ec$x*2{J#bGu5Ufd&GJY|>w7)C60Y2%Uz zNwtX(?VG5H#TpdF9c18k0f?Kx)?e5Ukm=cT$j$vl{!B9g#0EedDgU90-I6xpbE8$T&HAlK`G=0zn}MkmYyl#D zx>jV>WoloP6m)slz&24}Pcq@f+kfTVE!~U@JALljUypm0a=a$?zNbaaP(SIj+c`)t zORs%&k1O}LdXyV4?PnZb-f?|moQqd5N^$cS51@VMK)*Vt*`P1vt`y6aOu^+Z(t&;4PoQaMJky2D0n@WA#^WNYjVNDD&zZG!mu0)2X@2<8EKF!Aay7IsjtYO zL(AA+a1g%FcN@q*Phz2lmi@Kiu8In(eCPi%L$T(1WB+rp^Og6UA9(9K$S5|l>PK=y zC};V9AHP4I>b_Y!P4IF}2@3C>T*X;c^}p#ny-Ht6*?1!suio{6M&F-ZwJP6=G=V$N z*LU5Dn>*H4-61H*P)f_>C9zx5PQe48Z^X3I(kd5vAg7_MkxqJkF_+|s8RuX%R3M45 z@qYMvhOe6%yjs@meZ>GA98b*&E|q3zKR`HgAxQ z*s_zB$TwLW$i$@#*=rfD68KLlXFsk4XpC(0y<;^73FH)w7PN2ARSd8XVYkYHLI$@p z+5u1Nwi`#)arKXW;`%m*nRVTKcYg`R8>U3QoWywv7{;%LPgXCU|I>69%!xAUG@r3f zi#=o##Z4FGF!BuE)=kMSa z$gm39Vq{!;h?`LYmp58d>{#aVqEAi6_C!naV!q}N<9J-t>pY^WbHyB%6irsLk1Vo`Seit0NEWbrM% zKsjw}01GuyD7*SHT>~M!*hI!*s|l;IA`)zZ)Q|?_COdBjNq+oB?$0*E9I7T7^I=Q- zjX>qlL61!)9XoE_eCd#tlS{PgT9swgnq(GECmpetMwVsF)xtWWtf(%b?hSYe0XXW? z3X*N!+(d}D?`ENUUERm`>EBr6BT!&(f`w7m5vBprX92^!Brw3N?;Get0HD+)OP{uV z@>!MR3V6%E1#+iL%#TX3>Nl%Nj=^Vq1KhwMgasgNjz8d@HYtu@op+djJ;RwD*_k+M zjiPTl^x>_yd;fFe{llMclcM8#RfN^4ubnA)`JHs9Q#AO%A%P7I(#VVGwfELTp5(Dh z&j(k(bVe$9ID5;dm!|ezkLk1)j-RWvzDWprogl<^-)_#X+|<-)Gv43_e>EB@8CR`c zuW-U6$V{TyI^xsznVe~?%*?knhvHi{l?mE*V)5p?kcPh5m?JWFxaG=T$@;1qMo}Y- zSc?S|n2{k1p`o@i^+Fd3paGOipf@SSvwRGrM_9(7%Cdp;ScSq7kek4Pd*E!VmjZy= znQeaj^#cwYT$a;#@#6rT=1LkGl`qEYy+NC8@)e}zl?9_L6!6oaf+yDXU_p5v?-rO^ z*V%+>{OZZa&hh2wq0h?lY45t-g+DLltA)Srmd1B2hOQMfAnhXc4A~4y`hv)NxEeeYlV&~N+r)hewV(bImB|BJztVbs3G%ZiuAUse)6s6HMwX5;cUX+>(S^tsr$ zhE!{;FJ3WFUR}^2R9-V*!Q8Nn9U~!uxJ)Ds$i^RK_vx`@nee$6!^58G6Ac&(Bfl-Y>i+Oj+MVA)q(5EoERKCDF}Yx za^xa_9u3$zIS_Dr@v2g zr8S~}zf4USVSQ{vNgEf?{AIL{G`FjQSI`S7P9#~Tz$&<|vt&$Lnzcb6-D1xR2A?^d z#;T8#yzAwpTOFmHQ;$G5iaO2XC@P9e5A$i@)1{~?LiYz_U70;oC`7WA7L~XaK&6@x znyBd;9q8my>xGL4HBbmS%s&DJz_v%eJ8sR~#|ClS^+)|^Dob(P1)|6h&(mo+nLiE> zp|Wm4rg(Ozm^X1}%f{&8#$sv+MG^ z(pG0s0V@e@P<`GffUEkVUE!~h-)0v*iB=x0)?>-UYR2Gb(Dv zmzKXb)z+3-h-^x>&pun*k@(fx0?Ekuyl7l$XB?6nnhL5^?2%)boF>ya&ojDLpe|h1 zB|>MRBOle$E+UEx+TQo4yS)Ge-fcmLe(+#k3X6b`3c&(_iUhX8=d`Q?E~ar4cV#h% zPNi30&;R)k8vcW)|J5&m#5N!wEzS?Y0I34vCsL3!zz3;=XDWg4@wwB(g{fdEPsq6n3i?RliW>Q?&CDs>Hf~sgNW5#r(cD>Zc;hDfhTl- zTH|LIMb%sd)V$+wi!slZi8Ou~$xdD#v>+c286n;orYToU>uNbd47z&&Dgd9G0>LQ2 zV2mTzFh<7DL%+Xktn|zCF+=c!_}%{Or3a=lyXM$2{Xi^?0yySgW>HlTS(rBKQXv8C z{JCKk#q%sxs3g2lVgLe?4^>Ax6CCZr_%m3tKO02 zX2OARYTfG4_8}~fIW-}x>B=2AKkSbP0)U9{9({j@`WApGaWM^pBYMuA1fZY4SS!%z zt{LFZ5X^XOnU^a>m`@Q)yBMdGXW}`N!T|;lC<0*i?&0Hi2c@P%|FDLCN$DWMaVNv1 zekZb~qW3hs?rC<&8fAO=BMb3>EJ;Cce^H@OXe6t|woW0WyO3S^iu4ZBq?4Vm0;O^z?Q+CyeJJ;bCe<;BV!z0G9BIo>Qvq!rG>+gt&T$9hNo7Wqj8ja5mq zN2quyuyR>DTXvF50k+o_<*`b!hB4OPh(k1d1wDU+($X#6<&N6g4N39+1jk2Y-5iR8 z6Tkxc&=BCOZ~*gTIVOzN67UvEEdJdfi(88nBFi%P2}+2wLs+h=h{^5x850(a0<2e~ zq*Tkt$N!p*nqP$dp8l7pom}oZPes`NACM9QbXyR%WpgYj|*VL)4NJyE#UYW z3`89N1(dCg7QD%TPRDt1QMZ2^RVT5?o*&3t$N~rC%~&0V2JY!7(t?_ZGQp?T{;%{M zkk3jxtWDj!s-bPgeIs~hd%65*?I>LJHLvi!U(nzYg;o7tNKyPzRH_QCoLISICn;AO z8+@TXYXvEMI~JRHaKuluG|>yj#&B4_7rCH}t*%WQULF&PfjJY}IyKRYW}!u|-2>Cj zZiO95UIFJt=rk3hJ={p1tTK{!mEf1Df+anzQ6<-F@Tmbl%)}^p(env%7_S>5(^Ov$ zo$s@`x20DAuwFQ@q~&IE2mCs`8*#G*2kZebcL7LV4g&$U(v8+}j|Q1RfH?pJc0u(G z@-Z)!)TOwe&0}D4-Smt0j%)718{hKlEl$D2&IA_(H^QNI?N`|{xA>w{_95ln$7t;9~Nmp^poxt&_EpY@;t-Ot%GS#S(P&yg*hw#k70I& zQ9#?b>6Rh3%BXn3yoPdsXxRcr!>49K!0C5AL;*{Bj zX|BLx>PupKAaBo~E&YdLvw{L+{E&HGOXAD56CYsz zjxuhssxS7N9??VV;lYz|*NOGHZ9kg}zYGsHS!*(%C8Ci6Po%AUJr{K%t^<0&9-=Jb zC*(wK#c=3AQm_`SQ~AijwB#Nq?yjR!BahK=S4Ih@3b(<444(bRM6^}zs%hlB{X1ic zmv;l*{1B|88#KzIDWXcTd0q`*dU1dP>nQW2 zwf#w>a*d7OhK2cqCyQ%Vo{Isqsu{88)<*+Z*4LiIHV(dvkwqU!Dlq!mRK67m5ReNx zF&8YMLxqrWKlQ?oZckW;hpAyFa%OlHd2xx#Df_#W1f%IU75#+z=ysah7pJ!<=Ub=- zAfW}Hcu8|v{tjXBDQ1=t=5?u*v3E6KE{+lbZIlF2X$2{2QmEF3c&dRv?i_sks(3KK za@@Y>y9%pI`BY@f-rlHxc5d8g;n(0B_$l>Rf0l-(q;e;MuAzGrzzkH7jsy>7n-cbl zHJ`lX&OC0_#S7y|D8Eb$Zhk|!8TlGSBYyu#KRG0g7u!;=hD5C`^#kd@KA>F_YCJtl zn4X@&m+IkG;3K47zu{xw%kkv5HB|l@x3Tm6XlLl4Wn;3`GE;q#lG0;F^!_~OVqgt* zcpCe>z@CdHExIy7I6vwxKkc1kxsFP4gllz`;TVFZ?TyWb=bC<#2w>)jrdb(H-inS{ z7c2p1PAG*XM;#7_jeyC(*N2&tq;;xQwO^q&H}2!GL-_o=F-M}8PL-v#ltFBD5RiiC z`|Y^ig67*Z@LO~2r_vyk>F2ifqc>tt^qcDoDn129K>tOgtQpac_e_N>G87H8{e#>@ z?!Sk$sTS64k)B%QtFgD6Hs`gwLRRQvxoZv@Pq(m~FB$N!dzh?T3JWQCC2{cRQvUnw zv&SCK;ZFh$58SHhSX-uM;&*m~t7pZN~s?1i2a_danV5}65Uxvo`ycQ)yL9k4wlYB`K8^u_9 zq^2(whyGijkRxPS2?GF$A98d;0@q?@J(K8)<&VtZo&XX<1rSh`Ke^DlF*Y3$SiUwt zrp}QFh6A=tME8&ZVEzx4$vM~6aKpUvMl$fO<0Ic#2al1a@DVX_IP$ac&GyT#L%+c$ z`#?`Ow^*o`=k1Lbn(6Z4g`?%$^Q6|XQLG+x2a$ugp;vBtd{*U@M2!`ps4wT8f#>r9 zHR@i>+77qf_}MePDVi*Be(pib6nAlr(ycLJRGY;h@1E7=b|*UUhw-~OrLB~F^Wvs< z?|#i~Ht*bm!3nY>XK0MloYraU-tdMb?U8na33X)d`hrBHn6G|@Q*;@#K(nodQ!~(l z@3sj4F^j{q+)V|JN}^Y$B2<%y$VgXK#;!V@?isE_37BcZ%_yL2G*}KF1LeF9Ex|`V zfK-VHsBr)iUpY2l9sm{yR==bt>LJyt?Bg{-1c3KwMJ;@eoC_UtRR|z80&a)L^#}J; zKU~kC9>@7~SL)974VImtPio^=4_tNnmLtZ+#*#$bP3C0PHkta8x(h4_3Q+LFc_#MW zK&l=-i0fLs4Lp80^|`!XR;3i-_oJ*?fjp=gKmv}wPCouzU8`M)!5EHK%em>U@}hKi zXa0?(Y`XdlpVD^+V^uDNVNX00|0HukFqg)TDS9!;bKue<5xScgx5%5DnX~j>KVnj` zR#(?PU6#XK=4h}b4G-rG1K=THC1hdVh$$n`ouSro1c&4C(aqAhfzWhL)C<8L-JH17 z8{!G_Z=j$hfF%NOz|KZ4ej&#Wzyn0NyKvLeKdHZ2Ry9jAH@~h&7qK{Ru;+=gRIj%u zuWJAh;2%N1&RtSVWMgg(={2_cO~dV}*Z6A-5w*1_(TkDYBIe^0LjSRFeMubnd=~Jt z0igYRvblmuxBAU^?Yp*-p2qryb@G4l?FUs$hSfb>o*y7rab4M0)AqEL57eEhe!cU5 zyT$Jr8|heBjhYv&qbx9sV!e0DyQfz=FM1%Y{Pj!o+2y+3Rs`t1BdBV#jwpUa`U(oN zT$1xbSz8aL6icUb@ZniN`y43|4k}KFD1DWJOzg?~(CrEtYAhQ;UND4X^x<%mq|!JZ zrlmlrF`Lc=rUHFz32L?gApITu7CFHZtiUj3wd}xaQQ=fjLzT){4+ojH1=|;lNaGKf zZ!)Qm-khd~cmGj!5bQD>^qieMTH4{#T{8~Y67${cqNl-gBBMxCJ+I(c$ar1=sQ*ys z&ez;Y^+!`HcArK5dj7j3S6d5GcfGypB!kPC`unBtCXaI>tlimH=i@!cCeB@ABgWpc z#wnT^*{|W9GWK3nC zNA~moaycy@&(5H?opa$obc2T0_^)P76Dq$u)nRu3y-s@XlUO?Q(#2^pVj(LX{V!)w z^PNFAet{bBLhdk}WHZc}YUVEB__eUXKJ}-Co7WvI#tP9zzc}%Q%EMH=D_@$Unp&XP zZk!mZ8t_S=Cr9hc!JC_tD#|IvYGu0^+XycjwTZGCfoB^4cJ^CTYI9EL4aTQioOf#! zfq(L*6Q?}DEy|Q9)|Mc-04VuFBW_3npa@VDtWG7Q7@_D2ESoSaI2bqUC{3_koYznT z5kfEcR^SuopSxe!K%%5m4!d2J^}n5L{jtrRB1zafUneKL$6x?^&tt#9+w<)}wrZ(Y z#Yg->#q(e9MB*C&R$9ydNT2S(`$aEku*B!YbFuaNsew!lE9703U>j?inx!8~YLB5b zQ*29%&O05srJ?SF@Okg1F1hFviI%R^AnD^hBdqhJYY;#d$x? zt@V7T6#Ms;#r82=+Sb;tZQsw%^ZXv1P^04zFv6g~I^HV>* zcC{}mCw^QN*F%TuP~$x0xAQj@oZy2IdwA(ixCpGq9Kbb~Gum*m9J!B|gov zbzTEu{hl1G?v-rJhyqq}sWOhOB>~~&EFO{BQY1Pz$A>Ui2yaCo3fT0gy7=d2= z^%rxF3#@k`!p1_`5)CdzS2xU6X$*`BL;)T#9&KD_UdImY2AKQqBaHo=;5zmEqH=rH zMt(%O-qxY(Dspthoc6;h$sYj~CBN!F6rNan-&ApRys-y2SYMb~+4=ETz=N5G@zQw2 zd->z{S2@*tvOCfx$$}L(?^jLd{k6P?LbX`UM&&|JirajgVze+vOma`kvon|_>ok;m zsI^_{1%gv`lCLojWD=R;M&ZKZFrBDmmD#&>2~Yn{2O>i`RI+oh;4OB-`{O<+w#U>b z$+GKJF;y^XH9gOs8cKDv8aX5g_|a>|m4*J;C#>?}M+JVTI{^OzBRofvZTvK}ry4NG z&l1!-_Va{ezoCV{LIj|$0B9EYZ|{qRUAuQcn0zSx^Zfp`o`Rk2zO%8*Cp`@D_rL=t zS%8y#BS9_jgG%J{e>=Y$12j+wPSzIh+c4sz4VGnx3jEn#vDS4TO6IPBEHt~FSAO-K zO0OzzO*p2fJv5(FC2q}_n-XSWkv6o=8|(flXEkgkz6}_tF*0@gh)$!^Wo)p>=_L&eVdsy9(5m6Tfwv#MBj4o8$~Wg5_7QCJKwiH>g4ZU*B8 zjY5Qi+g}_B78*@u1d*E`HEr$yaQT8AkU#)1m1~1yr@4o9JKSM}l<~InhH!n;x;Ea} zFc_GDfpF?qt`^o%Sv$oOaSM_~$X{BQ4b2IDp&#uv&zS8`5Hk`lXEeJn-&=!Rnk zlGdOlny}k z_}kgRsARggJHDx)G_RdU%W`QgJnufmq8@n$u`DgEaIcRQMM)zrJb-X+zF4i${Jl{w`^{pTl5Sq@16A5m( zy*gEX8zasbjtnYyFb;66E6Bj2_s4uY(^vKeNWcUzfgZytN;rw0#mft9hyt7Bo8#N0 zr&7l3JN+lU_OIUhyqU|Ie!u2cHb z*GB9&WE_Yc0;iH1RbN=#5h)5$E@w?G1VEcSx`;Ji;Cu|RB+FfW`6$}%Uv-8r6F;71 zxvjq-H4HlBYv%gkdDG>&cg_I)t~ney>A8zgj%iSTI(mp{otaD-I(HO6U3-x6p^SKH z5$)mLX+DhG5QemUtqMHuBl>vpibGCzg-cUXDpZ1z`FZYJCHqcq4CDDw^i-XAZwBrU z=lg}yYI}BMTc|S^tKz4|^1S~r;R`YkiE(e{F!=vaE&uWYyP0ZteqW1>(A&O3KI%|s z(38S|%_Ihb+mPoaBB||HFwmtc_iYz_ZhVpD%n>e0x@%A&1bKb?6`kfw@gf{S8v-oc zRZ)yYQpc_mj#aG-B2wfjGf=LCRs+)t$&~$JdNLZS-e+{@`k-qQoILCT1wi_8poL&M zr8Cfi4UmiE4Vcy8U;%ly_Q3mf(8rp?m$V}O2K_qX;#CO$m{(5J&a$aMyX|(= z9!NOMR!X7a_Eb?lPq|CP_%m}pZ%qz=*85Ab2cP>#?>9DqemCVUXHktd&C7zPEw;7E z6`d%e5weyo8b1JK z5_{5eG*l!f*}0HNRQQ3Rpxer6!peqIkhcR+KspK`8|A+>;J&O9BbCFT*k44x6M$@$ zNGKDNqHr_1%^+}7fq9h~#v}b(@X=h0H#U|Z{P0*ds~o1f!X5(NU|q*xca4g7OU8TG z%M*t!%dHux;UiMxM1!g&$bHJ}zcn$FC;RgA%Vuu?GV|Pd7)$O{T2I^zd-j_r19G8% z1z+R}l3#MMplmqpQ2c$jTa%_yszOcB%t&~!Qlt`FA)Fq#imX~?nBD(cHjHCl{UF|M z7{+}$eYVsX?ZvK#!_b{?NG9QxZou%dMa5dhueyqfcia|(5ly&)REUn6#M4s&nKm{S z91B8X`J8r4!yr8JPCM?U+b6qz07ORM4xj)ZPm~6S9rL@H2A4-r_LXIA;u=gH``?i)W%dWDAV{)h<<{hw<(>g&+@-PNDU_R$-UT?wuHZ#SNORTE6?pzxkotEfBQvkOV zTqA-)^X!e9)*~%+O8mdSC0zPWAHn8hRJ8ltvhoBWUIB-t<=DR*o?2F{7HqLwyDa6CTE91^IF1;IAfomCdW;??hLTq zSA;)pHJ}rUm636cm(gDZNTdv z>`X0vQyKc1rk2oxr!mOm>i}*FZdX)cLdoz-9EdBz`aH+2O*nuwz^Lk0kdcE$QXhSo z>p~mF2%7ma}Z;wGT@FqyMEf6MIWh9xKEc*FkqIqV2PS;t}CVkh~-yY~LU`X^VtYC}FxwZrgB z4WBMHkubQ0Xw%NR|0tgLa15!f#Cb)p)GYp~d1_|!Std*iI+b0Kt4(6~5;XUVnM&;L zAxv{RFrHY%W@FqFt^=6K8Rzsg6H`Mn-|9CP{QF7S4^*c#=u~j(N{p+`d-e`91;;A) zz(z4(4fGfX(oiG{X}*8Ci5oyEBg=eGPmaTRl>um5K$|&iMOmZQyiCszsS)jH(fKd0>7D$Ztsp)c$?ZINl9cg@eU`cp&enyqZ*Wp6m8X9(v1c zL3G#8eks$xv^-WSGsiLd;)`R}j@OZkj^?Bd&lR0)>wnDZ-ZBI3U)gLERdB5)Cn6|# zw$ZKfaI2)zDb`4u3;6hlke!~i2vYUkB3l%RPN#BW-KQUA(>b{5^xBPHPb}&92?P+{ zBi(MRPcp68SNkuiLVwfvd4X28D%)VSmUG>q8BHYnUy<*FPuU5a`oX|SR)82mue6~T zdk>ZYtmNPk%|xlua$wPeW5t(?Jt_?|oAE{&qbyD){;-N`yMgoNqrP1~Z}UxE{o&V;U>yKM_3X_$I|XScIVF<+&9mMT z@ZXIHinidfHD&^ULM=&lX{1c&dvO2WIrxMQ&cXEwIi6YVd`^@7ye2`nN&KL0Y>+03 z3!EJU(GJa5Iq{%=1Ew>b1a)XnGZ^k~*<2pnsEI+5(Er5+{*GBA1AOZq44T}N`JAHu zkK1^$0EMyh4DCJQ&r)O~=qsMso`nq_(39D!C@MZ>$8oBu7Nlh9)lP?}b=3(}*OWD_ zU)eR+4m$+L&&6LT)buSR%yDA5s+|{?gH7C^>L2P;mS#tE4hzgk0A z`e>?DNBi&7U5fqW#}~%>IU0LR2R3)$j(QJ(KvSKrwkH)Wzx`}~$GNpy%Hy|W{yGhcdBZij)!s~3{Z1Ok# zX3b5_;Ab)~=32io=e=y{zt8O$Y@kkG=_ezGbY~*;ETHb7t7M#Gg5PoEaVQr%KarYS zzQ|*|CEV{c75KZyW1pNV z29-K*4q{ezqJmfDc#*ZESAIRH_BL5#47 zF5Y(XZU`^VCIN_*C&njE-LiF!01U$att!PXd-6XWj$8JfD;?!B>=^~dXc%^YRaNZ7FX*Sv)y<1j%9 z_H~`>OI=>Z^blmC@BLOOOq?W-6vL#=F6iUl*SDb|&|G@moOqLLoz*!3P_kgHuvmSM zP@lK4$!g`7#^n<_OQn3vJOGw}|DrsK1yT_nKCIpvy}2N+4Sq)2V5J-Fq5CzIL;1r2 zK&5*1c{dhs9-IWsfs@yj$_5nFix30KF&>;fAWTxm`90F5u9*c>G&%+v>3{F&@&U-fiH?Yb+&Sx`an8d~&7+4=PxzGNODM zo@G3QigF)@*6}+kjGGUQrEr_RryD!!dQxJUz2^2hIx!^hs34VD#^{w_Thc_M)#>>B9Ugt&3 z6b6C1-yq!gUZL{xep=!Ok>bAs&lg-~y0%C~QewM#6?s2Q{?;w#lxSZrAqiG+xb&CY zy={bW{K2dP!#uTU^0oL5kF}a4D=GHC9+U#Twf&>toQ#o0tB*RFNep+BTsKAzUTq9s`tq6}-yy}hD|JTSJz-^L zB+UapsO27%qPSM#=OlP@^NH21>A3+EeffMXleQXmmGcDwJ-MMRm)7DFOZrI|{L5)ic(Q}hzv88v-L#!ao! zoUick#ucJ%b#2Qg*1Ia^`88E3Besn0UCjV*k3&^#X}kSnvo&59Ws;-)eNptjm-da9 zWX-Mk;Ew1t3VHea2dpffDPsMpqY~x2*Xyx1gvU8o0d&SLiELcq(SoN(P9>42)s>yj z?&-5Ff1Ifn@5N{4LS`Y;e0lU5o=CHe9}~5f6Y&dXIU4-|a){)b())CMqF@kuKOkr- zt(DB1_q5=2=LL0l;3zu^@yWX9Lhmo;L%aYS5ZFZ! zV-Qs#Q>Qe%n**{ayOL=ODw}M;PaGX~65fs(>uYMXh1D>6o5E{v)N_8iVB&uOYi{VJ znODS9Zfc0JBm&d5WBwJdQSQs%!SI{2*fI-6&hCI`TD0sc-;+xNLF@UOA8#ybHdN?c z_H^p_3JrVv)FoOzhQX?o4`SY)BH1E4BEsBfqLO6A_XA%Xs>N!B2snyKvlm8BrwpN1 zo8nE_)K5P+bq+N{-u}0ZsXiQ$@9_Id@i3+~{?}(^F<>at8arSe>dn|9$!syA*Gjk*4IaI$o@+^NwiOrL@V;F0+BuOtUl_lLoTUet_d4otq z^k779VJow|LvZ|@Om2Xpc7cZei0QP4P*RwS-1>!Pb z*@R={#|t=17qQ(K*c>i^$T28r1$1`4yYr(1D_~ssPtGYdTJYZ6w5eRgd<`0B+qSQJ zx1U~PHkg<){OT_`_BW`gZ4Q~Qwcj2V-W!$OOKtg58}msHT)10m$wUoSFYPXrrJNkG zcSX(}ABJUlebEJX&VutUxsW9-vDedz6%2A_WU|>&)><^*c5V9e{-^uUvA29sQtGNo zrDoZXc#hE~G1t(dbiPY`w4=mBj$Fv#EG-V<4I2~pwz!|a8T=!B16H0gyRhz)1D$** zDqWwP(F!Y$;C3%po{HpoT9BX)|E#7_UKtEs&sA6q!ch1ffzQp+Nii#=TehfQsG0j> zh^;6v?ef20*ax`k^Nt?eUWA>$D4mQEKM;ZB(KyJDhg544D@_84^Eo#}=_0f5ZMm}< zx|Qy851Ar#g53BlnQp1*?n^-qp4~G>Vfd9?7kLJEA3P>=3omMLy||_85t976(Yu-r z#vG7TpOcE$@YRnJvkMGqyvh5)0=i5CcKq;mNKnHLo4fF}&|CioXMg)nuOqwdo%zVMNZ;nA=uC6*UdtL>D5|dYv+a?(^a)-+dh)6~@ z8*V9mpv)~G0@VPZhnqg}E5e33FWGs?+EXIwgrBwMqUlw8>^T}Hu01ETNHFC0J3}XJ z?`$a*X=@4bcRZp#Z;$m~IQyo(Gfv`;?*{X~Z4L8gSMScTP9wQKP5)7Nh>F&I$l;ke z{Yfnr!@d#W1^*9ff%cde>45c)~etwb~8SbV>YeytHs(w=p$P*W(M zSP8q$5}`@XWQ~sGmUEwyWFG8O^5NQ=6+Vmb&EL233T7D0m};zy>R-Oan68DY+(K2< z`wG6Nu&R{BZ3SBMYxR5?CFON_%O6!^sHw?HD04UJAl-jNCa2MZ;t?pM(l(wdWRT8z zwq6*RYPB5i2D4~~c*aj5m8b3Y%?1SMtT6X78WaV?IW_$%Q)2dSGrBLVwpk2-S7%O= zu0C+4NAXgQS{=L!eI*&57?c9G+s$t&PEP8&KfP^Sjr_TBPb%3IsNFt+s3*pH$TN%* zv37*^zKv^tk^X&f5y|=_48{ZzrVhhLlmbf@*ZbT?uK~P1euuUsan=AV{QuF|e}H9Z Ke>-(S0{kCVW%z;s literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/mffs/sounds/field5.ogg b/src/main/resources/assets/mffs/sounds/field5.ogg new file mode 100644 index 0000000000000000000000000000000000000000..33221db1a11044593fbb3d881ffb3f10848ec052 GIT binary patch literal 36591 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 S$7R~E$3+c&V78wiMAi`<3G$H@Z#8)W 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/mffs/sounds/fieldmove1.ogg b/src/main/resources/assets/mffs/sounds/fieldmove1.ogg new file mode 100644 index 0000000000000000000000000000000000000000..2f352536915eccd42b3bcf5859149a74ac55e75e GIT binary patch literal 17946 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/mffs/sounds/fieldmove5.ogg b/src/main/resources/assets/mffs/sounds/fieldmove5.ogg new file mode 100644 index 0000000000000000000000000000000000000000..5a409eb0abdcbb54e79510eea91f50840ff81734 GIT binary patch literal 18876 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 TN0&p400000NkvXXu0mjfajbTt literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/mffs/textures/blocks/biometricIdentifier_on.png b/src/main/resources/assets/mffs/textures/blocks/biometricIdentifier_on.png new file mode 100644 index 0000000000000000000000000000000000000000..e3e465e338ec96a12797fe10e9ff6a096c9356b5 GIT binary patch literal 1733 zcmV;$20HnPP)004R= z004l4008;_004mL004C`008P>0026e000+nl3&F}00009a7bBm000XT000XT0n*)m z`~Uy|8gxZibW?9;ba!ELWdKlNX>N2bPDNB8b~7$DE-^4L^m3s900t#VL_t(YOSP6u zY?M_L$8XrUb44S4&ZE;8w4G_^(RSLI={N6JJMT`PP+7E^un{OBJQ@lGN@6Uq0;vhB zVq6%v>cT?8Mx!nah!A&1Fs>vdh|yescW#-I)LrG~!wo}r<^VAu#@&Om=4;12`>tav;w^Z|>HMU$y98Xe-j zvvZ%@?e_cqKL1c)*gtFplF4`?5lg3&u~;M$2?c}0!@~ieZ^$r=Xf&KmCgSl}CNnxd zSuTy0@`W7h;c(C&@OeCL0D&bWqP@Kxr(?Uz?eh73+UlLikZ)+ft9%YDj8F=Q7>Iad zWHikL)4us$esE1Xugmpy`S79aT9D$36dy}Q>t4BbQ^pEvWo1o1e=g_#km9d@MnC$K zgB&074Pqq`iCKDg92+b3dWv$@pQ#n5`MV&%?_DqUpDOTjW*W~5PGB_>2+K^A4 zNaLzpyefCSA)Pnm_=8`?rAt}?z6DChKq-K;hSA4+Fc{3|^E+{lKI;qk2nK+_nk{Bw zvsrOglesn$4TmG4Y&J77F+MRdF*!LgJu`{CeQ-abC$qCNL{-bkNE#v9#ZtjAhQr}d zDwQC-E|(KJ0k|0hQjwYROfsI!Wp-{sGMzGv064&s;l!YcXpkd`M7&T^F2Z;B@5^0_ z^3EOUynWlXAdmg@Ca-@jk6xAUysttv_u_9I1I1Lo z4?tk?zrX?=WIm))Nv&Y+%NMKPJ#gN-CC;1?=g*7PRq^57=}&%c`~0rBc~jiDA=cK! z`ug0rkDMDDoj?BK{NkrKKf9+DkZV5QpboOl)+|UiW+;TFu~>BHE=r}7q$GgADhnuh z$`)HgZ*T9gFjiBTAN*bPRA23YY+^SX5QuaM&r3n+mR65ogaT+*7C2 zlTa@&E8LY8B~=CJK73dlIwa=jYu;Pc3Zl^nrD96~F`(A+?r=D$&pUS!`2#Ez?fY@jz`y{2TMDWT2kUeOD$Xn~>kP*OFb^Y`WV55n z`q{I+19E5K*cqha4v3nbWX9 zhp&L{KQMLRzzjmJBvXk*GC=`m4;_tmLYz3xoU74R!@)(Grrex@Aw%DMTnx9fy`w!6 z36uI!Ml1>`VNS7_t4LnmltPBOM)`f}Y*1alAbREE<;F7nyl>xL!7cUmT^+g1ZC)K; z)8$twfU2#Po46irZEfmSZnJfDaT(nlBqV%b+3WRUzS+znldZ+3_cK6XFyR_kJ>}{1 bK+}H#8&%}NcF%Jl00000NkvXXu0mjf;Wj1^ literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/mffs/textures/blocks/biometricIdentifier_top.png b/src/main/resources/assets/mffs/textures/blocks/biometricIdentifier_top.png new file mode 100644 index 0000000000000000000000000000000000000000..f73fe83febc244e15c91f3ed2df7021ed55387c9 GIT binary patch literal 1784 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 R@gx8M002ovPDHLkV1l%yvDg3r literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/mffs/textures/blocks/forceField.png b/src/main/resources/assets/mffs/textures/blocks/forceField.png new file mode 100644 index 0000000000000000000000000000000000000000..8749ec9dc56a30b72db13df2e9da1cdb9fb06aeb GIT binary patch literal 28417 zcmXt9WmFX3!=7d7TDoCL0qGDa0g(pj?obhFNvU0slJ0HI{x!} z&v`#^;0(jg+a_&`;ELJ3c%iBJ z*4f?J?X9y5qw=Z9u-QN^pBduOO`9u6@+M!F$C}7+-(Oljt zjoOj}N+={;%~XI!EH9VAtfbk69Mfdgm#Zcs)2+f{#pV#8lGo*SR+x^gtZ2D7Ik{P{ zaQ<6+(Rj1pI$}%-Bz)mZO~q7�`)heU!}FA&%E_-v^Ko21_I-pr)_TWKrddP1OHu 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/mffs/textures/blocks/forceField.png.mcmeta b/src/main/resources/assets/mffs/textures/blocks/forceField.png.mcmeta new file mode 100644 index 0000000..097faab --- /dev/null +++ b/src/main/resources/assets/mffs/textures/blocks/forceField.png.mcmeta @@ -0,0 +1,33 @@ +{ + "animation": { + "width": 1, + "height": 24, + "frametime": 6, + "frames": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23 + ] + } +} diff --git a/src/main/resources/assets/mffs/textures/blocks/fortron.png b/src/main/resources/assets/mffs/textures/blocks/fortron.png new file mode 100644 index 0000000000000000000000000000000000000000..184f7faa7f670bab34c3d8b5763ecccfcb574e1c GIT binary patch literal 5892 zcmV+f7yIamP)<{JPiaF#P*7-ZbZ>KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z000axNkl2sWgVSw@Hy^r11u1-s`WXaay+xP^GZH|D=QH-&H&;l7qFpxF} z5J=m=5R@>KPL7$RNnj=^4KuXGv?at80x=N4#>O^ad|(S(mnB)!u2y>=@4N5W5Bw2* z{)OL%N09nAhXA1vATPNbFO!1gFsc+_o6U6Ga6PG0=V_SyjO@%9zGo5XyBJn)=DNps zv;QA|NjaOu&CW6ZlFg)RD(yY(48QObg1K>YwE-d#%uPF~Rx%jLG0Nvo;YtEDbRqKp zoT!KbiYOolAst<((#b_zS5cY-v%U?=d1}=h zilWeLxY+N$!m&Lsvf{F<=(_t`(7%aoJGS%YbH5@#d6wpm)u5_;F+77@DpdgRkdX6f zs)yg_`Tc*!)J4o_0#Qz2TRujt72mKyYryQ7N23fAb4e;EKcPC8Mo5NT}(zg5(R&MS=Hs&t|AmWypoft&$3JAG0mZ+c! zB7r8*vhiB-6QlS}nwHCMV8{1w;**IAhxhEmsirZE2tlNopuQO~S3(dZ0^33IMQY>6 zkgYuP=QoiHRb<&GDk~(9AK}-#k0W;P*h%+}ouowrRW_*3%@QaoifZE39Q;5eQ+806 ztwnC?!D?*crDy-b_?aXWvM6GRt818@OIf^j9p&+J$gYQ^NAXmRmbyB`N{(zYWYLwo z2s+nL6$Rvofl{d=QeOx4b?9asDH_KE@B^x{LeSDprF{WwuD_8>Z`?t=XBDMm$7yVB zVM$j9TDd}{R-v)IgIdjH&6QgSodDbSK@1TDA2-^8-LrySKYfNx5AUS^YrDAr`JWRu zv=T9NBxTKY16IC-Ud&K9KZs&PaYT{E)!W$i{RfyGNuhNuWaQ)1G$`Qbvm}q~=feB% zQ_IXCSyjqY6Zp{>c}JjZdqe$h%YHdjHB1mwCFq`u48{>+c~@W2ppBZ3}vDCfsXetwwT&@p0umasfarIf<5 z^I(ElNi%Wieb8b=w%)+tS8+(v47qHXkn4C{8ACA4nXz=^$o!WjRQ;dfpo=2j>gaqjuq z&l#CXF+QFoJ9rk`$)lT1)RY)PF-1eINMT|WK~O1|vn;*zYNW7v$$;zl#QIiq$H0#{ z^56e~Q<_CG6V%ETvZGUs9v;EALgeKu!E>10`x@clHz+2@sZ%4^l_C*MAU~ew{D*I0 zjZY%R6ErU0L`^m5Si6qY+$_~|r?8Rf+^`16m`^0yiX2^c`Il2@H`)K;+h~G@El9{( z1T7ROf3}Yh2U|7Jyen|B({whrGo|TJs^Qr+YJMJR=mZnRGOAs}cZ(!8{uPCC3IB^j z42>P*=~wphgS#IfUP>}~;tOKE%c=NtNTHe-a8r{wd5^;MG=@_}l%SkCk7}sYveUTJ zqX=_Jg2F7KBvFyFfwIX=rSqa_RtLvB191huC<} zL(Eh?%tZ?^T%V}}2a&DG69A~C3&;%})Dj(7fq@c(M7#?-nZgYPg22MhXOQMC;>l+R zNI40Aq7jp7xr8EjqtzwQCknK z{NeY=qHTXk;J5^pDt>nhw?Fj=crbkUG_x-iQENF=GlHA5uxdq~y899I+&JcfrDRhx zh=z&WvVbe@yNe_5eni!(AvBm&hli0OQ7Xk*l)4ntAAHJNAG}5^3^-d!($TvPLG8ON z1Q0|SY00JB^5X$s{m}r?wxyKv$vpj@pX&W+((72MP$veAfOYDiyy`<;R1+qO`*Xg&E{jcn1usRVer z2?SYUI6KE3PdrF9h*3AclOuaxA~!OM)7%EVeJs9uC%HluFBDM(0c&m=(MjXG4q~N3 zVCV5%2Tjt^Or83+UZOpHgqlL3;2|_T_`5F&hEJg*QId7c_9ckbDN2*0H1)4y=Hvkc zuZ)+?;JPlYn{Op&WsrtWU`Lx!`d9JjKR?EA|MqdL>655lNPc#du#`gzLjqYxXly{O z?DmSW60ig z5&+q+K%x$@8o|~~R4Ga+@aWw575Y4#$@BYh22YW*Q)u}LH$3truRgIGp<2ZCU4mK; z(QHJHB#75FBiF^LRb~n75>C5@x&BI4{>>)d{KcPePo5+im+9+Sf-H$407}mW0#!qb zM!5Fj?-0mUCI<)6rI7g-ZRFzkMqar82So5Ng93m2x8Krn?d?n-_zPk&1EPYLXk+>I z?R;_c06rlEK7p!Zm@W9Kh@1~_j~~SuK805oXZq8_2;JX#E(GXYw~op5I8MRFnM&eZ zm_#)tD%Bcw_06>0ax;RdQG5M8Mn2k$EX(L?w;}sJ?&+fh3p%;|-urm*Xa9s)bMWRS zaZA%EkscP`c`svU&oY12rDTUrQ#$xEPR&9PB;;jRTn50tU;YHms-P#Dk%R!O5>~c~ zsTh>o7b2WVbHlw``Sb87N@h8A^E$ZY(Fb|&mDfquY`*>L$9VdhucBJB7z_LHs;z_# z-CY0O@ABHSzakMhOeK>Ty*=n!Jx)4_8LvmS{4WXoYzj(gYF3U~)k2G!2$G4~*GoBC z&&r!GLYxnoGv}DM^a_%L`}y4+yHMQ_p?d{p9HQ-ws96KslF%<%#{>6#li&Qqqv%7& z$h!rUco$9mi%2R4p&CIpqDYnQ%>%R3v(zgJxnc^zst{E2IJp@D&&Ad2x%{p>IP{-; zNuHj;B0}N)*9cQ1ke-6#EPf%$C;QLx=nKE#a7IR~MS1u)5AxhYk0XwKjvZFeWl%JY zTqaHT&aY84I%r(A9w~aw-2;N6vGuFBksP0;Ja!6^5P|?N6cLmd%eP&}*!~YG4G+AexZoyx;TP_ zT`getu0%?-_YX+f8P1;gjGYgCo8x<4z_;^Af{YT0p)}9uw#V+}@PF;4mL4N{@I5Z% zLhMBsp*kXpQAZeSM64B&Y65~FW0x}wzxD=|$!WsoCZfxhQ<VMP)004R= z004l4008;_004mL004C`008P>0026e000+nl3&F}00009a7bBm000iA000iA0f*eF zZvX%Q8gxZibW?9;ba!ELWdKlNX>N2bPDNB8b~7$DE-^4L^m3s900t;YL_t(YOSP8g za@t%FhPeo55?6|GY=4gFO@IIuKuBOrM-&?;_kR!Hvs!{Pli$(oXpW9n@4Njd_AR8s@J6?Y__yg>fm zQH9&PYb24n~l7o$!4>;e6CzBRcjTlTCLJ-Hf+~&aL1^%+pTuH%}%9Kf)7|?9J`5M_j*m9fBbkV zm&>hI%WO5)WdMOCC9#Kx2ZE08rE4+g=|=l=3C91OfM7%!u~*X#FP*L8pf zcQhIfhk@tymaE0vVIPL8`C?{S9m6o1X49xk%z>pMgn*0@JEAdq8SZxB&!2}N@R67C z$nCiZRs$Cd1J*b(@I7w;n=_kFKR(`m{rX_>`Z~59d}ue#2Ko>HD+KX)oM7P*%;9D= zolbW9t)gQ(h?qPa1>q*#zwHnu@!jP057iSi}}6&4Cb5vzArm*|zQJ zbc)_&`g%gy?KVJfx8ZKT!B|8%UXL6=Z+Dx;a*jh}O9-rv**0+mKwuNeL@b?75v-fU zd6#H(9Xt)gbr^=5jerX7&o@LDhr|BFO&SpV)94eiAQ+I|QmIHe0eH*-t;mWTP&1Rs znE2uZsZ${WO29%5*Yr?A=#zP%d;K1@Adwsfh(8R-1c1QO;pE_kY|tYp%@zVpN$mGq z6>v`i0eKb)eCmmMb6gvNMk%@X`^3Sf)ByyR_{Z=-lgtY==JVNVEry>sSg1GHsPR!J z&<7o}AfQ*U9R=IA=rz-9Xp+h{^fGHUavGJCk{nNxTr2fO(vcQp0UGX zGI=G1^bjoxAh6;A15bQOUlj_4j@4N#<|O%WIK~|ss+KbS9T_J|rW7%ELC2?v0CW|U z>6Onu&?Ms#1E*d$u#2vt7KJ0KOBSyYgj%fxB2h{yBuZmE9!+UA%3Jc}Q;+~k?Zo3U zO|_F5XB3$@PPXS$a8)4NZa31&iW`YW92t#-gIU5XikOZB00JvjbRx**vJ6O)Ob0+f ze<`{W(5qTJijI&l2=p$aX~d=Ffv2A5F`c<%4#JdYhEtJ1GrDOd zs!m@qK^qOjvQd_LB}udhfWQhtGMSW~PF)s@MNS(|6|l$ynLtpbBshN*D#;7%)HDX*YGO_i0h z!S{v%;3vW9z|n7t1SI-~vzPfQJ0*IsjYBkq4n)lXub7=6vLGzzN0c1n$1_>_;Oy*7 z3FtDzsG^ZCq(iof#R7|(QLQ(mu^^yCg+R-c#2R%fx`7AO z2GA4(Yc~1kp={Ud<=gxA{e8b!%&1^OL2#f!2N$(b_*~bY2M!_9G6jWF(LbLOSGoA` z_|WZ2G-z4du^D98KA%qz!bQT+m*1$CDc^G7b0*tX^y5_~2aM~dr~hL7rT)8LN9z0d z>-dj;euaQi{T}^^>veyBFMs9f^z$=6qsNPeq#oF=*Xy{SNbpfSeV0~!E)cj_@Edpf es#2{`rvC$Pq{c+5_M(^o0000004R= z004l4008;_004mL004C`008P>0026e000+nl3&F}00009a7bBm000iA000iA0f*eF zZvX%Q8gxZibW?9;ba!ELWdKlNX>N2bPDNB8b~7$DE-^4L^m3s900xRlL_t(YOSP8S zZrer_hWQW)8n0R`+mfw?S}2KkBBJJY$rcas`6n`(M-*0xmBv5XgZ{CX>r$`P5>eR4(T8 z`BJG^t5r3vTr3s~g2o({?QfbM(4twoTJyrCO~Z4_JJx zT*fYXy%zu3?7gOG?RMK}x6DqvW0}714F>(;(C_!V-L7NXoleIzjFx3ty`Jm)1JCPE zCgaU^y<9D4^C|1DYqw3KTGapqmXIjvbQ-5)dqt}lZKK(2_`x6;`i$f8a4_&DV2nq7 zuh;LpuIm5|?r1a|4g=5Yt=7xO=R+8-7t6V2b#z^C87;jbd=4xbAp{UHe1|tiL4S^llgK4_lOlgp7w*89?v$+vRG3K}1UkusVimUrLGi;jTr(-Q{=B!tIcLDeR7l` z(IGyv3z911PYBCcVKSXQ5JGB*k^~S~VF3+K*pfOgl}a6}vs^9+^7Hen-w{LBlBVB0 z<3zy}Nz5qFu_+P&x+IvXmA5*OLB=8)PNSit7ga+p3K>yeGI@v~q}Eb^peUpy5~(qn zjAoP?=`G^qlaK(4+=<0RHpWQiM*^f)vc2^sVfdQl|l zRRDm%iYz(`P}Kqrk|0w72%x?sx)eaI%H)yg5CKDg97SsyvFJyY(WOQw@L;@YQN5g9%BMaRsAH8S*;t$XQ zOFhq{J2OsdRWzc@)5FO~plRKd5?Lp==%CG}ZrL#R_O8eRN(4Y)g@8mNA!<5#RxX## z+uPrgiE&jU4nzVPX_c?}TsNPkg%P?a7lrzwSF7r;u^30Vqo#V@aV+~T{k4!E6jh`G z2rL;Sx+zzt2zqqjKSlX`cegZ}B}LhE%rChtD_`>2kyb`Wbe95_M(g+68@4#YL6}3! zvgB)X?n7Z(mLl6P{wUPIr16a}n7N$n}hRM)2sofY%;hF*^aTtNt6q?FL~ zUqt~OHp$F9IqBm?uHQs&J=+HN+h z$EV%X(_y)slfk^5a1JSt#bgx8O`&j{enZi`T{yT%rYR_-ihTK0DwV#PPiNBIuJ8sW zYdbcL4BZ!tDTKRpy#~K{MzxKgT;e7Wcd~6o4=;@v5aj#&JB3&3&wD!Zn0tLX{-npR z5J0NlL@#mq-QM1cS9vOx%kda}{U}KCf#pV{f%)+`hhnMgl;r0FfsYB#xZ|m6txB5y Y56P3004R= z004l4008;_004mL004C`008P>0026e000+nl3&F}00009a7bBm000XT000XT0n*)m z`~Uy|8gxZibW?9;ba!ELWdKlNX>N2bPDNB8b~7$DE-^4L^m3s900pZ_L_t(YOSRV5 zQd>zB1yFr~rv@0JL=eGbY?6^cAc-il1tJ(QwxOK=|9Mt(T-ToRlOINP)YZ4c-hE! zbN+{o%HDQKTd$S1`@5?;zmFJ<1!QY;?bpv3%x1HGBEWBAaI`QyoY#_}!CvzFNVdRK zvDo+P%GhW@YzzUL2nqvvgf@&%JfEJKnwpuMdpSG5@N#B$`sKol<&~v{#rYTWbF*_Z zA^JvMm6n%YEo#earTSKltdw4@S1ZJbDFk4dH^*wM;TyDx%EsE-`szk?y;|F7?C3BZ|8zu zUM=k(G=ORkj}H)lI666mg~oo+`W6tKi_6yAcXyZ97w4@r1oT*~luP9mfM7*LBH%H$ zV-1LJZm-`zyn{~QIyiCaK-8y1Xol?Uy!r0K{fEc*Iw!A>jo?6FJp!+lP2Ik|AqGQC-M@e9G+G)kQ8*(w!Uu^!%x+eb$(R_rbz1xX{=;AB z1f89=02A!cKyG-Xn0zqM<3yX=b(%U3fj>Dpd3t(!b8~ZXadC2TGCMn4uh(~WcFxbw zo6Y9j++5$&FQ3m_44vNG%a{BN@P`kiq8=Zx>}m5vO9`&CXJKJscX#*p_V)VvdV70& zdV0FMyBh~SteCd8wl+BgC8iG4D zH8nOi7M=F?_Cle6_~GH<@$vE7w{Ks+enn=ngHwVd*(ah1Ec@pqTj~wxg(-e1gFx`v z^X%C(a9Wnp>F@8Kn3xDpP=cZE@9#sE(13-x5EB}JV3P*Q1ziv-3~VP~m`LQ=^Vid_ zt*s3Q>-hwMWGdRPoS1c6-nnFrxy--?V3bP!ewAFzp2cXV`g zc6JtvMW6c;{NO-;eSQ7%@)Ek=(NT(N!R`3sJMu9yIh6|4G%{Hs6J(L4IP7uWQmN#; zi;IiAEuuuH!TI_5wY4?JXPmpcJMOVq>^Xi$01#}7qKrThMF3jT1_2XO9|}YJef;=Q z$g)1Ny}iA&r=OfyT3QMxhj29~|0Li8h1)j*ZUB9Ka}_4~{P{CnZPxLL5;1Ks(eL>9 zn5`^U$D#_bfiMLKHbs$gQK>BZmVr3rK}HY}0v%{D#fTqOL=l%DV6-4`IHJTV$pFD7 z0_7s5T(Qq3<4TA;h*AMax`wU6IVmg20G`k{$itk$=N8A6phU_iCISdn1f@)lE0Y7n zZzMBKli!+6ww6{RhgqOQuCCT0HYd}W>^zQx^4Z#s`G>$h;JaBB+_cZ!>;e?5p zjO!^FFCRuEo?>z76F|<+C6P_URNO7ZUT5;D{q^BBIX#i{O8x(yjxzVh)A4_L{3ZgS z8V~W1vGGx@8seRry+^GP55|Rugx5Ect+yp!^E#e!*)A)E>Ax|d!_n>pQ#k+t002ov JPDHLkV1oB90Eqwq literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/mffs/textures/blocks/interdictionMatrix_top_on.png b/src/main/resources/assets/mffs/textures/blocks/interdictionMatrix_top_on.png new file mode 100644 index 0000000000000000000000000000000000000000..e8ef1ed635050f7a391da6a55daade43b1b526fb GIT binary patch literal 1855 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≀Hi* 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 E2dm#{&j0`b literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/mffs/textures/gui/gui_components.png b/src/main/resources/assets/mffs/textures/gui/gui_components.png new file mode 100644 index 0000000000000000000000000000000000000000..303f2935be36bc59f168227b7711013cc2af257c GIT binary patch literal 7235 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/mffs/textures/items/cardBlank.png b/src/main/resources/assets/mffs/textures/items/cardBlank.png new file mode 100644 index 0000000000000000000000000000000000000000..ed17d9d72763af827ad4efc946f01ab4d8245769 GIT binary patch literal 2993 zcmV;i3r_TjP)KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z0002oNkli{Yn2C{>(lSbs;@24P*h6yTTHC$RRAr1|f-_YeMHW z01N=PG%+(5OQ@=R6Otf_5CTI8B)P;dNwQMB#`ux!1Co%f4{WDb)mjH70NLd*GfAs3 z?MhRV0?CyBmDND*r^<$^xj!f5`zX^#KnXN{Iq-pa8unIJCKEE0)t) z;N${a+68^babpU2pbjKNH~+wZOeDD#XhVFX_X? n>q-VdHp|O+84Un`58yKZ+R@2j&49!i00000NkvXXu0mjfT3Cp? literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/mffs/textures/items/cardFrequency.png b/src/main/resources/assets/mffs/textures/items/cardFrequency.png new file mode 100644 index 0000000000000000000000000000000000000000..b6e86ed04640cb42d42a39c7d50501f618dba4ce GIT binary patch literal 3062 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 Ef>hF|JOBUy literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/mffs/textures/items/cardIdentification.png b/src/main/resources/assets/mffs/textures/items/cardIdentification.png new file mode 100644 index 0000000000000000000000000000000000000000..95069196b7267966402a34fc48b44d8de9bf4516 GIT binary patch literal 3114 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 Ef@#0N)c^nh literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/mffs/textures/items/cardInfinite.png b/src/main/resources/assets/mffs/textures/items/cardInfinite.png new file mode 100644 index 0000000000000000000000000000000000000000..b083a9d23684bb76f183ca5d5bc862992c798d6c GIT binary patch literal 3554 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/mffs/textures/items/cardLink.png b/src/main/resources/assets/mffs/textures/items/cardLink.png new file mode 100644 index 0000000000000000000000000000000000000000..b8edaa29eabfa75df6c05ca2b37f82374e01aa86 GIT binary patch literal 3257 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/mffs/textures/items/focusMatrix.png b/src/main/resources/assets/mffs/textures/items/focusMatrix.png new file mode 100644 index 0000000000000000000000000000000000000000..0f54b352f68b3b6f516f0e534c8013d33d6430f5 GIT binary patch literal 4294 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/mffs/textures/items/fortron.png b/src/main/resources/assets/mffs/textures/items/fortron.png new file mode 100644 index 0000000000000000000000000000000000000000..184f7faa7f670bab34c3d8b5763ecccfcb574e1c GIT binary patch literal 5892 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/mffs/textures/items/modeSphere.png b/src/main/resources/assets/mffs/textures/items/modeSphere.png new file mode 100644 index 0000000000000000000000000000000000000000..c4cd5dce77ab9e0d474099df97e50e1fe2b74f66 GIT binary patch literal 4655 zcmV+~64335P)4Tx07%E3mUmQC*A|D*y?1({%`gH|hTglt0MdJtUPWP;8DJ;_4l^{dA)*2i zMMRn+NKnLp(NH8-M6nPQRImpm2q-ZaMN}+rM%Ih2ti1Q~^84egZ|$@9x%=$B&srA% zlBX}1mj+7#kjfMAgFKw+5s^`J>;QlP9$S?PR%=$HTzo3l9?ED;xoI3-JvF1F8#m>QQXW*8-Az9>Nv%ZWK* zkqtikEV84R*{M9Xh{ZXlvs2k(?iKO2Od&_ah_8qXGr62B5#JKAMv5?%E8;ie*i;TP z0{|3BY!`4?i6S-;F^L}%f`(o2L0Dz>ZZyndax(`h}FNp#{ zx{a}MR#uh~m%}m=7xWMPPlvyuufAs_KJJh5&|Nw4Oks+EF0LCZEhSCJr)Q)ySsc3I zpNIG#2mW;)20@&74xhslMTCi_jLS<9wVTK03b<)JI+ypKn)naH{-njZ7KzgM5l~}{ zfYfy=Kz{89C<+lE(fh?+|D$id_%I-TdEqLPi*x_)H~nY9rQ#)noA5c#B`Ac>67n+_ z_r%Wu$9dISw03U@r;Pdb`_%=KWKZEBGfDjQHqKX(I48#TT zN1~8;gpaI8ijWGV0cl0Lkv`-mGK$O~Z&4T&1w}_0qHIx~s8AFOwFb2wRf4KU9Y%Ga zdQmq~W2jlwM>H9&h}K8jpuNx$=mc~Yx)5D~ZbG-CFQRXwC(y4k7z_=gjj_UbVj?j~ zn6;P^%sxyT<{V}aGme?VVzKgAeXJeUAIroFu!Yzv>{0Al>=1SW`vynEso>0T?zku% z50{Utz#YMz!42UiaSM1Uye8fT?~iBWbMU43MtnE^I(`DbK#(SA6YK~fge1ZyLM5S< zaFOtU@RCR*su8V;fkZBGBe9ZrjCh$iMtn<>A?cA^NYNxAX$R>L=^W`U=_Q#=)*?HS zqsRjC4stX30{Id7jRZx)NWx2kEwMqOMxsMvNaDF9UQ$!iNpiJhu4IMe3CZh{Gg5dd zEh!f%rqp_=8mW^~BT{qH6lqgwf9X`|66qt-SEQ$8urgXQZZd3{0-1v{7i7jM2t}RZ zLSa!hQyM83DHBu-Rh#NXO`;Z4zoQONXJut%m&u07X3N&do|YY@Av7(T7cGTWN;^&) zroCIDw8Uu%XUX;@txJZM%*!p6bCl!A70I>9-IjYNPnUO-PnO>$-zoo40i~d)5U7x) zuwUV#!pu_YQro4hrA14RFTJM-E9xl*DXvvKsMxPKr=+app_HyvrF21QMwzDUsGOu+ zu6#y$T7{xwufkO+S2?TllrBqmqNmU+>Amz>RYg@#RiSFV>VWEknzmY~TE1GF+Cz1M zIzv5Pys-#cBCZ~;MXm#GGH#)6 z)ozd6)!Y-@Tijj2>R4y()XvmDLKXQ&yjjk&I!+oQOrohQ}U>eb4k~HZbSnyy9x(W?3$*y{uH6t~>7#3G*6dj`%lF|oWk4CLGP(p*(a%)BP)E2$IF@Oj zS(EuDD=h0owsbZxyFW)SXM4_Mu6ypcYf)=iYkTrk^ETy;t#evezaCm2x4vhC`i6oH z6B|7?9^ORQl)UMue3SgL{8yX9H+L5(6>KaR-{P^QrBI@fUpTVWc5B@>)Hd$6f$iqo ztG0hEVi#R4HYu(seqX{Wx%!RiH@;dd*9H0 z$NjB!N_E9`?+$Pe+^P4d?`Y6!s5po@n0fF?V_0L~w~TL_n-rRgn?4-k9U46xbhx+K zs=4`y;*ru8xJB49eKh*$jqhB)>uNP@t#6~X6(0k~gvXwKAN&3Aai8NoCm1JMf6)A) zww=;m)B$zmbj)@pc8+#Mb`75NKH1Z4+ui=7(T|5tsh+AiEql834Bs>djZ*&hXA3QVUFm(Q=>&;8Iyl!2)z2f%ZaOm)zk?4`pJM24C zcT?`ZxR-fv;r_-4=m$j)r5;v1Qhe0#v+mDrqn4wm$6Uwy9|u3aKh7F|_DjYu?mT-%DP~ zzdZD6*{hzpfVoGnQ(rI47rl{xbNDUeZQr}_casZQ@3HSIKj?nw{^;}Z!Kc(upZ)~{ znDhK^CfpAI000JJOGiWi001fgUO-9&x&QzG32;bRa{vGf6951U69E94oEQKA00(qQ zO+^RY0|X2WGTzmme*gdnfk{L`R9M5!m-&k&R~5%Ucd2?yy-s&}o9UUPGm|h$9Fs}x zsGx!f0YOO&0mpzE67eTN#05qF1*5+x2!acOK_iJl2>HR^ln}y@WJqSRi40_BGTogw z-P7B9Rdwqw{!mr7`xzAxK?@%5y;Iw{=ewM9;eULH_Q%PUmC)<=02uAbvm|a*v zYsL3pJ%<32Gyx!l5R;Hnf{-MMjxpywN=mBA0$^>0vkvbawuwn8@!q4g=1YeU0kE^P z!__ORLIZTOKF(Qwc>X+JKlwhg!GLU#;he*JPnKnDZEbPn=uxcq=p;dFjrSg73{%%l zarxpUgb)*0AJxP6&Zcr&Cu9P)gywXEPsTjN!3YUgh&M zGpt^`SXUrTQMZxNDNC-YYQv+m!45bzQsR8BI4zIoT8pn?a_kKnOuz6oe31Utec&aS`Vn&+ss(`%faJq%0+6Sw_4M@5ufOHLGKoJ;eTCD#C;wxUd2s#=PY+in zV%=_c-+bB%*vb-oKnj7Bl7)o@UON0OpeABVRBLT5wW8SffkqWA;UcM(s$)U$?6nW` ziTN?(as3GdT&pAiog^r&nVp|U2*GeTBmnp3Kb??X2m$9DWm!^|Wqe>!6fx$#C(mn425dJB#{`~y&=rlzDy?&qZ zXoPQ!r=Mk^Vdt4SU7x$ zUa!aDqenP$WQpOGRdP9|EK97l7-J$YilP7kQfrblMF>H++c^M%RtO;xqQNfIIOlmj zk%0G}!Spn9XFKF-jQ5V+?QQI6L=eyoS%gMP8R2V6fDnRgFhFS)JEg9By~Wy!@n}>_ z$JZ}aN--XfqkgNZqRexaPTz3*9P#XQI+5+7kyQ(UwKksf-V>B(>)JK0 zOB0-Rn4)~I6Sfw+viUP!zW&SqwXy50{v@|<{~=bA10>e~Nt)ul$Cf3|Io8+LVR}-} z2eEA{u(!7t%iLDLIX59gfY5cUt*tRPH;0JR(E%TjQsBLdGF(_#0PlFA`?;8DYr}1C zH^v}@VASxYb;Z5CJ&Z9FMS(Gf^Sw_4p4r)1oO7}9>COQaRAp70L}L(ZYiq3RJ`Uc+ zcH81>jEP266b05=_V)HDih`mjVv_ApLvS3s`V<=*8-x(p-rm9cFzExv7`$^RA;_{U z8pa35Pw+zeAZ1zB3i!JoP*qh8T|+u+ZEQ+aRq@u~K8|nvegd9u+G$81-s^;$o0|a4 z&d$cz2X=qU+3d6R=)U>*zeTz?2lo^Dj^i6o#n|-pbexPQChdc>UY2DTTk+02@5B!1 zoa5Ba6W}XepLvM$*PWiQ?pAKrTHcs?fH$Y^Cj`e$SD!=(5h2;$-mVGk9YTO<_6)l5 zV0;Lara~*t($W%np2x%h?ixKE4djjMPXmDfh~S|aP;XlQ4c>b?oeruou6BX5v$KQ{ z7{2>1&N@`Hx2T=a1-$bFALz}@u)V$>eZO_A)^y6UzkXQwW=zda}>>N(RRGJ zfQFDqZn>GwjSWOIe@@H;-#&FGKRADm@7{ek%eS6jV`Bq^;OO#lGuhN$E|g;a&|*ED zD#>tljX{=i`SN9^rlzQj;o9akoV7S>Nz;_H(_v$Hm7T3^e)QH~_{N=gOd3&peCO0D z9((20W~)`|=W1&>N4|JBIxjqC>S(FGVqSS|D^_ww@lRz|vCuzLs)$;-`! zo*{AqUjza0dRV*yaMRE;fKCVhpQKsoe1Yhg01=zBIT!& zC1$=TK@rP|Ibo3vKKm@PqnO#LJhq6%Ij6Hz*<$V$@wQAMN5qJ)hzm2hoGcOF60t^# zFqJFfH{#e-4l@G)6iI9sa9D{VHW4w29}?su;^hF~NC{tY+*d5%WDCTXa!E_i;d2ub z1#}&jF5T4HnnCyEWTkKf0>c0%E1Ah>(_PY1)0w;+02c53Su*0<(nUqKG_|(0G&D0Z z{i;y^b@OjZ+}lNZ8Th$p5Uu}MTtq^NHl z*T1?CO*}7&0ztZsv2j*bmJyf3G7=Z`5B*PvzoDiKdLpOAxi2$L0#SX*@cY_n(^h55xYX z#km%V()bZjV~l{*bt*u9?FT3d5g^g~#a;iSZ@&02Abxq_DwB(I|L-^bXThc7C4-yr zInE_0gw7K3GZ**7&k~>k0Z0NWkO#^@9q0fwx1%qjZ=)yBuQ3=5 z4Wo^*!gyjLF-e%Um=erBOdIALW)L%unZshS@>qSW9o8Sq#0s#5*edK%>{;v(b^`kb zN5rY%%y90wC>#%$kE_5P!JWYk;U;klcqzOl-UjcFXXA75rT9jCH~u<)0>40zCTJ7v z2qAyk54cquI@7b&LHdZ`+zlTss6bJ7%PQ)z$cROu4wBhpu-r)01)S~6}jY?%U? zgEALn#wiFzo#H}aQ8rT=DHkadR18&{>P1bW7E`~Y4p3)hWn`DhhRJ5j*2tcg9i<^O zEt(fCg;q*CP8+7ZTcWhYX$fb^_9d-LhL+6BEtPYWVlfK zTBusSTASKKb%HuWJzl+By+?gkLq)?+BTu761jmyXF)a;mc z^>(B7bo*HQ1NNg1st!zt28YLv>W*y3CdWx9U8f|cqfXDAO`Q48?auQqHZJR2&bcD4 z9Ip>EY~kKEPV6Wm+eXFV)D)_R=tM0@&p?(!V*Qu1PXHG9o^TY0bZ?)4%0 z1p8F`JoeS|<@=<@RE7GY07EYX@lwd>4oW|Yi!o+Su@M`;WuSK8LKk71XR(_ zRKHM1xJ5XYX`fk>`6eqY>qNG6HZQwBM=xi4&Sb88?zd}EYguc1@>KIS<&CX#T35dw zS|7K*XM_5Nf(;WJJvJWRMA($P>8E^?{IdL4o5MGE7bq2MEEwP7v8AO@qL5!WvekBL z-8R%V?zVyL=G&{be=K4bT`e{#t|)$A!YaA?jp;X)-+bB;zhj`(vULAW%ue3U;av{9 z4wp%n<(7@__S@Z2PA@Mif3+uO&y|X06?J#o zSi8M;ejj_^(0<4Lt#wLu#dYrva1Y$6_o(k^&}yhSh&h;f@JVA>W8b%oZ=0JGnu?n~ z9O4}sJsfnnx7n(>`H13?(iXTy*fM=I`sj`CT)*pTHEgYKqqP+u1IL8No_-(u{qS+0 z<2@%BCt82d{Gqm;(q7a7b>wu+b|!X?c13m#p7cK1({0<`{-e>4hfb-UsyQuty7Ua; zOu?B?XLHZaol8GAb3Wnxcu!2v{R_`T4=x`(GvqLI{-*2AOSimkUAw*F_TX^n z@STz9kDQ$NC=!KfXWC z8h`dn#xL(D3Z9UkR7|Q&Hcy#Notk!^zVUSB(}`#4&lYA1f0h2V_PNgUAAWQEt$#LR zcH#y9#i!p(Udq2b^lI6wp1FXzN3T;~FU%Lck$-deE#qz9yYP3D3t8{6?<+s(e(3(_ z^YOu_)K8!O1p}D#{JO;G(*OVf24YJ`L;wH)Dga(UN(8z9000SaNLh0L01m+b01m+c zxRGn^00007bV*G`2i*e;2@V_S;)iVj00*;4L_t(o!_AjTj~!PP$A5RI=?(5qr`@*O z#F7(durm-GiAC}i*nq@_6-X=*3P>RM28h6h1xqB@vSGmoKv`rJVkK#i7;F@GJDu+K zd-m%$)NqHxqFz`%Hub7>_3GSn{?mp3@uj*Sw{G8-Vo(6ETrAk!+&H%|`alQ) zo24X43P4@eXsdB`gL4jm;5}%KZ)&Qt0$?y261`_tR`~V0&+hN5zJTXmdP%k}Uc_3% z&p-MY1te(#fQa-(XstnMlEn7!LW~%#an1way(9QQi~+xXr?n==h_#mQT)qUr>FFsC zKRr|yARi70!Sl<#J>I@`li_H@a5N-@fcKsv&pADv^QCLg(0EUpWf)^{&JjXjd|}MN z{e867RI8G5xkPKte0GY~8f^^I>4aylUE??J|Cyh@ahq~go{iw;H*U+X@7?2vw{8J& z_33Rw2-I~=RaN~CoO5Wc@!q49LTgQyWq9w&^Bk=;tJMk-Ax%@1Qiuq{;Si-1({e@A zG`#cSM|^8@lf(P>+YY2@iqVEFO-Yp|gn)C7<#LI&7Gn%al8__`F-EqwwkXRItu=X` zQ`dE0(0DvXL};3Zx~>7(-QC4G$Dpb>JUKxm_9L_a!_g394TJHB>d}n7yLY*C=@S3A z`7^ZAXagD{hJYp@(G!F3?<(_H9jTj|goq+wi%8SdxTfN&yTjhz9@np5rx*-SN;4df z&I%}(D^QAJFkpJ{DH|Ib{AKt11gEH6fc-yV2*l_S0iACUs~Jjx3N@lM5+h0+Dmr3R zpbaz&cu^RRy2D&)2r^ zP!t8m7?e`v`3crqs;a_!Pt!Eyd5(zmILY&z-`>3m(L*w1GC88IYm(srfPB#2^?wqF z5CS?K!0`usedhzT)`$p7sUBD%g#OuDd+v9h=foKKYV!w1g#}tRi3oX~pNUV`0q;B# z1+5e@M#keYlMp~96h+aay!&V;Ish?7M1-oU&eTmQ%Ce=|=BQv{25fI{b9i{zvIHT- zcvgT-5{$KMZEth@uTPlI=NKX^kMQ32)r&|^$F5T$gmZ$GBnhXdr!1FCnx<)mDoJ_p z-~oA_WAYqO=P}^D!x&APWjN=!aNz={DuOnI5HQA2mStZ+_t9?m?SHhY=bR(P*wfN^ zk5R(T&JOeWoWWp#wFYg>83q*XVq?wOtR+A?BF5N@QPj51Xbapco8TEtkX)5D^B$AvbT_z!=ky z00i&O%t~ubVv{p}>E;Gt%~=N|23S1kF;LevP16u#Tgu1SYF*4fN;ORRV zrCAYUU_P7SmrF!JF2jB_og7=Oh`zylkJg&uXoRt*cS_rOy~lgUYPsx%M5}<#hE!EW z2!Wy~aL!SeC0D-r3|={w^@129O`5WEF5ntDc2=n=zOj_f4 zG6!`0?mDnoEXcC#Tn9o3y%m>b*=7d`92^|9Uec!{b5?-XiWmb`RUsm5ZEZ1g4N*8J zza2%pK%$glHk*;IHy|REW!Y;-o0uG83U;2};rRHtH$J;A+yc0|rAhO&q+-Lo$zk; zCa;u#>{HT{ALxqdl(9p;Qi|1Tg?{zB98YH878qk%+fK7J=;ez_IGs+>S~D7rh#|nn z^)^CZ`!=aHt%HdWMX(w|3`huAqi~HwDjh{Fod2zhi&#JV@l>M7P00BA5&W6oUA&Z9VD?*}evow4SdtDm1)2e!$Vu zNgG;XKq+X}XNI-|S`kI48%LU??C$QeSS)yJyN%kN(RAr2gn+fS*MPdNF~;;_9_)?M^yD z(wd8xFOeh(+GtJ=KVvi;a&U0Kcs#~64UeXe2;LLCCrwk*EMs!=kkiLAe)YG%^MhAk zIgf$v`tfV8@y>@It&duc5F>+o_u9xNLYk!*W3h?tbwRCJBqB%@Q0-~QIo~2(fwc)u zT@yw4-it3#&*zNC|?R8#9C8-QK^-(NqtqxgTg{tfih8em(8e7XPt002ovPDHLkV1lbC@K^u< literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/mffs/textures/items/moduleAntiFriendly.png b/src/main/resources/assets/mffs/textures/items/moduleAntiFriendly.png new file mode 100644 index 0000000000000000000000000000000000000000..586e052668119c49c1ffe6cebab19401129589b9 GIT binary patch literal 4847 zcmV004&%004{+008|`004nN004b?008NW002DY000@xb3BE2000Uv zX+uL$Nkc;*P;zf(X>4Tx07%E3mUmQC*A|D*y?1({%`gH|hTglt0MdJtUPWP;8DJ;_ z4l^{dA)*2iMMRn+NKnLp(NH8-M6nPQRImpm2q-ZaMN}+rM%Ih2ti1Q~^84egZ|$@9 zx%=$B&srA%lBX}1mj+7#kjfMAgFKw+5s^`J>;QlP9$S?PR%=$HTzo3l9?ED;xoI3-JvF1F8#m>QQXW*8-A zz9>Nv%ZWK*kqtikEV84R*{M9Xh{ZXlvs2k(?iKO2Od&_ah_8qXGr62B5#JKAMv5?% zE8;ie*i;TP0{|3BY!`4?i6S-;F^L}%f`(o2L0Dz>ZZynda zx(`h}FNp#{x{a}MR#uh~m%}m=7xWMPPlvyuufAs_KJJh5&|Nw4Oks+EF0LCZEhSCJ zr)Q)ySsc3IpNIG#2mW;)20@&74xhslMTCi_jLS<9wVTK03b<)JI+ypKn)naH{-njZ z7KzgM5l~}{fYfy=Kz{89C<+lE(fh?+|D$id_%I-TdEqLPi*x_)H~nY9rQ#)noA5c# zB`Ac>67n+__r%Wu$9dISw03U@r;Pdb`_%=KWKZEBGfDjQH zqKX(I48#TTN1~8;gpaI8ijWGV0cl0Lkv`-mGK$O~Z&4T&1w}_0qHIx~s8AFOwFb2w zRf4KU9Y%GadQmq~W2jlwM>H9&h}K8jpuNx$=mc~Yx)5D~ZbG-CFQRXwC(y4k7z_=g zjj_UbVj?j~n6;P^%sxyT<{V}aGme?VVzKgAeXJeUAIroFu!Yzv>{0Al>=1SW`vynE zso>0T?zku%50{Utz#YMz!42UiaSM1Uye8fT?~iBWbMU43MtnE^I(`DbK#(SA6YK~f zge1ZyLM5SA?cA^NYNxAX$R>L=^W`U z=_Q#=)*?HSqsRjC4stX30{Id7jRZx)NWx2kEwMqOMxsMvNaDF9UQ$!iNpiJhu4IMe z3CZh{Gg5ddEh!f%rqp_=8mW^~BT{qH6lqgwf9X`|66qt-SEQ$8urgXQZZd3{0-1v{ z7i7jM2t}RZLSa!hQyM83DHBu-Rh#NXO`;Z4zoQONXJut%m&u07X3N&do|YY@Av7(T z7cGTWN;^&)roCIDw8Uu%XUX;@txJZM%*!p6bCl!A70I>9-IjYNPnUO-PnO>$-zoo4 z0i~d)5U7x)uwUV#!pu_YQro4hrA14RFTJM-E9xl*DXvvKsMxPKr=+app_HyvrF21Q zMwzDUsGOu+u6#y$T7{xwufkO+S2?TllrBqmqNmU+>Amz>RYg@#RiSFV>VWEknzmY~ zTE1GF+Cz1MIzv5Pys-#cBCZ~; zMXm#GGH#)6)ozd6)!Y-@Tijj2>R4y()XvmDLKXQ&yjjk&I!+oQOrohQ}U>eb4k~HZbSnyy9x( zW?3$*y{uH6t~>7#3G*6dj`%lF|oWk4CLGP(p*(a%)B zP)E2$IF@OjS(EuDD=h0owsbZxyFW)SXM4_Mu6ypcYf)=iYkTrk^ETy;t#evezaCm2 zx4vhC`i6oH6B|7?9^ORQl)UMue3SgL{8yX9H+L5(6>KaR-{P^QrBI@fUpTVWc5B@> z)Hd$6f$iqotG0hEVi#R4HYu(seqX{Wx%!RiH@;dd*9H0$NjB!N_E9`?+$Pe+^P4d?`Y6!s5po@n0fF?V_0L~w~TL_n-rRgn?4-k z9U46xbhx+Ks=4`y;*ru8xJB49eKh*$jqhB)>uNP@t#6~X6(0k~gvXwKAN&3Aai8No zCm1JMf6)A)ww=;m)B$zmbj)@pc8+#Mb`75NKH1Z4+ui=7(T|5tsh+AiEql834Bs>djZ*&hXA3QVUFm(Q=>&;8Iyl!2)z2f%ZaOm)z zk?4`pJM24CcT?`ZxR-fv;r_-4=m$j)r5;v1Qhe0#v+mDrqn4wm$6Uwy9|u3aKh7F| z_DjYu?mT-%DP~zdZD6*{hzpfVoGnQ(rI47rl{xbNDUeZQr}_casZQ@3HSIKj?nw{^;}Z z!Kc(upZ)~{nDhK^CfpAI000SaNLh0L01FZT01FZU(%pXi00007bV*G`2i*e%6DuMY z#_4hZ000_vMObuGZ)S9NVRB^vP+@6qbS_RsR3LUUE;TMOFfjCTp#T5}@kvBMR9HvN zmupaz=M~4Pt%?zrWf%6sUSKcm1(v&_A}T?2G$>=J1O){Iq9{$R32B;{=%kG`YGNDH zgrufM1;h|hLNsY>oPMa&X{XaTX&Y;5z~oD3I*o#U^~=BKfA9siv2FYoW`46QywCIe z&w0-6O-T5<{5)b$M2Fq1Y&6fs4!19khO8{qdpy`_cVbu81Y7)8JZZI|Eh8OG>1L%q z-HK+@YeZ`J zRaK>|T)7gx97oxnpTo;TM6yTazeAa4JF&!Np=m0-p}{%Rc^fg^Sd08&m*{b;)L?Ao@2_`(Fw*+^{arZ;uXe5zIc&_F%T)B z*_Qgh1<>t(&B(w9a`+#`{a5GDzi$B)aYY1NlsyaqPlYn^WY7~YV6)4K{c;GeVZIzh zw_kC)abDd1k5^v7$GlsYOCx^#m{=!_(OTig5%Gj@>(oi*_RyIL-WgQ>E^9AK+`J=u z(F3dzO!JnM#3>IvDmly|@>YHnrKP19EiA;asAeEi0MUDutNHxF2k%S3x^?R&V`#~e zC3r>-C#;&2)vz^9qB|!W=L>T+1};mgQSpiuEAY?mZslg*i762hOgB&UDPz48jQ93W zFmOt_eNMa}tXj27*S#(2x>Pc3Uo0EX=Y`O2O_~zWy6YfN3}*;TwwaGxp}2 zlevCfQr588h=DtI?tmEU3<2~)zj$GPNU|;07cZdAmx=fDig7NdKuhd7QOca9`|c$` zMcmEx&!k>Z#D5b&xAX4#JgeqQ5f@(0@u0(OneqTz>V?uGZ7@u~cSXRWMT=C#jc&<% zVf=WHa`VDP<@TlDO^A@H$;!v?%COwM@I`;0LQfh3PKtn@;sAO}g4mpvG9_S}(~JIC z7`@V3*;tH}`F{co5fno1C4hUBm6d5az9jd%mP-zKFNYNWEQwCS-==5 zmYk;-jC?mf4_7|~GTzgx+!}ZreX=nt9!1<5I;$A{E~d|AK= z>FumoS2HuUczjg>6u~qzJn^3b_;+^7h;&I7ArdEGm(zux#0v02G=^NM0VC3sK9(}P zc=2M~_}Oa{bW6n(F74T?{C@92<#Nvv<)cG~a6B~?e-=yW?(yLvB~OBy0_Y`nSr(xu zq#?yMqb_$u$1YAlh5%MQF1#NB6mdq}Ol!H80u1YWMO>zM_Br|cZV|(|aWV#&hMWhU z_4*JD2H}#r&jEys$BwP&y+E)1U6%D}@*WIA-x+Mt4X?cDC)0n-LWQ)T(tsBa4u+8hlR(Y}L^n37qdEua&w%Jl}IO@iW zK|2nFJvbQg;?-;$eiQTKQc)Nmick(RCrb)(z@CQgpbsyIrCn0(IRA6p@5s!+W1EAg?a5NC{Mt--_`6v){8q-c!Qwo; zoaMn!JsCLYNXI_$)(^v3I{or3i$?uGzVi)fog+!DUq5$Nya3(>AKo6$R<;KHXmBMd z9M=frgcXdI?v`3ke(W*hnP4iO&UB!~XHmEhU&%OfH8^YvC*W0L05PuM>+({b@Nb@y VI9!_LZ4>|i002ovPDHLkV1k-HG5i1k literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/mffs/textures/items/moduleAntiHostile.png b/src/main/resources/assets/mffs/textures/items/moduleAntiHostile.png new file mode 100644 index 0000000000000000000000000000000000000000..d6cc30528094f4269b1db6e7164d12bbd1342169 GIT binary patch literal 4837 zcmV004&%004{+008|`004nN004b?008NW002DY000@xb3BE2000Uv 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 X0RZaNFc2ew00000NkvXXu0mjf4472? literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/mffs/textures/items/moduleBlockAccess.png b/src/main/resources/assets/mffs/textures/items/moduleBlockAccess.png new file mode 100644 index 0000000000000000000000000000000000000000..346e875ebab096159bda38cf1fa06f1952b638a9 GIT binary patch literal 4625 zcmV+s67KDZP)004&%004{+008|`004nN004b?008NW002DY000@xb3BE2000U( zX+uL$P-t&-Z*ypGa3D!TLm+T+Z)Rz1WdHz3$DNjUR8-d%htIutdZEoQ0#b(FyTAa_ zdy`&8VVD_UC<6{NG_fI~0ue<-nj%P0#DLLIBvwSR5EN9f2P6n6F&ITuEN@2Ei>|D^ z_ww@lRz|vC zuzLs)$;-`!o*{AqUjza0dRV*yaMRE;fKCVhpQKsoe1Yhg01=zBIT!&C1$=TK@rP|Ibo3vKKm@PqnO#LJhq6%Ij6Hz*<$V$@wQAMN5qJ)hzm2h zoGcOF60t^#FqJFfH{#e-4l@G)6iI9sa9D{VHW4w29}?su;^hF~NC{tY+*d5%WDCTX za!E_i;d2ub1#}&jF5T4HnnCyEWTkKf0>c0%E1Ah>(_PY1)0w;+02c53Su*0<(nUqK zG_|(0G&D0Z{i;y^b@OjZ+}lNZ8Th$p5Uu}MTtq^NHl*T1?CO*}7&0ztZsv2j*bmJyf3G7=Z`5B*PvzoDiKdLpOAxi2$L0#SX*@cY z_n(^h55xYX#km%V()bZjV~l{*bt*u9?FT3d5g^g~#a;iSZ@&02Abxq_DwB(I|L-^b zXThc7C4-yrInE_0gw7K3GZ**7&k~>k0Z0NWkO#^@9q0fwx1%qj zZ=)yBuQ3=54Wo^*!gyjLF-e%Um=erBOdIALW)L%unZshS@>qSW9o8Sq#0s#5*edK% z>{;v(b^`kbN5rY%%y90wC>#%$kE_5P!JWYk;U;klcqzOl-UjcFXXA75rT9jCH~u<) z0>40zCTJ7v2qAyk54cquI@7b&LHdZ`+zlTss6bJ7%PQ)z$cROu4wBhpu-r)01) zS~6}jY?%U?gEALn#wiFzo#H}aQ8rT=DHkadR18&{>P1bW7E`~Y4p3)hWn`DhhRJ5j z*2tcg9i<^OEt(fCg;q*CP8+7ZTcWhYX$fb^_9d-LhL+6BEtPYWVlfKTBusSTASKKb%HuWJzl+By+?gkLq)?+BTu761 zjmyXF)a;mc^>(B7bo*HQ1NNg1st!zt28YLv>W*y3CdWx9U8f|cqfXDAO`Q48?auQq zHZJR2&bcD49Ip>EY~kKEPV6Wm+eXFV)D)_R=tM0@&p?(!V*Qu1PXHG9o^ zTY0bZ?)4%01p8F`JoeS|<@=<@RE7GY07EYX@lwd>4oW|Yi!o+Su@M`;WuSK z8LKk71XR(_RKHM1xJ5XYX`fk>`6eqY>qNG6HZQwBM=xi4&Sb88?zd}EYguc1@>KIS z<&CX#T35dwS|7K*XM_5Nf(;WJJvJWRMA($P>8E^?{IdL4o5MGE7bq2MEEwP7v8AO@ zqL5!WvekBL-8R%V?zVyL=G&{be=K4bT`e{#t|)$A!YaA?jp;X)-+bB;zhj`(vULAW z%ue3U;av{94wp%n<(7@__S@Z2PA@Mif3+uO&y|X06?J#oSi8M;ejj_^(0<4Lt#wLu#dYrva1Y$6_o(k^&}yhSh&h;f@JVA>W8b%o zZ=0JGnu?n~9O4}sJsfnnx7n(>`H13?(iXTy*fM=I`sj`CT)*pTHEgYKqqP+u1IL8N zo_-(u{qS+0<2@%BCt82d{Gqm;(q7a7b>wu+b|!X?c13m#p7cK1({0<`{-e>4hfb-U zsyQuty7Ua;Ou?B?XLHZaol8GAb3Wnxcu!2v{R_`T4=x`(GvqLI{-*2AOSimk zUAw*F_TX^n@STz9kDQ z$NC=!KfXWC8h`dn#xL(D3Z9UkR7|Q&Hcy#Notk!^zVUSB(}`#4&lYA1f0h2V_PNgU zAAWQEt$#LRcH#y9#i!p(Udq2b^lI6wp1FXzN3T;~FU%Lck$-deE#qz9yYP3D3t8{6 z?<+s(e(3(_^YOu_)K8!O1p}D#{JO;G(*OVf32;bRa{vGizyJUazyWI3i3tDz02*{f zSaefwW^{L9a%BKeVQFr3E>1;MAa*k@H7+qQF!XYv000LZNklRZ&OwyM-0s2cU5f06fm)9zk7J(uew zNPUc@CEwxPbJkvaI_J)v@8#zR1SptF3T!?v#d4V$MDQ*iqbNU5l}mzfI!)1hmI8@5 zxx*oW!|x+UFhEwflZ+O#z~=Li)#adNvxydr2EmNoW}8hWi|2EKM6p1d&vpd0osNcf zzek;;LmIuBYUrJv((u&_c@7lYEsF6RekNshI0SaTpG*!rd7}|B*){}oON%!ooXi+j z1d|CtrdpwTcbh7mHkH~<+Tw+?^(yrzC$xKVO#O>9I+|Y6;pGMGo{s6{%@tL6e3c1j zH|rG1W+-0BlPee`cPPXQN6D~m5yM=p65cHujkgnMx7*ZgHmP2(Q>j!ER4NrJ7K@b2 z+wlM^~WKc~rLLgVpRaB*=V_ot`qn&D7zcz8&=ySrk@8q2@#a?TP+m5Wr~ zYKh!ww#;NQi50M{-|q_sgMmzZe0(gED}V^DK?cAWkQ$9fvM8{#vqS6a>oT8%t+#Wa zTAYp>7X;b=mF+ER?e9^DeHM$wD3wad2c1qwaCCGelV4t5(sVi%C`)0vo&ZRJfKm(u z;F@eUOW{nKvb8E_h4Y3$D3zcZ2T+NFF35qiwzfu54jg<0>p==Kf&`$f$2bQ^ImW1W zPzsCN?RM&Ry8^_9$Kw&h5C^eVq`5N`)GLsbBC^j#1s_6M#6Y!L6$|`aNU*>^Kf3Afs}=g| z?S|mjOM?b=kAIuRKwhs`iyycW3Z=Q&W!ZWFRa2{mzF36z&nGl|`9fj<{zsnIYBf!P zQp!hvPR&9<;nSy2^x?w?`nkU-?-U&C28j)P4)D%zz4ld7cB>-QGZ+%t`u>Sh`np_)3d4~7E%JTfJ1gbmR)a>oe5{Phl z9C1S#ytp8r&nF6iG31+@n-i2%Ua|6*u~ox3|Ac@aI?FT9;ev+`AJWsOPepoIp3mng z%V_TRsD02UUtH$`wA9Jl*V15+uP7J_2*}5eA8SE~Kvcn~u2oQ~djuf}EG{le&v1c0>amzU6A+kqhA|*uwOTbJ zFdq)w$?l&!NQtD&e#7h#Fjqp#W+D09Qali^U=?P+6d&U7r!S)@Q-$>Z&#m zGHYXl(~|=ets0fk#MfUD*d7jUC7|knl3A~Yx`rYkf-Ja=0E!SWLm*zrQRiTvTD@ID z8AbU;L4x1l3bWZPRSyd(0!r>LU4bzUtC5zMm&xsR3sANnJa`~o7DXtM%g#2VWGOG( zF6@9n0Ft2rVR1!3iVMRf|3)1?KgY8T^XKPlhI#1)kR5;l2fC7kQWC0|FGJ4#-dzS!=*JEK}f$rVAr!_Gwj>d&={n*@cOP(Qs zW|YRJq}7nBhsjWm0jPlwQ6V8Ef)pwNAch)&va5hB!Zn^las?2;ym3xNKW79sCO5s{ zKLWvITnNB#dIBKvEdq+rw+QGL$F;#=5CUoLupTySh5&X%P$0uOYUiyIdOTtPZa`&J zfYl(U6hM8z;z%##Jpj4kMz{>V2jF`s01~NEQFh=KR!UPK$aNsfkqNkU5<_kUv}9PU zUkn5QEPw@7oZuP8DFRRc?=Wt|r=$9AmnvLG@|;CQ z-rAS=c!u3CPFXOj*lfrN$;JT=>&+ZzGX&rZ3{LSPK%9wqxDo;(&RYO+f(iypbA0>) z@~l*b4=*Vu7~-M@U>-S=;jqdb55NxC%JBmz7kn>=@;m>*E00000NkvXX Hu0mjfdc&50 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/mffs/textures/items/moduleBlockAlter.png b/src/main/resources/assets/mffs/textures/items/moduleBlockAlter.png new file mode 100644 index 0000000000000000000000000000000000000000..d5cb19f720c5b6b95800de5881c1791bf0695112 GIT binary patch literal 4680 zcmV-O61VM%P)004&%004{+008|`004nN004b?008NW002DY000@xb3BE2000U( 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 KMNUMnLSTYQFwxQg literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/mffs/textures/items/moduleCamouflage.png b/src/main/resources/assets/mffs/textures/items/moduleCamouflage.png new file mode 100644 index 0000000000000000000000000000000000000000..cee45ae978bfb34ea68dd90013a6adab4b0748be GIT binary patch literal 5545 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 P00000NkvXXu0mjf#N@wq literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/mffs/textures/items/moduleCollection.png b/src/main/resources/assets/mffs/textures/items/moduleCollection.png new file mode 100644 index 0000000000000000000000000000000000000000..09166ade0cfaf24815987426018f6d50f9c24705 GIT binary patch literal 2111 zcmd^<`B&3d7QnxhLRkuPs6C>D^l)lZM;b zxY_^!U?&uCd{$KzSiA14LXfzs$ z!(p-501(9Ca7a9e#N&_zJc>X-5eaA_5kn?nNhBp$#Gn%y!6aq~nL#Hrg2@a9B_xEx z452cafe=AKbUHmaIGDj;gg`KvEEbE#W>VR#KsGaw&7yJGL6D)4oS@LqU@nKw3k&9R z>3klG!(oJlGPq$39yf#!$!7_|SwaC*C}fF*`8>xXfvkuX#&;zWozl87)Vq=Y9C^CS^mDWpUo5D0}rkw_#Kiz6Z;Boc{K zDvgYc zHL5giY+9;Xr&a6H)ahxldR?3$J>H;C$VgAf)W>CIBxV_svNMx&vXXPNl5(?CQc^S; zO=@bYR;x`*OVjCe>FMcuyg+u$pL>8kK8Z zf@@up>s5nSPmWJdF=?XMbLX)=OG_IX8X6lLo0^)gT)EQH($e1Ee)Hzdj*gDb&d#o`uI}#cJ9q9FjmF;I-oC!R zfq{XMk&)5SQIpB^?Af!asj2DdY3TER^l65A!VD;sOBFl+-vEluFQB;rSmz633!t&k zzZ+(mrV4B5(6x}KE>z^D7yd=FPY1{}hTK9>%8Q2YCxH}@fXA=zy8?}r6GAR0IxtfE zArioE?{vOixVFda^QLNz!7w{NZfSXu-u>dm5-}k=duNBV?X+24U44nDdo@sTyMFm) zU&)i+Z^f6cHX;yreNPPzTqv_CY)DKX`fZROjlVEzKF&6N6}cHXvU>U{2|r&!I;lH> zUR=ruK%p?8l{E?pzF9%G`AFl35 z>e;8MxPTRKG7A(|B~jDwe`&9Frx&j;u3inVb_?!GpTEC#UpI4cl5H{GbNj|0;`2H~G7u$Xt_}toa zr?mwb#!|0y0bo;k&-DhU$?nC$HqV!=qg(%dJ^aI;-X-;A7*N*M-!Ps!UhkjpN7?So zy+4R!9{#Yh`p3sj&)J@X8}E4rgCQzE?`uExJ^PcNIRY^gEc4d>te3f@otC=s@#XRA zx;oS3xpU`QS|-k%nY;hdat_zM}uc$VS$Ne^{RFQ@9nrG5v<e!HuEePUkn7z!tBE(|l z&Ld2HXY$CShns!6{hKBj|I>|pS=wOa+o*11Q2=rTgin}$AG!;~$HQP2kN^4XLtwi@ zA$vBvV^3<&p#XUQ_~g*g!tY8YT;`xO9y)#Y$s_mHe)L_==?xQ1EVhLy5#JuFudS_h z{M(1E&IC=`>4L|WnEV(;*X?8Ie;n}muJrQdW0Ze=-r65TNvs&185$dl5b}gVwUEO- z9(hv5E_mF{V=ye7 zEe7L{!`Rw>!MfZGXO&$1o{9v&JZwz;sxfgPqLEQFbC2|E-ST(egrFWgd`wGxC>t|t zffIkcA61YkfALnLH@%yt-0i&9F+DukKE#fVcW9mK6N^NxU0rQ$SqCIaWzPN|>+7qU j%6faxHZ(x5uQ>p~`3~nj;Z<+YP~!qZo|M}Wno|BhGlSuI literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/mffs/textures/items/moduleConfiscate.png b/src/main/resources/assets/mffs/textures/items/moduleConfiscate.png new file mode 100644 index 0000000000000000000000000000000000000000..5f7f059da31dcb2ab95e91f8fd0a852fee6bad23 GIT binary patch literal 4511 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/mffs/textures/items/moduleGlow.png b/src/main/resources/assets/mffs/textures/items/moduleGlow.png new file mode 100644 index 0000000000000000000000000000000000000000..0895fbd4c7dffb59ae053c2987ac68f3e3f03089 GIT binary patch literal 4685 zcmV-T60+@yP)004&%004{+008|`004nN004b?008NW002DY000@xb3BE2000U( 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 P00000NkvXXu0mjf5?jzU literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/mffs/textures/items/moduleInvert.png b/src/main/resources/assets/mffs/textures/items/moduleInvert.png new file mode 100644 index 0000000000000000000000000000000000000000..03265476ef821c624de6703d9399a001bb4b452d GIT binary patch literal 2100 zcmd^<`BRhE8h}3#MhsUR5iYAN2}?*q7P9XPSs@7@Ng#nh2#|mQS!5qX32`ZewwKYi zP%gCAL8*Yng%Rs6Hmy=`4IoseNQ;%av|JFlO+g&)$J{^TKJ&cqd(N3TKb$k?ye*(o zvJ(~z0{~#BOe$1CHDW8gwn16gWB+z*k}p*$0H8h^0IWv#Ek3=HlAkZi@8jZx^Fc?fc1Qv_K;gEPN5|2X?@Non}Tmk`=kbou;F+?H;$|Mq& zOvX|mDOf5MN2B8LcmjctkdQzm67f_Di9{lk$rK8ON~Pjy6g-VepwkF+dIAHIL1Zx! zSWF^^O=2-fEGCJ?BD2|K4x7T^&>-k^27|$5GFdDZ8-l~(a=Ag=QYw!_;c;m^4voj9 z@_BSf0VJO;5HN*&hA5FK7Ba*lE}zdz6tIMeERm2S7P7=5wph%SO1Ls9M<(MY$)fn? zSV<{LQWB*&%;WL+5CTDBVxmwe6p2J)u~;IJ@T3x+Ov+1=36hg|@+5&gnXiy1Dj^jj zMY2dC7b+nYQmIrXlO-i3B_}7#<#L5Wp;RhUQc^^qQUs=mRiIdvD$%HASRS};=wX6sW8 zSvs9ABO@a-GgGhEXJ=;{42GPX9JSG)$<0ya8Pg#1bG4@Y3{#%YoUb#RbOol2LUX32 zKyN9`+Ex8 z94>|aqua%>vuEp%!!|Y;%MD#!o14Uqc9>Ky|CCufHIR`^>7rK_{QPQXNWCxHWLiBF z9~GTph5e1qVy_gYEErT58XwK6C9c^{!ettA`pIKegoE^{cb{?jn_Hco*IwK2-?zWM z*0QI+e?3Ot!6G<*272zq6D}5wKfhJ|`&7wv#r&wFza5u#wPtPn&jtODkEJN9pUG7v zfoY#^vwi;pmwl~je%#U8zWDTZZP}T+?xxQ|!KUwq96opFaE2Ro^^5BtgtX(buhzYB zYjfq9t2M?Zcd%)3=3I^7hsl3ZZ`U;}j-T=ViCT7WDxrFMe%Jx!ngZz<9(haSx3!dR{*ol&NDBe=IEYpFel*T%Ub?34J=D@fj`*`f${jopyu&3l`+5&T*`?6!U8}-Fps=xou>iPLG9%wN5rw94_ z2M3?vXaoGf>wmY<8OMcUTTe3Y%buZ`>9H}Tfc_;9Hef{P_;k>>2k3!c3mu5yhWA8R z-no;*dM_+3zw~V*d3_{ow-goOcLaQEgQKgbG-T%XHddg`>(r=f$L`44v!ui}>cPx! zXrcE;`RjKJtZ5(hc@dWD-dg>h6xJ41(wIm5cmn`2>DaL#x{9^)4vaNK?(SZ&et5LQ zO)x()GBOjo_DO_i*!0(Z4}CtInwpPjv@RfV0e-vZ%+G)Lv&|E=WdC4NrJficzcdCM zLwGGUqg$K3yq8gNac=%s^&XxwuQwItUf!23US9F4xNxb$+q=aM^L`N+Xni(9a&o`^ z{$Ay)8}yamKEHmb_TI%$qA%~+cxqc-{Z~|WB<$IqkeSur%srUt+JmkKzpk7ezT)zz zUmx!53%PIg+i*P`wGUrdT3NA|K$n0XU2(Zc6f%LJ)sXOj+29TUq#(Z&!nYHvTa8U7 LQVPEk7;XOrLUF>S literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/mffs/textures/items/moduleManipulator.png b/src/main/resources/assets/mffs/textures/items/moduleManipulator.png new file mode 100644 index 0000000000000000000000000000000000000000..3b603e48287674665e17e6b3caca9b248c694ed8 GIT binary patch literal 4704 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/mffs/textures/items/moduleScale.png b/src/main/resources/assets/mffs/textures/items/moduleScale.png new file mode 100644 index 0000000000000000000000000000000000000000..fe60e48509e03558ff467fcbcf249664da96b7f1 GIT binary patch literal 4752 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 e!as!nhxKojlmAOCb literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/mffs/textures/items/moduleShock.png b/src/main/resources/assets/mffs/textures/items/moduleShock.png new file mode 100644 index 0000000000000000000000000000000000000000..c41a4664bb861101b525a5b608d66b625adf6f6e GIT binary patch literal 4803 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/mffs/textures/items/moduleSpeed.png b/src/main/resources/assets/mffs/textures/items/moduleSpeed.png new file mode 100644 index 0000000000000000000000000000000000000000..926064000f598bece0ba14a018a7b55097ae8fda GIT binary patch literal 4713 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/mffs/textures/items/moduleSponge.png b/src/main/resources/assets/mffs/textures/items/moduleSponge.png new file mode 100644 index 0000000000000000000000000000000000000000..634a04d7241d345f2231b9fc8d0d072913202f9e GIT binary patch literal 5354 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 IM6N<$f?FOslmGw# literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/mffs/textures/items/moduleStabilize.png b/src/main/resources/assets/mffs/textures/items/moduleStabilize.png new file mode 100644 index 0000000000000000000000000000000000000000..adac3879d066ffdad1eb6f79411d5af9a9f71d61 GIT binary patch literal 4919 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/mffs/textures/items/moduleTranslate.png b/src/main/resources/assets/mffs/textures/items/moduleTranslate.png new file mode 100644 index 0000000000000000000000000000000000000000..8c38c67595c3d79ba53468330ef19d18ad4b3f80 GIT binary patch literal 4932 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 beg&8;bKA;@gEoP`8~_a!9py?T%h3M=kT@^W literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/mffs/textures/models/coercionDeriver_on.png b/src/main/resources/assets/mffs/textures/models/coercionDeriver_on.png new file mode 100644 index 0000000000000000000000000000000000000000..9d03c9a92114168281a51c2c5f50e8e92474f930 GIT binary patch literal 4041 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�sLK)zpXXM?en1D0nC1%wr4?Wb?*BM78M-1yF0VZ$M#j(HNATo z!grZ&Vn7rBK2b{7FDeEOael#(YsCgSm?q34JYCAj;9U3p_y|vS-i8tCQnXa=Kl?a7 zl8VjRkp_*f)A!z)#iECX(slmwcMEb?lW9^=#O6fJM;kFRDHanTKaUqOY1;my^H-B) zEba@=m{)Qb7oPTIzE{ykl`sYo@IJHLlw($>NZf*Ljq5=&VNbY4!`<0w*{jWz!*T;m)m#x2_yW6Gl;hG)0kq!*Y;Mk({B>UErBi$w2 zF7MOB*CAa}Q@FGRT8m+D5k0VR!|Eb3pW>(v}-h_Y>ucsB7fD zOW=xAq_NRjWQ~!Rnsa;UpC-oQtZSVc;RUaMSeIgR_I3m_`04oz12C<6Jo0q7s4qrN z_|~B+wq)a^cxIlNUJ5@xj1{oy)?H}I^;O&8f!Kv@Yg38TpL(pE@jHk;?e=JdWxqI3 zXKl`lGi4MVx%R^#-lk2*sao&i1#?#8X)==iHWs6x)Ur7f- zKcq4=q*D=$aU>&_vG~fS7EuBHCh-^hBQ<8lrdLI&9joF;cbT@kzn0u_p%SbWXlG0U zcjXyH;7W-vMajY;6NF{7EqQkDp!ewk!D_6(bL`KNsJ+V<$Bp~*C1KWW(6qeUaPyu( z5e6jyqzlZ4$F|2_+2=EbJSmVGJwEMW`+)2r%|H`bC7TMr3n7zL5IGQ8n^EQwP%2TD&CnEl{MQWtdRm5>ICc96 F{{f6=-{$}T literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/mffs/textures/models/forceManipulator_off.png b/src/main/resources/assets/mffs/textures/models/forceManipulator_off.png new file mode 100644 index 0000000000000000000000000000000000000000..d8b399020ce450120ec1ca92bbd116de51a4ab7b GIT binary patch literal 5337 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/mffs/textures/models/forceManipulator_on.png b/src/main/resources/assets/mffs/textures/models/forceManipulator_on.png new file mode 100644 index 0000000000000000000000000000000000000000..cfda3babbaf0efeecd52fb191571b5430b8769f6 GIT binary patch literal 5399 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%0APpDq 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/mffs/textures/models/fortronCapacitor_on.png b/src/main/resources/assets/mffs/textures/models/fortronCapacitor_on.png new file mode 100644 index 0000000000000000000000000000000000000000..f0df7395ef4532add7efa8a22c93ea148e5a1dce GIT binary patch literal 2932 zcmd^=2U8Q+7J%a-=t{BSN+=RYApsIv5)zU?IwU|K(v=c=KthuuNDoB7Pz3}8A#M;w z6ahsPMZ`i?5Gk^Vz2J(nQbcf(4g2QJ`w{QXz4y$VbMAM_oSB>B$gx)5roIgT04TF; z==)_dO?JpzMqqiyZ5U7rUu*# z)KF8`1ZrriYiem|X=`eO_JOp4Iv{mjT@8?qHW;i4f@OL>COxfk43! z7#OMtfx^KsI7AN))6<8-5qby%J-8uE-vEIygc~6B4NwR}q=6wyABi$FGDaDj7#W)y zq0J0U%#2OY#%5?!G}aVjjz;6musDo49&2ua!Qstu1T2Y!#arMkh=@V8?N^ci?gy_d9T%9QQkOot*bOyEwVHI=i~NxOup`A8_+H=zhS{#*b-dZ{FW4lWXC*e0V=m*;ZYzqOD;;~GlKoO8_tlQ$ zZ}91NEHds9GVhT@Jw#EjWp=-1&Y)@fW3$XBW?7?X(U?W%V{-Z+`S>G>c!-)mA{+kD z$3qtYfK7my{T!$D|L+BGTHXScwdB`G8;`>PfJ*nq*|Z1FPLnCsV;Jr+P7y&d@xIZ4 z07u`D@E8<_;S7p1Lt#)R#>R`$5&%HqDT_{V=F>i(JnHTgtJdR|i91tHRzw)sW%qf*gg1s|-8YH4eMT!&#e4sCAZAPj_z6wQDaz-N zYYIe@Y<1~?^qig6MeQJsVuE;lv3q`aTwb$UfHu9OHuzHE!P3OL%7p|;uP^p(#QD%~ zC-bq7)iGtq+EBcu)r?=TYC_;>S3=fAMBwI>2KU!h{rH-=)dASM7ljvcdNxpoUXG5u zZ4Y>`e(SEXqbtSds~kK1;}=HzKL*ydCAsb{*ho9KeHS+%Vz^4HlHOixY-3{c*A+l6DIvSHcTnTZCJAMWfxq`KviU}f?9mA?3 zgS8_@n9RSyY6oW*+?;2ht=wINr3Z&$Pk#_RxCb%ZE`TE*$qhU$>CIN35j218{J3Y& zo|M$q-l?$r0j)40On!i-vCYN#nz&9E99nxa@bS!ebw@9?>XtM!tTl6a>-c{l;u&;B zd2jY@xvUB$A1?mlh*$U25y}pF)4@posQbP@9Is%@Fo(e4P*AubW1+KuE(Ow2T3dT5(X&H$9{9 z+Gs*~(XFHu^DC!5c)Led{7M58D&@(V!d++@&2zJ6j&@CE30G4m|G06j57bUXhDX0$ ztHa*)xU~_8Um+J8CkUV`pIhL6@@|@#+kq>nXQ(ooUd-`&12f-Blmh{@gAe6&!9RD3 zwZe9LUJ^X?Q4Aj%FZ*rYThX@DsT0?tKLBuJ4aa4A! zQop18=;0yBAP}aJVWRk{wrbdV7~zm|V*>E0wzo5L!t>~hGZW9<*B)Ja z@%iXN^QV2O^GnxUn^JyECpS@nJhP`cLHP?JZyhbsNr0)osodRQtDB*pMatUPFIM00 zB(YMr1*Qcpalj7~XibGGLU5Wm_e{FI;Fvk8a530XB@$Jd^ho~WhkEF8k!ndmB-&ai z&K>O9lg{WnyIpHi6}@A)hK2{kaxMIgi`IGdtZi)5L1ydD0Oz-JT~*e9P6)!DJ&XJP zqD{W|r(FLgnER8wC!KJQrN68M z1?<&$_!izQ%?q`+r@|B>Uk8w!c(ugd#?I|kdgkra5tRG}HvjO))u?7^U{9oR{N!*| zmEDcG`^6di(}w$A;$+O773oD|+sDSuN1Hr4!u{8hSVmbb;^Cj&!IYVR$ScxXY4%{( zSnHusxABPy^P9^lf~(S+|9O<>$?DW?cm@7oxzJqO#_67G8=Dc1E!_W{od*< zp|eo3Ry5&bvGJ&v2bG61y2!lu@u%0zzqIeA{!pxumz=mW@^5rt|9?sB)>^{3ApN0K zyLIJcErLs>{4@pQlRb>)X4O_s-DlDK0jxQu`EI4)qfzagR8m<_ zTsJ{>?Byslcx(W3m%G;~nAiP;56@}s%Rjfg_a3|2DYwc|ZyA_z9`>*8As3|YlOri` en$zF(tjpnFK50OrI>%){A%Ml;&@WMW8UFzP&Z5cy literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/mffs/textures/models/projector_off.png b/src/main/resources/assets/mffs/textures/models/projector_off.png new file mode 100644 index 0000000000000000000000000000000000000000..99d340ff1b436e124348af20023cdd533edb7ce5 GIT binary patch literal 10853 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