diff --git a/src/main/java/carpet/mixins/PointOfInterest_scarpetMixin.java b/src/main/java/carpet/mixins/PointOfInterest_scarpetMixin.java index 6956788b..02780344 100644 --- a/src/main/java/carpet/mixins/PointOfInterest_scarpetMixin.java +++ b/src/main/java/carpet/mixins/PointOfInterest_scarpetMixin.java @@ -3,10 +3,14 @@ package carpet.mixins; import net.minecraft.village.PointOfInterest; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; @Mixin(PointOfInterest.class) public interface PointOfInterest_scarpetMixin { @Accessor("freeTickets") int getFreeTickets(); + + @Invoker + boolean callReserveTicket(); } diff --git a/src/main/java/carpet/script/CarpetExpression.java b/src/main/java/carpet/script/CarpetExpression.java index 6bd82b67..e7e24fc9 100644 --- a/src/main/java/carpet/script/CarpetExpression.java +++ b/src/main/java/carpet/script/CarpetExpression.java @@ -497,8 +497,16 @@ public class CarpetExpression * place_item('piston,x,y,z,'down') // places a piston facing down * place_item('carrot',x,y,z) // attempts to plant a carrot plant. Returns true if could place carrots at that position. * - *

biome(pos)

- *

returns biome at that block position.

+ *

set_poi(pos, type, occupancy?)

+ *

Sets a Point of Interest (POI) of a specified type with optional custom occupancy. By default new POIs are not + * occupied. If type is null, POI at position is removed. In any case, previous POI is also removed. + * Available POI types are:

+ * + *

Interestingly, unemployed, and nitwit are not used in the game, meaning, they could be used + * as permanent spatial markers for scarpet apps. meeting is the only one with increased max occupancy of 6.

*

set_biome(pos, biome_name)

*

changes biome at that block position.

*

update(pos)

@@ -554,6 +562,22 @@ public class CarpetExpression *
      *     block_data(x,y,z) => '{TransferCooldown:0,x:450,y:68, ... }'
      * 
+ *

poi(pos), poi(pos, radius), poi(pos, radius, status)

+ *

Queries a POI (Point of Interest) at a given position, returning null if none is found, or tuple of + * poi type and its occupancy load. With optional radius and status, returns a list of POIs + * around pos within a given radius. If status is specified (either 'available', + * or 'occupied') returns only POIs with that status. The return format is again, poi type, occupancy load, and extra tripple of + * coordinates.

+ *

Querying for POIs using the radius is intended use of POI mechanics and ability of accessing individual POIs via + * poi(pos) in only provided for completness.

+ *
+     *     poi(x,y,z) => null  // nothing set at position
+     *     poi(x,y,z) => ['meeting',3]  // its a bell-type meeting point occupied by 3 villagers
+     *     poi(x,y,z,5) => []  // nothing around
+     *     poi(x,y,z,5) => [['nether_portal',0,[7,8,9]],['nether_portal',0,[7,9,9]]] // two portal blocks in the range
+     * 
+ *

biome(pos)

+ *

returns biome at that block position.

*

solid(pos)

*

Boolean function, true if the block is solid

*

air(pos)

@@ -794,12 +818,12 @@ public class CarpetExpression }); // poi_get(pos, radius?, type?, occupation?) - this.expr.addLazyFunction("poi_get", -1, (c, t, lv) -> + this.expr.addLazyFunction("poi", -1, (c, t, lv) -> { CarpetContext cc = (CarpetContext) c; if (lv.size() == 0) { - throw new InternalExpressionException("'poi_get' requires at least one parameter"); + throw new InternalExpressionException("'poi' requires at least one parameter"); } BlockValue.LocatorResult locator = BlockValue.fromParams(cc, lv, 0, true); BlockPos pos = locator.block.getPos(); @@ -860,17 +884,17 @@ public class CarpetExpression }); //poi_set(pos, null) poi_set(pos, type, occupied?, - this.expr.addLazyFunction("poi_set", -1, (c, t, lv) -> + this.expr.addLazyFunction("set_poi", -1, (c, t, lv) -> { CarpetContext cc = (CarpetContext) c; if (lv.size() == 0) { - throw new InternalExpressionException("'poi_get' requires at least one parameter"); + throw new InternalExpressionException("'set_poi' requires at least one parameter"); } BlockValue.LocatorResult locator = BlockValue.fromParams(cc, lv, 0, true); BlockPos pos = locator.block.getPos(); if (lv.size() < locator.offset) - throw new InternalExpressionException("'poi_set' requires the new poi type or null, after position argument"); + throw new InternalExpressionException("'set_poi' requires the new poi type or null, after position argument"); Value poi = lv.get(locator.offset+0).evalValue(c); PointOfInterestStorage store = cc.s.getWorld().getPointOfInterestStorage(); if (poi == Value.NULL) @@ -882,7 +906,7 @@ public class CarpetExpression PointOfInterestType type = Registry.POINT_OF_INTEREST_TYPE.get(new Identifier(poiTypeString)); // solving lack of null with defaulted registries if (type == PointOfInterestType.UNEMPLOYED && !"unemployed".equals(poiTypeString)) - throw new InternalExpressionException("unknown POI type: "+poiTypeString); + throw new InternalExpressionException("Unknown POI type: "+poiTypeString); int occupancy = 0; if (locator.offset + 1 < lv.size()) { @@ -893,7 +917,15 @@ public class CarpetExpression if (store.getType(pos).isPresent()) store.remove(pos); store.add(pos, type); // setting occupancy for a - for (int i = 0; i < occupancy; i++) store.getPosition((p) -> p == type, p -> true, pos, 0); + // again - don't want to mix in unnecessarily - peeps not gonna use it that often so not worries about it. + if (occupancy > 0) + { + int finalO = occupancy; + store.get((tt) -> tt==type, pos, 1, PointOfInterestStorage.OccupationStatus.ANY + ).filter(p -> p.getPos().equals(pos)).findFirst().ifPresent(p -> { + for (int i=0; i < finalO; i++) ((PointOfInterest_scarpetMixin)p).callReserveTicket(); + }); + } return LazyValue.NULL; });