police
This commit is contained in:
@@ -6,7 +6,7 @@ minecraft_version=1.20.1
|
|||||||
yarn_mappings=1.20.1+build.10
|
yarn_mappings=1.20.1+build.10
|
||||||
loader_version=0.18.3
|
loader_version=0.18.3
|
||||||
# Mod Properties
|
# Mod Properties
|
||||||
mod_version=1.0.9
|
mod_version=1.0.10
|
||||||
maven_group=dev.tggamesyt
|
maven_group=dev.tggamesyt
|
||||||
archives_base_name=szar
|
archives_base_name=szar
|
||||||
# Dependencies
|
# Dependencies
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package dev.tggamesyt.szar.client;
|
||||||
|
|
||||||
|
import dev.tggamesyt.szar.NiggerEntity;
|
||||||
|
import dev.tggamesyt.szar.PoliceEntity;
|
||||||
|
import net.minecraft.client.render.entity.EntityRendererFactory;
|
||||||
|
import net.minecraft.client.render.entity.MobEntityRenderer;
|
||||||
|
import net.minecraft.client.render.entity.model.BipedEntityModel;
|
||||||
|
import net.minecraft.client.render.entity.model.EntityModelLayers;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
|
||||||
|
public class PoliceEntityRenderer
|
||||||
|
extends MobEntityRenderer<PoliceEntity, BipedEntityModel<PoliceEntity>> {
|
||||||
|
|
||||||
|
public PoliceEntityRenderer(EntityRendererFactory.Context context) {
|
||||||
|
super(
|
||||||
|
context,
|
||||||
|
new BipedEntityModel<>(context.getPart(EntityModelLayers.PLAYER)),
|
||||||
|
0.5F
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Identifier getTexture(PoliceEntity entity) {
|
||||||
|
return new Identifier("szar", "textures/entity/police-man.png");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -41,6 +41,10 @@ public class SzarClient implements ClientModInitializer {
|
|||||||
Szar.NiggerEntityType,
|
Szar.NiggerEntityType,
|
||||||
NiggerEntityRenderer::new
|
NiggerEntityRenderer::new
|
||||||
);
|
);
|
||||||
|
EntityRendererRegistry.register(
|
||||||
|
Szar.PoliceEntityType,
|
||||||
|
PoliceEntityRenderer::new
|
||||||
|
);
|
||||||
EntityRendererRegistry.register(
|
EntityRendererRegistry.register(
|
||||||
Szar.TERRORIST_ENTITY_TYPE,
|
Szar.TERRORIST_ENTITY_TYPE,
|
||||||
TerroristEntityRenderer::new
|
TerroristEntityRenderer::new
|
||||||
|
|||||||
82
src/main/java/dev/tggamesyt/szar/AggroOnHitRevengeGoal.java
Normal file
82
src/main/java/dev/tggamesyt/szar/AggroOnHitRevengeGoal.java
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
package dev.tggamesyt.szar;
|
||||||
|
|
||||||
|
import net.minecraft.entity.LivingEntity;
|
||||||
|
import net.minecraft.entity.ai.TargetPredicate;
|
||||||
|
import net.minecraft.entity.ai.goal.TrackTargetGoal;
|
||||||
|
import net.minecraft.entity.mob.MobEntity;
|
||||||
|
import net.minecraft.entity.mob.PathAwareEntity;
|
||||||
|
import net.minecraft.util.math.Box;
|
||||||
|
import net.minecraft.predicate.entity.EntityPredicates;
|
||||||
|
|
||||||
|
import java.util.EnumSet;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class AggroOnHitRevengeGoal extends TrackTargetGoal {
|
||||||
|
|
||||||
|
private static final TargetPredicate VALID_TARGET =
|
||||||
|
TargetPredicate.createAttackable().ignoreVisibility().ignoreDistanceScalingFactor();
|
||||||
|
|
||||||
|
private int lastHurtTime;
|
||||||
|
private int lastAttackTime;
|
||||||
|
|
||||||
|
public AggroOnHitRevengeGoal(PathAwareEntity mob) {
|
||||||
|
super(mob, true);
|
||||||
|
this.setControls(EnumSet.of(Control.TARGET));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canStart() {
|
||||||
|
LivingEntity attacker = this.mob.getAttacker();
|
||||||
|
LivingEntity target = this.mob.getTarget();
|
||||||
|
|
||||||
|
int hurtTime = this.mob.getLastAttackedTime();
|
||||||
|
int attackTime = this.mob.getLastAttackTime();
|
||||||
|
|
||||||
|
// Trigger if mob was hurt
|
||||||
|
if (attacker != null && hurtTime != this.lastHurtTime) {
|
||||||
|
return this.canTrack(attacker, VALID_TARGET);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trigger if mob attacked someone
|
||||||
|
if (target != null && attackTime != this.lastAttackTime) {
|
||||||
|
return this.canTrack(target, VALID_TARGET);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start() {
|
||||||
|
LivingEntity target =
|
||||||
|
this.mob.getAttacker() != null
|
||||||
|
? this.mob.getAttacker()
|
||||||
|
: this.mob.getTarget();
|
||||||
|
|
||||||
|
this.mob.setTarget(target);
|
||||||
|
|
||||||
|
this.lastHurtTime = this.mob.getLastAttackedTime();
|
||||||
|
this.lastAttackTime = this.mob.getLastAttackTime();
|
||||||
|
|
||||||
|
this.callForHelp(target);
|
||||||
|
|
||||||
|
super.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void callForHelp(LivingEntity target) {
|
||||||
|
double range = this.getFollowRange();
|
||||||
|
Box box = this.mob.getBoundingBox().expand(range, 10.0D, range);
|
||||||
|
|
||||||
|
List<? extends MobEntity> allies =
|
||||||
|
this.mob.getWorld().getEntitiesByClass(
|
||||||
|
this.mob.getClass(),
|
||||||
|
box,
|
||||||
|
EntityPredicates.EXCEPT_SPECTATOR
|
||||||
|
);
|
||||||
|
|
||||||
|
for (MobEntity ally : allies) {
|
||||||
|
if (ally != this.mob && ally.getTarget() == null) {
|
||||||
|
ally.setTarget(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
51
src/main/java/dev/tggamesyt/szar/ArrestedEffect.java
Normal file
51
src/main/java/dev/tggamesyt/szar/ArrestedEffect.java
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
package dev.tggamesyt.szar;
|
||||||
|
|
||||||
|
import net.minecraft.entity.LivingEntity;
|
||||||
|
import net.minecraft.entity.attribute.AttributeContainer;
|
||||||
|
import net.minecraft.entity.attribute.EntityAttributes;
|
||||||
|
import net.minecraft.entity.effect.StatusEffect;
|
||||||
|
import net.minecraft.entity.effect.StatusEffectCategory;
|
||||||
|
import net.minecraft.entity.mob.MobEntity;
|
||||||
|
|
||||||
|
public class ArrestedEffect extends StatusEffect {
|
||||||
|
|
||||||
|
private static double originalspeed;
|
||||||
|
public ArrestedEffect() {
|
||||||
|
// BENEFICIAL = false because it's like a debuff
|
||||||
|
super(StatusEffectCategory.HARMFUL, 0xA0A0A0); // gray color
|
||||||
|
}
|
||||||
|
|
||||||
|
@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
|
||||||
|
entity.velocityModified = true;
|
||||||
|
|
||||||
|
// Stop AI for mobs
|
||||||
|
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 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
|
||||||
|
}
|
||||||
|
}
|
||||||
58
src/main/java/dev/tggamesyt/szar/CannabisPatchFeature.java
Normal file
58
src/main/java/dev/tggamesyt/szar/CannabisPatchFeature.java
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
package dev.tggamesyt.szar;
|
||||||
|
|
||||||
|
import com.mojang.serialization.Codec;
|
||||||
|
import dev.tggamesyt.szar.Szar;
|
||||||
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.random.Random;
|
||||||
|
import net.minecraft.world.StructureWorldAccess;
|
||||||
|
import net.minecraft.world.gen.feature.Feature;
|
||||||
|
import net.minecraft.world.gen.feature.util.FeatureContext;
|
||||||
|
|
||||||
|
public class CannabisPatchFeature extends Feature<CannabisPatchFeatureConfig> {
|
||||||
|
|
||||||
|
public CannabisPatchFeature(Codec<CannabisPatchFeatureConfig> codec) {
|
||||||
|
super(codec);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean generate(FeatureContext<CannabisPatchFeatureConfig> context) {
|
||||||
|
StructureWorldAccess world = context.getWorld();
|
||||||
|
BlockPos origin = context.getOrigin();
|
||||||
|
Random random = context.getRandom();
|
||||||
|
|
||||||
|
int cannabisCount = 2 + random.nextInt(5); // 2–6
|
||||||
|
int tallCount = random.nextInt(3); // 0–2
|
||||||
|
|
||||||
|
int placed = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < cannabisCount + tallCount; i++) {
|
||||||
|
BlockPos pos = origin.add(
|
||||||
|
random.nextInt(6) - 3,
|
||||||
|
0,
|
||||||
|
random.nextInt(6) - 3
|
||||||
|
);
|
||||||
|
|
||||||
|
pos = world.getTopPosition(
|
||||||
|
net.minecraft.world.Heightmap.Type.WORLD_SURFACE,
|
||||||
|
pos
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!world.getBlockState(pos.down()).isSolidBlock(world, pos.down())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockState state =
|
||||||
|
tallCount > 0
|
||||||
|
? Szar.TALL_CANNABIS_BLOCK.getDefaultState()
|
||||||
|
: Szar.CANNABIS_BLOCK.getDefaultState();
|
||||||
|
|
||||||
|
if (tallCount > 0) tallCount--;
|
||||||
|
|
||||||
|
world.setBlockState(pos, state, 3);
|
||||||
|
placed++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return placed > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package dev.tggamesyt.szar;
|
||||||
|
|
||||||
|
import com.mojang.serialization.Codec;
|
||||||
|
import net.minecraft.world.gen.feature.FeatureConfig;
|
||||||
|
|
||||||
|
public class CannabisPatchFeatureConfig implements FeatureConfig {
|
||||||
|
|
||||||
|
public static final Codec<CannabisPatchFeatureConfig> CODEC =
|
||||||
|
Codec.unit(new CannabisPatchFeatureConfig());
|
||||||
|
|
||||||
|
}
|
||||||
@@ -20,6 +20,8 @@ import java.util.*;
|
|||||||
|
|
||||||
public class GypsyEntity extends PathAwareEntity {
|
public class GypsyEntity extends PathAwareEntity {
|
||||||
|
|
||||||
|
public static boolean arrestable = false;
|
||||||
|
|
||||||
private final DefaultedList<ItemStack> stolenItems = DefaultedList.of();
|
private final DefaultedList<ItemStack> stolenItems = DefaultedList.of();
|
||||||
private final Set<UUID> stolenFromPlayers = new HashSet<>();
|
private final Set<UUID> stolenFromPlayers = new HashSet<>();
|
||||||
|
|
||||||
@@ -247,6 +249,7 @@ public class GypsyEntity extends PathAwareEntity {
|
|||||||
|
|
||||||
if (mob.distanceTo(target) < 1.3) {
|
if (mob.distanceTo(target) < 1.3) {
|
||||||
mob.trySteal(target);
|
mob.trySteal(target);
|
||||||
|
arrestable = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import java.util.*;
|
|||||||
|
|
||||||
public class IslamTerrorist extends PathAwareEntity {
|
public class IslamTerrorist extends PathAwareEntity {
|
||||||
|
|
||||||
|
public static boolean arrestable = false;
|
||||||
private int BlowUpCooldown = 0;
|
private int BlowUpCooldown = 0;
|
||||||
private int panicTicks = 0;
|
private int panicTicks = 0;
|
||||||
private UUID fleeingFrom = null;
|
private UUID fleeingFrom = null;
|
||||||
@@ -186,6 +187,7 @@ public class IslamTerrorist extends PathAwareEntity {
|
|||||||
|
|
||||||
if (mob.distanceTo(target) < 1.3) {
|
if (mob.distanceTo(target) < 1.3) {
|
||||||
mob.triggerExposion(target);
|
mob.triggerExposion(target);
|
||||||
|
arrestable = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,33 +1,44 @@
|
|||||||
package dev.tggamesyt.szar;
|
package dev.tggamesyt.szar;
|
||||||
|
|
||||||
import dev.tggamesyt.szar.Szar;
|
import dev.tggamesyt.szar.Szar;
|
||||||
|
import dev.tggamesyt.szar.AggroOnHitRevengeGoal;
|
||||||
import net.minecraft.entity.EntityType;
|
import net.minecraft.entity.EntityType;
|
||||||
import net.minecraft.entity.ai.goal.LookAroundGoal;
|
import net.minecraft.entity.LivingEntity;
|
||||||
import net.minecraft.entity.ai.goal.WanderAroundFarGoal;
|
import net.minecraft.entity.ai.goal.*;
|
||||||
import net.minecraft.entity.attribute.DefaultAttributeContainer;
|
import net.minecraft.entity.attribute.DefaultAttributeContainer;
|
||||||
import net.minecraft.entity.attribute.EntityAttributes;
|
import net.minecraft.entity.attribute.EntityAttributes;
|
||||||
import net.minecraft.entity.damage.DamageSource;
|
import net.minecraft.entity.damage.DamageSource;
|
||||||
import net.minecraft.entity.mob.MobEntity;
|
import net.minecraft.entity.mob.MobEntity;
|
||||||
import net.minecraft.entity.mob.PathAwareEntity;
|
import net.minecraft.entity.mob.PathAwareEntity;
|
||||||
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
import net.minecraft.item.Item;
|
import net.minecraft.item.Item;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class NiggerEntity extends PathAwareEntity {
|
public class NiggerEntity extends PathAwareEntity {
|
||||||
|
|
||||||
|
public static boolean arrestable = true;
|
||||||
|
|
||||||
public NiggerEntity(EntityType<? extends PathAwareEntity> type, World world) {
|
public NiggerEntity(EntityType<? extends PathAwareEntity> type, World world) {
|
||||||
super(type, world);
|
super(type, world);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void initGoals() {
|
protected void initGoals() {
|
||||||
this.goalSelector.add(1, new WanderAroundFarGoal(this, 1.0D));
|
this.goalSelector.add(0, new MeleeAttackGoal(this, 1.2D, true));
|
||||||
this.goalSelector.add(2, new LookAroundGoal(this));
|
this.goalSelector.add(2, new WanderAroundFarGoal(this, 1.0D));
|
||||||
|
this.goalSelector.add(3, new LookAroundGoal(this));
|
||||||
|
|
||||||
|
this.targetSelector.add(1, new AggroOnHitRevengeGoal(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static DefaultAttributeContainer.Builder createAttributes() {
|
public static DefaultAttributeContainer.Builder createAttributes() {
|
||||||
return MobEntity.createMobAttributes()
|
return MobEntity.createMobAttributes()
|
||||||
.add(EntityAttributes.GENERIC_MAX_HEALTH, 20.0)
|
.add(EntityAttributes.GENERIC_MAX_HEALTH, 20.0)
|
||||||
.add(EntityAttributes.GENERIC_MOVEMENT_SPEED, 0.25);
|
.add(EntityAttributes.GENERIC_MOVEMENT_SPEED, 0.25)
|
||||||
|
.add(EntityAttributes.GENERIC_ATTACK_DAMAGE, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
120
src/main/java/dev/tggamesyt/szar/PoliceArrestGoal.java
Normal file
120
src/main/java/dev/tggamesyt/szar/PoliceArrestGoal.java
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
package dev.tggamesyt.szar;
|
||||||
|
|
||||||
|
import dev.tggamesyt.szar.Szar;
|
||||||
|
import net.minecraft.entity.LivingEntity;
|
||||||
|
import net.minecraft.entity.ai.TargetPredicate;
|
||||||
|
import net.minecraft.entity.ai.goal.Goal;
|
||||||
|
import net.minecraft.entity.damage.DamageSource;
|
||||||
|
import net.minecraft.entity.mob.MobEntity;
|
||||||
|
import net.minecraft.entity.mob.PathAwareEntity;
|
||||||
|
import net.minecraft.entity.player.PlayerEntity;
|
||||||
|
import net.minecraft.util.Hand;
|
||||||
|
|
||||||
|
import java.util.EnumSet;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class PoliceArrestGoal extends Goal {
|
||||||
|
private final PathAwareEntity police;
|
||||||
|
private LivingEntity target;
|
||||||
|
private static final int ARREST_DURATION = 2400; // 2 minutes in ticks
|
||||||
|
|
||||||
|
public PoliceArrestGoal(PathAwareEntity police) {
|
||||||
|
this.police = police;
|
||||||
|
this.setControls(EnumSet.of(Control.MOVE, Control.TARGET));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canStart() {
|
||||||
|
// 1️⃣ Find nearest arrestable mob
|
||||||
|
List<? extends MobEntity> nearby = police.getWorld().getEntitiesByClass(
|
||||||
|
MobEntity.class,
|
||||||
|
police.getBoundingBox().expand(16),
|
||||||
|
mob -> isArrestable(mob)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!nearby.isEmpty()) {
|
||||||
|
target = nearby.get(0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2️⃣ Find entities attacking villagers or police
|
||||||
|
List<LivingEntity> possibleTargets = police.getWorld().getEntitiesByClass(
|
||||||
|
LivingEntity.class,
|
||||||
|
police.getBoundingBox().expand(16),
|
||||||
|
entity -> isAttackingProtected(entity)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!possibleTargets.isEmpty()) {
|
||||||
|
target = possibleTargets.get(0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start() {
|
||||||
|
police.getNavigation().startMovingTo(target, 1.2D);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
if (target == null || !target.isAlive()) {
|
||||||
|
police.setTarget(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
police.setTarget(target);
|
||||||
|
police.getNavigation().startMovingTo(target, 1.2D);
|
||||||
|
|
||||||
|
double distanceSq = police.squaredDistanceTo(target);
|
||||||
|
if (distanceSq < 4.0D) { // ~2 blocks
|
||||||
|
// Swing the hand
|
||||||
|
police.swingHand(Hand.MAIN_HAND);
|
||||||
|
|
||||||
|
// Deal half a heart using vanilla attack system
|
||||||
|
police.tryAttack(target); // this uses vanilla attack logic and triggers death messages
|
||||||
|
|
||||||
|
// Apply arrested effect
|
||||||
|
target.addStatusEffect(new net.minecraft.entity.effect.StatusEffectInstance(
|
||||||
|
Szar.ARRESTED, ARREST_DURATION, 0
|
||||||
|
));
|
||||||
|
|
||||||
|
// Reset target so Police doesn’t spam the effect
|
||||||
|
target = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldContinue() {
|
||||||
|
return target != null && target.isAlive();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isArrestable(MobEntity mob) {
|
||||||
|
try {
|
||||||
|
return mob.getClass().getField("arrestable").getBoolean(null);
|
||||||
|
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
54
src/main/java/dev/tggamesyt/szar/PoliceEntity.java
Normal file
54
src/main/java/dev/tggamesyt/szar/PoliceEntity.java
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
package dev.tggamesyt.szar;
|
||||||
|
|
||||||
|
import dev.tggamesyt.szar.AggroOnHitRevengeGoal;
|
||||||
|
import dev.tggamesyt.szar.PoliceArrestGoal;
|
||||||
|
import net.minecraft.entity.EntityType;
|
||||||
|
import net.minecraft.entity.SpawnReason;
|
||||||
|
import net.minecraft.entity.ai.goal.LookAroundGoal;
|
||||||
|
import net.minecraft.entity.ai.goal.WanderAroundFarGoal;
|
||||||
|
import net.minecraft.entity.attribute.DefaultAttributeContainer;
|
||||||
|
import net.minecraft.entity.attribute.EntityAttributes;
|
||||||
|
import net.minecraft.entity.damage.DamageSource;
|
||||||
|
import net.minecraft.entity.mob.MobEntity;
|
||||||
|
import net.minecraft.entity.mob.PathAwareEntity;
|
||||||
|
import net.minecraft.item.Items;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.random.Random;
|
||||||
|
import net.minecraft.world.ServerWorldAccess;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
|
public class PoliceEntity extends PathAwareEntity {
|
||||||
|
|
||||||
|
public PoliceEntity(EntityType<? extends PathAwareEntity> type, World world) {
|
||||||
|
super(type, world);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initGoals() {
|
||||||
|
// PoliceArrestGoal replaces normal melee behavior
|
||||||
|
this.goalSelector.add(0, new PoliceArrestGoal(this));
|
||||||
|
|
||||||
|
this.goalSelector.add(2, new WanderAroundFarGoal(this, 1.0D));
|
||||||
|
this.goalSelector.add(3, new LookAroundGoal(this));
|
||||||
|
|
||||||
|
this.targetSelector.add(1, new AggroOnHitRevengeGoal(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DefaultAttributeContainer.Builder createAttributes() {
|
||||||
|
return MobEntity.createMobAttributes()
|
||||||
|
.add(EntityAttributes.GENERIC_MAX_HEALTH, 20.0)
|
||||||
|
.add(EntityAttributes.GENERIC_MOVEMENT_SPEED, 0.25)
|
||||||
|
.add(EntityAttributes.GENERIC_ATTACK_DAMAGE, 1.0); // half heart
|
||||||
|
}
|
||||||
|
public static boolean canSpawnHere(EntityType<PoliceEntity> type, ServerWorldAccess world, SpawnReason reason, BlockPos pos, Random random) {
|
||||||
|
// Only spawn near players
|
||||||
|
return world.getClosestPlayer(pos.getX(), pos.getY(), pos.getZ(), 48, false) != null
|
||||||
|
&& world.getLightLevel(pos) > 8; // optional, spawn in light
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void dropLoot(DamageSource source, boolean causedByPlayer) {
|
||||||
|
this.dropItem(Items.DEBUG_STICK);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,9 +19,11 @@ import net.minecraft.block.*;
|
|||||||
import net.minecraft.entity.EntityDimensions;
|
import net.minecraft.entity.EntityDimensions;
|
||||||
import net.minecraft.entity.EntityType;
|
import net.minecraft.entity.EntityType;
|
||||||
import net.minecraft.entity.SpawnGroup;
|
import net.minecraft.entity.SpawnGroup;
|
||||||
|
import net.minecraft.entity.SpawnRestriction;
|
||||||
import net.minecraft.entity.effect.StatusEffect;
|
import net.minecraft.entity.effect.StatusEffect;
|
||||||
import net.minecraft.item.*;
|
import net.minecraft.item.*;
|
||||||
import net.minecraft.registry.*;
|
import net.minecraft.registry.*;
|
||||||
|
import net.minecraft.registry.tag.BiomeTags;
|
||||||
import net.minecraft.server.network.ServerPlayerEntity;
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
import net.minecraft.sound.SoundEvents;
|
import net.minecraft.sound.SoundEvents;
|
||||||
import net.minecraft.text.Text;
|
import net.minecraft.text.Text;
|
||||||
@@ -30,8 +32,10 @@ import net.minecraft.util.Identifier;
|
|||||||
import net.minecraft.util.collection.DataPool;
|
import net.minecraft.util.collection.DataPool;
|
||||||
import net.minecraft.village.TradeOffer;
|
import net.minecraft.village.TradeOffer;
|
||||||
import net.minecraft.village.VillagerProfession;
|
import net.minecraft.village.VillagerProfession;
|
||||||
|
import net.minecraft.world.Heightmap;
|
||||||
import net.minecraft.world.biome.Biome;
|
import net.minecraft.world.biome.Biome;
|
||||||
import net.minecraft.world.biome.BiomeKeys;
|
import net.minecraft.world.biome.BiomeKeys;
|
||||||
|
import net.minecraft.world.gen.GenerationStep;
|
||||||
import net.minecraft.world.gen.feature.*;
|
import net.minecraft.world.gen.feature.*;
|
||||||
import net.minecraft.world.gen.placementmodifier.BiomePlacementModifier;
|
import net.minecraft.world.gen.placementmodifier.BiomePlacementModifier;
|
||||||
import net.minecraft.world.gen.placementmodifier.CountPlacementModifier;
|
import net.minecraft.world.gen.placementmodifier.CountPlacementModifier;
|
||||||
@@ -88,6 +92,15 @@ public class Szar implements ModInitializer {
|
|||||||
.dimensions(EntityDimensions.fixed(0.6F, 1.8F)) // player-sized
|
.dimensions(EntityDimensions.fixed(0.6F, 1.8F)) // player-sized
|
||||||
.build()
|
.build()
|
||||||
);
|
);
|
||||||
|
public static final EntityType<PoliceEntity> PoliceEntityType =
|
||||||
|
Registry.register(
|
||||||
|
Registries.ENTITY_TYPE,
|
||||||
|
new Identifier(MOD_ID, "police"),
|
||||||
|
FabricEntityTypeBuilder
|
||||||
|
.create(SpawnGroup.CREATURE, PoliceEntity::new)
|
||||||
|
.dimensions(EntityDimensions.fixed(0.6F, 1.8F)) // player-sized
|
||||||
|
.build()
|
||||||
|
);
|
||||||
public static final EntityType<GypsyEntity> GYPSY_ENTITY_TYPE =
|
public static final EntityType<GypsyEntity> GYPSY_ENTITY_TYPE =
|
||||||
Registry.register(
|
Registry.register(
|
||||||
Registries.ENTITY_TYPE,
|
Registries.ENTITY_TYPE,
|
||||||
@@ -119,6 +132,7 @@ public class Szar implements ModInitializer {
|
|||||||
entries.add(Szar.NIGGER_SPAWNEGG);
|
entries.add(Szar.NIGGER_SPAWNEGG);
|
||||||
entries.add(Szar.GYPSY_SPAWNEGG);
|
entries.add(Szar.GYPSY_SPAWNEGG);
|
||||||
entries.add(Szar.TERRORIST_SPAWNEGG);
|
entries.add(Szar.TERRORIST_SPAWNEGG);
|
||||||
|
entries.add(Szar.POLICE_SPAWNEGG);
|
||||||
entries.add(Szar.CANNABIS_ITEM);
|
entries.add(Szar.CANNABIS_ITEM);
|
||||||
entries.add(Szar.WEED_ITEM);
|
entries.add(Szar.WEED_ITEM);
|
||||||
entries.add(Szar.WEED_JOINT_ITEM);
|
entries.add(Szar.WEED_JOINT_ITEM);
|
||||||
@@ -277,6 +291,10 @@ public class Szar implements ModInitializer {
|
|||||||
NiggerEntityType,
|
NiggerEntityType,
|
||||||
NiggerEntity.createAttributes()
|
NiggerEntity.createAttributes()
|
||||||
);
|
);
|
||||||
|
FabricDefaultAttributeRegistry.register(
|
||||||
|
PoliceEntityType,
|
||||||
|
NiggerEntity.createAttributes()
|
||||||
|
);
|
||||||
FabricDefaultAttributeRegistry.register(
|
FabricDefaultAttributeRegistry.register(
|
||||||
GYPSY_ENTITY_TYPE,
|
GYPSY_ENTITY_TYPE,
|
||||||
GypsyEntity.createAttributes()
|
GypsyEntity.createAttributes()
|
||||||
@@ -285,6 +303,12 @@ public class Szar implements ModInitializer {
|
|||||||
TERRORIST_ENTITY_TYPE,
|
TERRORIST_ENTITY_TYPE,
|
||||||
IslamTerrorist.createAttributes()
|
IslamTerrorist.createAttributes()
|
||||||
);
|
);
|
||||||
|
SpawnRestriction.register(
|
||||||
|
Szar.PoliceEntityType,
|
||||||
|
SpawnRestriction.Location.ON_GROUND, // spawn on solid blocks
|
||||||
|
Heightmap.Type.MOTION_BLOCKING_NO_LEAVES, // avoids leaves
|
||||||
|
PoliceEntity::canSpawnHere // your custom condition
|
||||||
|
);
|
||||||
ServerTickEvents.END_SERVER_TICK.register(PlayerValueTimer::onServerTick);
|
ServerTickEvents.END_SERVER_TICK.register(PlayerValueTimer::onServerTick);
|
||||||
BiomeModifications.addSpawn(
|
BiomeModifications.addSpawn(
|
||||||
BiomeSelectors.includeByKey(
|
BiomeSelectors.includeByKey(
|
||||||
@@ -323,27 +347,21 @@ public class Szar implements ModInitializer {
|
|||||||
1, // min group size
|
1, // min group size
|
||||||
5 // max group size
|
5 // max group size
|
||||||
);
|
);
|
||||||
}
|
BiomeModifications.addFeature(
|
||||||
BlockStateProvider provider =
|
BiomeSelectors.tag(BiomeTags.IS_JUNGLE),
|
||||||
new WeightedBlockStateProvider(
|
GenerationStep.Feature.VEGETAL_DECORATION,
|
||||||
DataPool.<BlockState>builder()
|
RegistryKey.of(
|
||||||
.add(Szar.CANNABIS_BLOCK.getDefaultState(), 8)
|
RegistryKeys.PLACED_FEATURE,
|
||||||
.add(Szar.TALL_CANNABIS_BLOCK.getDefaultState(), 1)
|
new Identifier("szar", "cannabis_patch")
|
||||||
.build()
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
ConfiguredFeature<RandomPatchFeatureConfig, ?> patch =
|
}
|
||||||
new ConfiguredFeature<>(
|
public static final Feature<CannabisPatchFeatureConfig> CANNABIS_PATCH =
|
||||||
Feature.RANDOM_PATCH,
|
Registry.register(
|
||||||
new RandomPatchFeatureConfig(
|
Registries.FEATURE,
|
||||||
32,
|
new Identifier("szar", "cannabis_patch"),
|
||||||
6,
|
new CannabisPatchFeature(CannabisPatchFeatureConfig.CODEC)
|
||||||
3,
|
|
||||||
PlacedFeatures.createEntry(
|
|
||||||
Feature.SIMPLE_BLOCK,
|
|
||||||
new SimpleBlockFeatureConfig(provider)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
public static final Map<UUID, Integer> PLAYER_JOINT_LEVEL = new HashMap<>();
|
public static final Map<UUID, Integer> PLAYER_JOINT_LEVEL = new HashMap<>();
|
||||||
public static final Map<UUID, Boolean> PLAYER_ADDICTION_LEVEL = new HashMap<>();
|
public static final Map<UUID, Boolean> PLAYER_ADDICTION_LEVEL = new HashMap<>();
|
||||||
@@ -352,6 +370,7 @@ public class Szar implements ModInitializer {
|
|||||||
new Identifier(MOD_ID, "drog"),
|
new Identifier(MOD_ID, "drog"),
|
||||||
new DrogEffect()
|
new DrogEffect()
|
||||||
);
|
);
|
||||||
|
public static final StatusEffect ARRESTED = Registry.register(Registries.STATUS_EFFECT, new Identifier("szar", "arrested"), new ArrestedEffect());
|
||||||
public static final Item CHEMICAL_WORKBENCH_ITEM = Registry.register(
|
public static final Item CHEMICAL_WORKBENCH_ITEM = Registry.register(
|
||||||
Registries.ITEM,
|
Registries.ITEM,
|
||||||
new Identifier(MOD_ID, "chemical_workbench"),
|
new Identifier(MOD_ID, "chemical_workbench"),
|
||||||
@@ -511,6 +530,16 @@ public class Szar implements ModInitializer {
|
|||||||
new Item.Settings()
|
new Item.Settings()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
public static final Item POLICE_SPAWNEGG = Registry.register(
|
||||||
|
Registries.ITEM,
|
||||||
|
new Identifier(MOD_ID, "police_spawn_egg"),
|
||||||
|
new SpawnEggItem(
|
||||||
|
PoliceEntityType,
|
||||||
|
0x0000FF,
|
||||||
|
0xFF0000,
|
||||||
|
new Item.Settings()
|
||||||
|
)
|
||||||
|
);
|
||||||
public static final Item GYPSY_SPAWNEGG = Registry.register(
|
public static final Item GYPSY_SPAWNEGG = Registry.register(
|
||||||
Registries.ITEM,
|
Registries.ITEM,
|
||||||
new Identifier(MOD_ID, "gypsy_spawn_egg"),
|
new Identifier(MOD_ID, "gypsy_spawn_egg"),
|
||||||
|
|||||||
@@ -26,5 +26,8 @@
|
|||||||
"block.szar.chemical_workbench": "Chemical Workbench",
|
"block.szar.chemical_workbench": "Chemical Workbench",
|
||||||
"entity.minecraft.villager.drog_dealer": "Drog dealer",
|
"entity.minecraft.villager.drog_dealer": "Drog dealer",
|
||||||
"entity.szar.islam_terrorist": "Islam Terrorist",
|
"entity.szar.islam_terrorist": "Islam Terrorist",
|
||||||
"item.szar.terrorist_spawn_egg": "Islam Terrorist Spawn Egg"
|
"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"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,28 +1,12 @@
|
|||||||
{
|
{
|
||||||
"format_version": "1.9.0",
|
"parent": "block/cube",
|
||||||
"credit": "Made with Blockbench",
|
|
||||||
"texture_size": [64, 64],
|
|
||||||
"textures": {
|
"textures": {
|
||||||
"0": "szar:block/chemical_1",
|
"north": "szar:block/chemical_1",
|
||||||
"1": "szar:block/chemical_2",
|
"east": "szar:block/chemical_2",
|
||||||
"2": "szar:block/chemical_3",
|
"south": "szar:block/chemical_3",
|
||||||
"3": "szar:block/chemical_4",
|
"west": "szar:block/chemical_4",
|
||||||
"4": "szar:block/chemical_bottom",
|
"up": "szar:block/chemical_top",
|
||||||
"5": "szar:block/chemical_top",
|
"down": "szar:block/chemical_bottom",
|
||||||
"particle": "szar:block/chemical_1"
|
"particle": "szar:block/chemical_1"
|
||||||
},
|
}
|
||||||
"elements": [
|
}
|
||||||
{
|
|
||||||
"from": [0, 0, 0],
|
|
||||||
"to": [16, 16, 16],
|
|
||||||
"faces": {
|
|
||||||
"north": {"uv": [0, 0, 16, 16], "texture": "#3"},
|
|
||||||
"east": {"uv": [0, 0, 16, 16], "texture": "#2"},
|
|
||||||
"south": {"uv": [0, 0, 16, 16], "texture": "#1"},
|
|
||||||
"west": {"uv": [0, 0, 16, 16], "texture": "#0"},
|
|
||||||
"up": {"uv": [15.73333, 16, 0, 0], "texture": "#5"},
|
|
||||||
"down": {"uv": [16, 0, 0, 16], "texture": "#4"}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"parent": "minecraft:item/template_spawn_egg"
|
||||||
|
}
|
||||||
BIN
src/main/resources/assets/szar/textures/entity/police-man.png
Normal file
BIN
src/main/resources/assets/szar/textures/entity/police-man.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
BIN
src/main/resources/assets/szar/textures/mob_effect/arrested.png
Normal file
BIN
src/main/resources/assets/szar/textures/mob_effect/arrested.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 267 B |
23
src/main/resources/data/szar/recipes/chemical_workbench.json
Normal file
23
src/main/resources/data/szar/recipes/chemical_workbench.json
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"type": "minecraft:crafting_shaped",
|
||||||
|
"pattern": [
|
||||||
|
"SSS",
|
||||||
|
"PCP",
|
||||||
|
"PPP"
|
||||||
|
],
|
||||||
|
"key": {
|
||||||
|
"S": {
|
||||||
|
"item": "minecraft:smooth_stone"
|
||||||
|
},
|
||||||
|
"P": {
|
||||||
|
"tag": "minecraft:planks"
|
||||||
|
},
|
||||||
|
"C": {
|
||||||
|
"item": "szar:cannabis"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"result": {
|
||||||
|
"item": "szar:chemical_workbench",
|
||||||
|
"count": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"type": "szar:cannabis_patch",
|
||||||
|
"config": {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"feature": "szar:cannabis_patch",
|
||||||
|
"placement": [
|
||||||
|
{
|
||||||
|
"type": "minecraft:count",
|
||||||
|
"count": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "minecraft:in_square"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "minecraft:heightmap",
|
||||||
|
"heightmap": "WORLD_SURFACE_WG"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "minecraft:biome"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user