extended police and items

This commit is contained in:
2026-01-29 10:32:29 +01:00
parent b7c5f9cb31
commit 1cf3b06f59
22 changed files with 302 additions and 56 deletions

View File

@@ -0,0 +1,6 @@
package dev.tggamesyt.szar;
public interface Arrestable {
boolean isArrestable();
}

View File

@@ -2,50 +2,65 @@ package dev.tggamesyt.szar;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.attribute.AttributeContainer;
import net.minecraft.entity.attribute.EntityAttributeModifier;
import net.minecraft.entity.attribute.EntityAttributes;
import net.minecraft.entity.effect.StatusEffect;
import net.minecraft.entity.effect.StatusEffectCategory;
import net.minecraft.entity.mob.MobEntity;
import java.util.UUID;
public class ArrestedEffect extends StatusEffect {
private static double originalspeed;
private static final UUID SPEED_MODIFIER_ID =
UUID.fromString("b2c7c2b8-0e55-4c9f-9e8d-8c5fdd7b9c11");
public ArrestedEffect() {
// BENEFICIAL = false because it's like a debuff
super(StatusEffectCategory.HARMFUL, 0xA0A0A0); // gray color
super(StatusEffectCategory.HARMFUL, 0xA0A0A0);
}
@Override
public void applyUpdateEffect(LivingEntity entity, int amplifier) {
// This method is called every tick while the effect is active
if (!entity.getWorld().isClient) {
// Stop movement completely
entity.setVelocity(0, entity.getVelocity().y, 0); // keep Y velocity (falling) if you want
// Freeze horizontal movement
entity.setVelocity(0, entity.getVelocity().y, 0);
entity.velocityModified = true;
// Stop AI for mobs
// Stop mob AI
if (entity instanceof MobEntity mob) {
mob.getNavigation().stop();
mob.setTarget(null);
}
// Optional: reset movement speed to 0
originalspeed = entity.getAttributeInstance(EntityAttributes.GENERIC_MOVEMENT_SPEED).getValue();
entity.getAttributeInstance(EntityAttributes.GENERIC_MOVEMENT_SPEED)
.setBaseValue(0.0D);
}
}
@Override
public boolean canApplyUpdateEffect(int duration, int amplifier) {
// Run every tick
return true;
}
@Override
public void onApplied(LivingEntity entity, AttributeContainer attributes, int amplifier) {
var speed = entity.getAttributeInstance(EntityAttributes.GENERIC_MOVEMENT_SPEED);
if (speed == null) return;
// Check by UUID manually (1.20.1-safe)
if (speed.getModifier(SPEED_MODIFIER_ID) == null) {
speed.addPersistentModifier(new EntityAttributeModifier(
SPEED_MODIFIER_ID,
"Arrested speed reduction",
-1.0D,
EntityAttributeModifier.Operation.MULTIPLY_TOTAL
));
}
}
@Override
public void onRemoved(LivingEntity entity, AttributeContainer attributes, int amplifier) {
// Reset movement speed when effect ends
entity.getAttributeInstance(EntityAttributes.GENERIC_MOVEMENT_SPEED)
.setBaseValue(originalspeed); // default walking speed for mobs
var speed = entity.getAttributeInstance(EntityAttributes.GENERIC_MOVEMENT_SPEED);
if (speed != null) {
speed.removeModifier(SPEED_MODIFIER_ID);
}
}
}

View File

@@ -18,7 +18,7 @@ import net.minecraft.world.World;
import java.util.*;
public class GypsyEntity extends PathAwareEntity {
public class GypsyEntity extends PathAwareEntity implements Arrestable{
public static boolean arrestable = false;
@@ -285,4 +285,8 @@ public class GypsyEntity extends PathAwareEntity {
return best;
}
}
@Override
public boolean isArrestable() {
return arrestable;
}
}

View File

@@ -0,0 +1,26 @@
package dev.tggamesyt.szar;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.effect.StatusEffectInstance;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
public class HandcuffItem extends Item {
public HandcuffItem(Item.Settings settings) {
super(settings);
}
/**
* Called when the player right-clicks an entity with this item.
*/
@Override
public ActionResult useOnEntity(ItemStack stack, PlayerEntity user, LivingEntity entity, Hand hand) {
entity.addStatusEffect(new StatusEffectInstance(Szar.ARRESTED, 2400, 1));
stack.decrement(1);
return ActionResult.SUCCESS;
}
}

View File

@@ -20,7 +20,7 @@ import net.minecraft.world.World;
import java.util.*;
public class IslamTerrorist extends PathAwareEntity {
public class IslamTerrorist extends PathAwareEntity implements Arrestable{
public static boolean arrestable = false;
private int BlowUpCooldown = 0;
@@ -223,4 +223,8 @@ public class IslamTerrorist extends PathAwareEntity {
return best;
}
}
@Override
public boolean isArrestable() {
return arrestable;
}
}

View File

@@ -0,0 +1,79 @@
package dev.tggamesyt.szar;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.sound.SoundCategory;
import net.minecraft.sound.SoundEvents;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.TypedActionResult;
import net.minecraft.world.World;
public class KeyItem extends Item {
public KeyItem(Settings settings) {
super(settings.maxDamage(3)); // max durability 3
}
// Right-click on entity → lose 1 durability
@Override
public ActionResult useOnEntity(ItemStack stack, PlayerEntity player, LivingEntity target, Hand hand) {
if (!player.getWorld().isClient) {
if (target.hasStatusEffect(Szar.ARRESTED)) {
target.removeStatusEffect(Szar.ARRESTED);
// Play sound to indicate effect removed
player.getWorld().playSound(null, target.getBlockPos(),
SoundEvents.BLOCK_ANVIL_USE, SoundCategory.PLAYERS, 1.0F, 1.0F);
// Use 1 durability
stack.damage(1, player, p -> p.sendToolBreakStatus(hand));
}
}
return ActionResult.SUCCESS;
}
// Hold right-click to use on self → lose 3 durability
@Override
public TypedActionResult<ItemStack> use(World world, PlayerEntity user, Hand hand) {
ItemStack stack = user.getStackInHand(hand);
if (!world.isClient) {
if (user.hasStatusEffect(Szar.ARRESTED)) {
user.removeStatusEffect(Szar.ARRESTED);
world.playSound(null, user.getBlockPos(),
SoundEvents.BLOCK_ANVIL_USE, SoundCategory.PLAYERS, 1.0F, 1.0F);
// Use 3 durability
stack.damage(3, user, p -> p.sendToolBreakStatus(hand));
}
}
// Start hold animation
return TypedActionResult.consume(stack);
}
// Make it holdable like a bow
@Override
public int getMaxUseTime(ItemStack stack) {
return 72000;
}
// Continuous usage tick
@Override
public void usageTick(World world, LivingEntity user, ItemStack stack, int remainingUseTicks) {
if (!world.isClient && user instanceof PlayerEntity player) {
if (player.hasStatusEffect(Szar.ARRESTED)) {
player.removeStatusEffect(Szar.ARRESTED);
world.playSound(null, player.getBlockPos(),
SoundEvents.BLOCK_ANVIL_USE, SoundCategory.PLAYERS, 1.0F, 1.0F);
// Remove full 3 durability if held
stack.damage(3, player, p -> p.sendToolBreakStatus(player.getActiveHand()));
}
}
}
}

View File

@@ -16,7 +16,7 @@ import net.minecraft.world.World;
import java.util.List;
public class NiggerEntity extends PathAwareEntity {
public class NiggerEntity extends PathAwareEntity implements Arrestable{
public static boolean arrestable = true;
@@ -45,4 +45,9 @@ public class NiggerEntity extends PathAwareEntity {
protected void dropLoot(DamageSource source, boolean causedByPlayer) {
this.dropItem(Szar.NIGGERITE_INGOT);
}
@Override
public boolean isArrestable() {
return arrestable;
}
}

View File

@@ -25,35 +25,55 @@ public class PoliceArrestGoal extends Goal {
@Override
public boolean canStart() {
// 1⃣ Find nearest arrestable mob
List<? extends MobEntity> nearby = police.getWorld().getEntitiesByClass(
target = null;
// 1⃣ Find nearest arrestable mob (NOT police)
List<? extends MobEntity> arrestables = police.getWorld().getEntitiesByClass(
MobEntity.class,
police.getBoundingBox().expand(16),
mob -> isArrestable(mob)
mob -> mob != police && isArrestable(mob)
);
if (!nearby.isEmpty()) {
target = nearby.get(0);
return true;
if (!arrestables.isEmpty()) {
target = police.getWorld().getClosestEntity(
arrestables,
TargetPredicate.DEFAULT,
police,
police.getX(),
police.getY(),
police.getZ()
);
return target != null;
}
// 2⃣ Find entities attacking villagers or police
List<LivingEntity> possibleTargets = police.getWorld().getEntitiesByClass(
// 2⃣ Find actual criminals (players or mobs attacking protected entities)
List<LivingEntity> criminals = police.getWorld().getEntitiesByClass(
LivingEntity.class,
police.getBoundingBox().expand(16),
entity -> isAttackingProtected(entity)
entity -> entity != police && isAttackingProtected(entity)
);
if (!possibleTargets.isEmpty()) {
target = possibleTargets.get(0);
return true;
if (!criminals.isEmpty()) {
target = police.getWorld().getClosestEntity(
criminals,
TargetPredicate.DEFAULT,
police,
police.getX(),
police.getY(),
police.getZ()
);
return target != null;
}
return false;
}
@Override
public void start() {
if (target == null || !target.isAlive()) {
return;
}
police.getNavigation().startMovingTo(target, 1.2D);
}
@@ -93,28 +113,25 @@ public class PoliceArrestGoal extends Goal {
}
private boolean isArrestable(MobEntity mob) {
try {
return mob.getClass().getField("arrestable").getBoolean(null);
} catch (NoSuchFieldException | IllegalAccessException e) {
return false;
}
if (mob == police) return false;
return mob instanceof Arrestable arrestable && arrestable.isArrestable();
}
private boolean isAttackingProtected(LivingEntity entity) {
// Check if entity is currently attacking a villager or police
if (entity instanceof MobEntity mob) {
LivingEntity targetEntity = mob.getTarget();
if (targetEntity instanceof PlayerEntity player) {
return false; // optional: ignore if player attacking non-protected
}
return targetEntity instanceof MobEntity protectedEntity &&
(protectedEntity instanceof PathAwareEntity p && p.getClass() == police.getClass()
|| protectedEntity.getType().getSpawnGroup().isPeaceful());
} else if (entity instanceof PlayerEntity) {
// Check if player recently attacked villager or police
// You may need to track recent attacks in an event listener
return false; // placeholder, can be implemented via attack events
if (entity == police) return false;
if (entity instanceof PlayerEntity player) {
long lastCrime = player.getDataTracker().get(Szar.LAST_CRIME_TICK);
return police.getWorld().getTime() - lastCrime < 200; // 10 sec window
}
if (entity instanceof MobEntity mob) {
LivingEntity target = mob.getTarget();
return target instanceof PoliceEntity
|| target != null && target.getType().getSpawnGroup().isPeaceful();
}
return false;
}
}

View File

@@ -49,6 +49,11 @@ public class PoliceEntity extends PathAwareEntity {
@Override
protected void dropLoot(DamageSource source, boolean causedByPlayer) {
this.dropItem(Items.DEBUG_STICK);
this.dropItem(Szar.KEY_ITEM);
int randomnum = this.random.nextInt(20);
if (randomnum == 6 || randomnum == 7) { // SIX OR SEVEENNN (1 in 10)
this.dropItem(Items.DEBUG_STICK);
}
}
}

View File

@@ -5,6 +5,7 @@ import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.biome.v1.BiomeModifications;
import net.fabricmc.fabric.api.biome.v1.BiomeSelectors;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.fabricmc.fabric.api.event.player.AttackEntityCallback;
import net.fabricmc.fabric.api.event.registry.DynamicRegistrySetupCallback;
import net.fabricmc.fabric.api.item.v1.FabricItemSettings;
import net.fabricmc.fabric.api.itemgroup.v1.FabricItemGroup;
@@ -16,17 +17,20 @@ import net.fabricmc.fabric.api.object.builder.v1.trade.TradeOfferHelper;
import net.fabricmc.fabric.api.object.builder.v1.world.poi.PointOfInterestHelper;
import net.minecraft.advancement.Advancement;
import net.minecraft.block.*;
import net.minecraft.entity.EntityDimensions;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.SpawnGroup;
import net.minecraft.entity.SpawnRestriction;
import net.minecraft.entity.*;
import net.minecraft.entity.data.DataTracker;
import net.minecraft.entity.data.TrackedData;
import net.minecraft.entity.data.TrackedDataHandlerRegistry;
import net.minecraft.entity.effect.StatusEffect;
import net.minecraft.entity.passive.VillagerEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.*;
import net.minecraft.registry.*;
import net.minecraft.registry.tag.BiomeTags;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.sound.SoundEvents;
import net.minecraft.text.Text;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Formatting;
import net.minecraft.util.Identifier;
import net.minecraft.util.collection.DataPool;
@@ -59,6 +63,8 @@ public class Szar implements ModInitializer {
public static final Logger LOGGER = LogManager.getLogger(MOD_ID);
public static final Block SZAR_BLOCK =
new SzarBlock();
public static final TrackedData<Long> LAST_CRIME_TICK =
DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.LONG);
public static final Block NIGGERITEBLOCK =
new Block(AbstractBlock.Settings.copy(Blocks.NETHERITE_BLOCK));
public static final Block FASZ_BLOCK =
@@ -133,6 +139,8 @@ public class Szar implements ModInitializer {
entries.add(Szar.GYPSY_SPAWNEGG);
entries.add(Szar.TERRORIST_SPAWNEGG);
entries.add(Szar.POLICE_SPAWNEGG);
entries.add(Szar.KEY_ITEM);
entries.add(Szar.HANDCUFF_ITEM);
entries.add(Szar.CANNABIS_ITEM);
entries.add(Szar.WEED_ITEM);
entries.add(Szar.WEED_JOINT_ITEM);
@@ -355,6 +363,20 @@ public class Szar implements ModInitializer {
new Identifier("szar", "cannabis_patch")
)
);
AttackEntityCallback.EVENT.register((player, world, hand, entity, hitResult) -> {
if (!world.isClient && entity instanceof LivingEntity victim) {
// Villagers or police are protected
if (victim instanceof PoliceEntity || victim instanceof VillagerEntity) {
player.getDataTracker().set(
Szar.LAST_CRIME_TICK,
world.getTime()
);
}
}
return ActionResult.PASS;
});
}
public static final Feature<CannabisPatchFeatureConfig> CANNABIS_PATCH =
@@ -399,6 +421,16 @@ public class Szar implements ModInitializer {
new Item.Settings()
)
);
public static final Item KEY_ITEM = Registry.register(
Registries.ITEM,
new Identifier(MOD_ID, "police_key"),
new KeyItem(new Item.Settings())
);
public static final Item HANDCUFF_ITEM = Registry.register(
Registries.ITEM,
new Identifier(MOD_ID, "police_handcuff"),
new HandcuffItem(new Item.Settings())
);
public static final Item NIGGERITE_INGOT = Registry.register(
Registries.ITEM,
new Identifier(MOD_ID, "niggerite_ingot"),

View File

@@ -0,0 +1,18 @@
package dev.tggamesyt.szar.mixin;
import dev.tggamesyt.szar.Szar;
import net.minecraft.entity.player.PlayerEntity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(PlayerEntity.class)
public abstract class PlayerEntityMixin {
@Inject(method = "initDataTracker", at = @At("TAIL"))
private void szar$initTracker(CallbackInfo ci) {
PlayerEntity player = (PlayerEntity) (Object) this;
player.getDataTracker().startTracking(Szar.LAST_CRIME_TICK, 0L);
}
}

View File

@@ -29,5 +29,8 @@
"item.szar.terrorist_spawn_egg": "Islam Terrorist Spawn Egg",
"entity.szar.police": "Police Man",
"item.szar.police_spawn_egg": "Police Man Spawn Egg",
"effect.szar.arrested": "Arrested"
"effect.szar.arrested": "Arrested",
"item.szar.police_key": "Police Key",
"item.szar.police_handcuff": "Police Handcuff",
"entity.szar.gypsy": "Cigány"
}

View File

@@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "szar:item/police_handcuff"
}
}

View File

@@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "szar:item/police_key"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 805 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 565 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 525 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 267 B

After

Width:  |  Height:  |  Size: 805 B

View File

@@ -0,0 +1,19 @@
{
"type": "minecraft:crafting_shaped",
"pattern": [
"BBB",
"NNB"
],
"key": {
"B": {
"item": "minecraft:iron_ingot"
},
"N": {
"item": "minecraft:iron_nugget"
}
},
"result": {
"item": "szar:police_key",
"count": 1
}
}

View File

@@ -4,6 +4,7 @@
"package": "dev.tggamesyt.szar.mixin",
"compatibilityLevel": "JAVA_17",
"mixins": [
"PlayerEntityMixin"
],
"injectors": {
"defaultRequire": 1