diff --git a/gm4/modeldata_registry.json b/gm4/modeldata_registry.json index 3d0cd6842e..376bb5def0 100644 --- a/gm4/modeldata_registry.json +++ b/gm4/modeldata_registry.json @@ -527,6 +527,7 @@ "fishing_rod": { "gm4_end_fishing:gui/advancement/end_fishing": 1, "gm4_end_fishing:guidebook_icon/end_fishing": 2, + "gm4_reeling_rods:guidebook_icon/reeling_rods": 3, "gm4_metallurgy:shamir/hypexperia": 110, "gm4_animi_shamir:shamir/animi": 124 }, diff --git a/gm4/utils.py b/gm4/utils.py index b25526c47b..8b0c9ac0cd 100644 --- a/gm4/utils.py +++ b/gm4/utils.py @@ -27,177 +27,177 @@ def run(cmd: list[str]|str) -> str: - """Run a shell command and return the stdout.""" - return subprocess.run(cmd, capture_output=True, encoding="utf8", shell=isinstance(cmd, str)).stdout.strip() + """Run a shell command and return the stdout.""" + return subprocess.run(cmd, capture_output=True, encoding="utf8", shell=isinstance(cmd, str)).stdout.strip() def X_int(val: str) -> int | None: - """Int casting that accepts character 'X' and returns None""" - return None if val.lower() == 'x' else int(val) + """Int casting that accepts character 'X' and returns None""" + return None if val.lower() == 'x' else int(val) def add_namespace(val: str, namespace: str) -> str: - """Adds a namsepace prefix to a string, if one does not already exist""" - if ":" not in val: - return f"{namespace}:{val}" - return val + """Adds a namsepace prefix to a string, if one does not already exist""" + if ":" not in val: + return f"{namespace}:{val}" + return val @dataclass @total_ordering class Version(): - """Class with methods useful for semver versions in the gm4 build pipeline""" - major: int|None - minor: int|None - patch: int|None - - def __init__(self, input: str): - self.major, self.minor, self.patch = map(X_int, input.split(".")) - - def __str__(self): - if type(None) in map(type, [self.major, self.minor, self.patch]): - warnings.warn(f"Version number was printed to string when one or more fields are not set") - return f"{self.major}.{self.minor}.{self.patch}" - - def int_rep(self) -> int: - """returns integer representation of version, for use in datapack scoreboards""" - if type(None) in map(type, [self.major, self.minor, self.patch]): - raise TypeError(f"Version number cannot be converted to integer when one or more fields are not set") - return 100_000*self.major + 1_000*self.minor + self.patch # type: ignore - - def __eq__(self, other: object) -> bool: - if other is None: - return False - elif isinstance(other, Version): - return self.major==other.major and self.minor==other.minor and self.patch==other.patch - raise TypeError - - def __lt__(self, other: object) -> bool: - if isinstance(other, Version): - if self.major is None or self.minor is None or self.patch is None \ - or other.major is None or other.minor is None or other.patch is None: - raise TypeError(f"Version numbers cannot be compared when one or more fields are not set") - if self.major < other.major: - return True - elif self.major == other.major: - if self.minor < other.minor: - return True - elif self.minor == other.minor: - if self.patch < other.patch: - return True - return False - raise TypeError - - def replace(self, **changes: Any): - params = asdict(self) | changes - params = {k:(v if v is not None else 'X') for k,v in params.items()} - return Version(f"{params['major']}.{params['minor']}.{params['patch']}") - + """Class with methods useful for semver versions in the gm4 build pipeline""" + major: int|None + minor: int|None + patch: int|None + + def __init__(self, input: str): + self.major, self.minor, self.patch = map(X_int, input.split(".")) + + def __str__(self): + if type(None) in map(type, [self.major, self.minor, self.patch]): + warnings.warn(f"Version number was printed to string when one or more fields are not set") + return f"{self.major}.{self.minor}.{self.patch}" + + def int_rep(self) -> int: + """returns integer representation of version, for use in datapack scoreboards""" + if type(None) in map(type, [self.major, self.minor, self.patch]): + raise TypeError(f"Version number cannot be converted to integer when one or more fields are not set") + return 100_000*self.major + 1_000*self.minor + self.patch # type: ignore + + def __eq__(self, other: object) -> bool: + if other is None: + return False + elif isinstance(other, Version): + return self.major==other.major and self.minor==other.minor and self.patch==other.patch + raise TypeError + + def __lt__(self, other: object) -> bool: + if isinstance(other, Version): + if self.major is None or self.minor is None or self.patch is None \ + or other.major is None or other.minor is None or other.patch is None: + raise TypeError(f"Version numbers cannot be compared when one or more fields are not set") + if self.major < other.major: + return True + elif self.major == other.major: + if self.minor < other.minor: + return True + elif self.minor == other.minor: + if self.patch < other.patch: + return True + return False + raise TypeError + + def replace(self, **changes: Any): + params = asdict(self) | changes + params = {k:(v if v is not None else 'X') for k,v in params.items()} + return Version(f"{params['major']}.{params['minor']}.{params['patch']}") + def nested_get(d: dict[str, Any], key: str) -> list[Any]: - """Recursively traverses a string-keyed dict (like minecraft json files) for the specified key, returning all that exist - returns empty list and throws no errors if key does not exist""" - ret_list: list[Any] = [] - for k, v in d.items(): - if k == key: - ret_list.append(d[k]) - elif isinstance(v, dict): - ret_list.extend(nested_get(d[k], key)) - elif isinstance(v, list): - for elem in d[k]: - if isinstance(elem, dict): - ret_list.extend(nested_get(elem, key)) #type: ignore ; NBT is hard to type due to its nested nature - return ret_list + """Recursively traverses a string-keyed dict (like minecraft json files) for the specified key, returning all that exist + returns empty list and throws no errors if key does not exist""" + ret_list: list[Any] = [] + for k, v in d.items(): + if k == key: + ret_list.append(d[k]) + elif isinstance(v, dict): + ret_list.extend(nested_get(d[k], key)) + elif isinstance(v, list): + for elem in d[k]: + if isinstance(elem, dict): + ret_list.extend(nested_get(elem, key)) #type: ignore ; NBT is hard to type due to its nested nature + return ret_list class NoneAttribute(): - """Object which returns None for any arbitrary attribute access. Used for default members""" - def __getattribute__(self, __name: str) -> None: - return None + """Object which returns None for any arbitrary attribute access. Used for default members""" + def __getattribute__(self, __name: str) -> None: + return None class MapOption(GenericModel, Generic[T]): - """A union-like type of dict and list, supporting common methods for both - - Written for use in resource_pack plugin's texture lists""" - __root__: list[T]|dict[str,T] = [] - - def entries(self) -> list[T]: - if isinstance(self.__root__, list): - return self.__root__ - return list(self.__root__.values()) - - def __getitem__(self, key: str|int) -> T: - if isinstance(key, int): - return self.entries()[key] - if isinstance(self.__root__, list): - raise KeyError(f"MapOption has no mapping data keys. Could not retrieve {key}") - return self.__root__[key] - - def items(self): - if isinstance(self.__root__, dict): - return self.__root__.items() - raise KeyError("MapOption has no mapping data keys. Can not retrieve items()") - - @validator("__root__", pre=True) # type: ignore ; v1 validator behaves strangely with type checking - def validate_root(cls, value: list[T]|dict[str,T]|T) -> list[T]|dict[str,T]: - if value is None: - value = [] - elif isinstance(value, ListOption): - value = value.entries() - if not isinstance(value, (list, tuple, dict)): # single element - value = [value] - return value # type: ignore + """A union-like type of dict and list, supporting common methods for both + - Written for use in resource_pack plugin's texture lists""" + __root__: list[T]|dict[str,T] = [] + + def entries(self) -> list[T]: + if isinstance(self.__root__, list): + return self.__root__ + return list(self.__root__.values()) + + def __getitem__(self, key: str|int) -> T: + if isinstance(key, int): + return self.entries()[key] + if isinstance(self.__root__, list): + raise KeyError(f"MapOption has no mapping data keys. Could not retrieve {key}") + return self.__root__[key] + + def items(self): + if isinstance(self.__root__, dict): + return self.__root__.items() + raise KeyError("MapOption has no mapping data keys. Can not retrieve items()") + + @validator("__root__", pre=True) # type: ignore ; v1 validator behaves strangely with type checking + def validate_root(cls, value: list[T]|dict[str,T]|T) -> list[T]|dict[str,T]: + if value is None: + value = [] + elif isinstance(value, ListOption): + value = value.entries() + if not isinstance(value, (list, tuple, dict)): # single element + value = [value] + return value # type: ignore # TODO 1.20.5: might not need this anymore class InvokeOnJsonNbt: - """Extendable mixin to run MutatingReducer's rules on nbt within advancements, loot_tables ect...""" - def __init__(self, ctx: Context): - self.ctx = ctx - raise RuntimeError("InvokeOnJsonNbt should not be directly instantiated. It is a mixin for MutatingReducers and should be interited instead") - - @contextmanager - def use_diagnostics(self, diagnostics: DiagnosticCollection) -> Iterator[None]: - """Class is mixed into MutatingReducer, who does have this method. Passed here for type completion""" - raise NotImplementedError() - - def invoke(self, node: AbstractNode, *args: Any, **kwargs: Any) -> Any: - """Class is mixed into MutatingReducer, who does have this method. Passed here for type completion""" - raise NotImplementedError() - - - @rule(AstJsonObjectEntry, key=AstJsonObjectKey(value='nbt')) - @rule(AstJsonObjectEntry, key=AstJsonObjectKey(value='tag')) - def process_nbt_in_json(self, node: AstJsonObjectEntry): - mc = self.ctx.inject(Mecha) - if isinstance(mc.database.current, (Advancement, LootTable, ItemModifier, Predicate)): - if isinstance(node.value, AstJsonValue) and isinstance(node.value.value, str) \ - and node.value.value.startswith("{") and node.value.value.endswith("}"): # excludes location check block/fluid tags - easier than making rule that checks for 'set_nbt' functions on the same json level - try: - nbt = mc.parse(node.value.value.replace("\n", "\\\\n"), type=AstNbtCompound) - except DiagnosticError as exc: - # if parsing failed, give pretty traceback - for d in exc.diagnostics.exceptions: - yield set_location(replace(d, file=mc.database.current), node.value) - return replace(node, value="{}") - - ## TEMP - trial on yielding children rather than using invoke - # with self.use_diagnostics(captured_diagnostics:=DiagnosticCollection()): - # nbt = yield nbt # run all rules on child-node - # print(captured_diagnostics.exceptions) - # print(nbt) - # new_node = replace(node, value=AstJsonValue(value=mc.serialize(nbt, type=AstNbtCompound))) - - with self.use_diagnostics(captured_diagnostics:=DiagnosticCollection()): - processed_nbt = mc.serialize(self.invoke(nbt, type=AstNbtCompound)) - for exc in captured_diagnostics.exceptions: - yield propagate_location(exc, node.value) # set error location to nbt key-value that caused the problem and pass diagnostic back to mecha - - new_node = replace(node, value=AstJsonValue(value=processed_nbt)) - if new_node != node: - return new_node - - return node + """Extendable mixin to run MutatingReducer's rules on nbt within advancements, loot_tables ect...""" + def __init__(self, ctx: Context): + self.ctx = ctx + raise RuntimeError("InvokeOnJsonNbt should not be directly instantiated. It is a mixin for MutatingReducers and should be interited instead") + + @contextmanager + def use_diagnostics(self, diagnostics: DiagnosticCollection) -> Iterator[None]: + """Class is mixed into MutatingReducer, who does have this method. Passed here for type completion""" + raise NotImplementedError() + + def invoke(self, node: AbstractNode, *args: Any, **kwargs: Any) -> Any: + """Class is mixed into MutatingReducer, who does have this method. Passed here for type completion""" + raise NotImplementedError() + + + @rule(AstJsonObjectEntry, key=AstJsonObjectKey(value='nbt')) + @rule(AstJsonObjectEntry, key=AstJsonObjectKey(value='tag')) + def process_nbt_in_json(self, node: AstJsonObjectEntry): + mc = self.ctx.inject(Mecha) + if isinstance(mc.database.current, (Advancement, LootTable, ItemModifier, Predicate)): + if isinstance(node.value, AstJsonValue) and isinstance(node.value.value, str) \ + and node.value.value.startswith("{") and node.value.value.endswith("}"): # excludes location check block/fluid tags - easier than making rule that checks for 'set_nbt' functions on the same json level + try: + nbt = mc.parse(node.value.value.replace("\n", "\\\\n"), type=AstNbtCompound) + except DiagnosticError as exc: + # if parsing failed, give pretty traceback + for d in exc.diagnostics.exceptions: + yield set_location(replace(d, file=mc.database.current), node.value) + return replace(node, value="{}") + + ## TEMP - trial on yielding children rather than using invoke + # with self.use_diagnostics(captured_diagnostics:=DiagnosticCollection()): + # nbt = yield nbt # run all rules on child-node + # print(captured_diagnostics.exceptions) + # print(nbt) + # new_node = replace(node, value=AstJsonValue(value=mc.serialize(nbt, type=AstNbtCompound))) + + with self.use_diagnostics(captured_diagnostics:=DiagnosticCollection()): + processed_nbt = mc.serialize(self.invoke(nbt, type=AstNbtCompound)) + for exc in captured_diagnostics.exceptions: + yield propagate_location(exc, node.value) # set error location to nbt key-value that caused the problem and pass diagnostic back to mecha + + new_node = replace(node, value=AstJsonValue(value=processed_nbt)) + if new_node != node: + return new_node + + return node def propagate_location(obj: T, parent_location_obj: Any) -> T: - """a set_location like function propagating diagnostic information for manually invoked rules""" - return set_location(obj, - SourceLocation(pos=parent_location_obj.location.pos+obj.location.pos, lineno=parent_location_obj.location.lineno, colno=parent_location_obj.location.colno+obj.location.colno), # type: ignore - SourceLocation(pos=parent_location_obj.location.pos+obj.end_location.pos, lineno=parent_location_obj.location.lineno, colno=parent_location_obj.location.colno+obj.end_location.colno) # type: ignore - ) + """a set_location like function propagating diagnostic information for manually invoked rules""" + return set_location(obj, + SourceLocation(pos=parent_location_obj.location.pos+obj.location.pos, lineno=parent_location_obj.location.lineno, colno=parent_location_obj.location.colno+obj.location.colno), # type: ignore + SourceLocation(pos=parent_location_obj.location.pos+obj.end_location.pos, lineno=parent_location_obj.location.lineno, colno=parent_location_obj.location.colno+obj.end_location.colno) # type: ignore + ) # CSV READING UTILS class CSVCell(str): @@ -214,7 +214,7 @@ def as_integer(self) -> int: Interprets the string contained in this CSVCell as an integer. Supported formats are: - base 10 integers (no prefix) - - prefixed hex color codes (# prefix and 6 digits) + - prefixed hex color codes (# prefix and 6 digits) - prefixed hex, octal, or binary (0x, 0o, or 0b and some amount of digits) - bool (True or False, case insensitive) Returns a integer representation of the value. @@ -232,7 +232,32 @@ def as_integer(self) -> int: if self.casefold() == 'false': return 0 return int(self) # default case, interpret as base 10 - + + def as_bool(self) -> bool: + """ + Interprets the string contained in this CSVCell as a boolean. + Returns `True` if the cell's content is: + - `TRUE` in any capitalization + - A positive number greater or equal to `1` + Returns `False` if the cell's content is: + - `FALSE` in any capitalization + - `0` or any number that truncates to zero + Raises a `ValueError` in all other cases. + """ + match self.casefold(): + case 'true': # TRUE / FALSE keywords + return True + case 'false': + return False + case other: + try: # test if contents can be parsed as a number + other = int(other) + if 0 <= other: # only positive numbers can be interpreted as a boolean + return 1 <= other + except ValueError: + pass # not a number + raise ValueError(f"Couldn't interpret CSVCell contents ('{self}') as a boolean.") + def to_color_code(self, encoding: str) -> 'CSVCell': """ Interprets the string contained in this CSVCell as a color code using the given encoding and returns a new CSVCell with that interpretation as its content. @@ -271,7 +296,7 @@ def __init__(self, column_names: List[str] | None = None, data: List[CSVCell] | f"Could not build CSVRow from supplied column names and data; Number of supplied column names ({len(column_names)}) does not match number of supplied data entries ({len(data)}).") self._data = {column_names[column_index] - : value for column_index, value in enumerate(data)} + : value for column_index, value in enumerate(data)} def __bool__(self): """ @@ -291,7 +316,7 @@ def __repr__(self) -> str: def get(self, key: str, default: str | Any) -> CSVCell: """ - Returns the value corrosponding to the key if it exists and is not the empty string. + Returns the value corresponding to the key if it exists and is not the empty string. Else returns the provided default. The provided default is cast to a string internally. """ value = self._data.get(key, CSVCell(default)) @@ -331,6 +356,7 @@ def __init__(self, column_names: List[str], rows: List[List[CSVCell]]) -> None: self._rows = rows def __iter__(self): + "Iterate over `CSVRow` objects contained within this `CSV`. Traverses in order, starting with the topmost row." self.__current = 0 self.__last = len(self._rows) return self diff --git a/gm4_guidebook/triggers.json b/gm4_guidebook/triggers.json index b4b7ed6745..1638c317e0 100644 --- a/gm4_guidebook/triggers.json +++ b/gm4_guidebook/triggers.json @@ -1,6 +1,6 @@ { "__important__": "Generated by generate_guidebooks.py. Don't manually update this", - "__next__": 119, + "__next__": 120, "animi_shamir": 91, "apple_trees": 83, "arborenda_shamir": 20, @@ -81,6 +81,7 @@ "potion_liquids": 32, "potion_swords": 62, "record_crafting": 97, + "reeling_rods": 119, "relocators": 70, "resurrecting_skeletons": 41, "resurrecting_zombies": 46, diff --git a/gm4_reeling_rods/README.md b/gm4_reeling_rods/README.md new file mode 100644 index 0000000000..b9e4fe8600 --- /dev/null +++ b/gm4_reeling_rods/README.md @@ -0,0 +1,10 @@ +# Reeling Rods + +Reel in more than just fish with these rods. Yoink the chest from the chest boat, deal some damage, and more! + +### Features +- All fishing rods have extra abilities when hooking Paintings, Item Frames, Leash Knots, Shulkers and End Crystals. Hooking any entity will also dismount them from their vehicle. + +Adds 2 fishing rod enchantments, Reeling and Barbed. +- Reeling revolves around stealing from entities. Pull the chest from chest boats and so much more! +- Barbed turns a fishing rod into a lethal weapon. With 5 levels, it applies a scratching damage to the hooked mob and then bleeding damage. diff --git a/gm4_reeling_rods/beet.yaml b/gm4_reeling_rods/beet.yaml new file mode 100644 index 0000000000..8ab5f751b5 --- /dev/null +++ b/gm4_reeling_rods/beet.yaml @@ -0,0 +1,38 @@ +id: gm4_reeling_rods +name: Reeling Rods +version: 1.0.X + +data_pack: + load: . + +pipeline: + - generate_files + - gm4.plugins.extend.module + +require: + - bolt + +meta: + gm4: + versioning: + schedule_loops: [tick] + website: + description: Reel in more than just fish with these rods! Yoink the chest from the chest boat and more! + recommended: + - gm4_end_fishing + - gm4_live_catch + notes: [] + #modrinth: + #project_id: + #smithed: + #pack_id: + #planetminecraft: + #uid: + video: null + wiki: https://wiki.gm4.co/wiki/Reeling_Rods + credits: + Creators: + - runcows + - Bloo + Icon Design: + - runcows diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/enchantment/barbed.json b/gm4_reeling_rods/data/gm4_reeling_rods/enchantment/barbed.json new file mode 100644 index 0000000000..5a84154998 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/enchantment/barbed.json @@ -0,0 +1,24 @@ +{ + "description": { + "translate": "gm4.reeling_rods.enchantment.barbed", + "fallback": "Barbed" + }, + "exclusive_set": "gm4_reeling_rods:reeling", + "supported_items": "minecraft:fishing_rod", + "primary_items": "minecraft:fishing_rod", + "weight": 1, + "max_level": 5, + "min_cost": { + "base": 1, + "per_level_above_first": 10 + }, + "max_cost": { + "base": 51, + "per_level_above_first": 10 + }, + "anvil_cost": 1, + "slots": [ + "any" + ], + "effects": {} +} diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/enchantment/reeling.json b/gm4_reeling_rods/data/gm4_reeling_rods/enchantment/reeling.json new file mode 100644 index 0000000000..392ae08292 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/enchantment/reeling.json @@ -0,0 +1,24 @@ +{ + "description": { + "translate": "gm4.reeling_rods.enchantment.reeling", + "fallback": "Reeling" + }, + "exclusive_set": "gm4_reeling_rods:barbed", + "supported_items": "minecraft:fishing_rod", + "primary_items": "minecraft:fishing_rod", + "weight": 1, + "max_level": 1, + "min_cost": { + "base": 20, + "per_level_above_first": 0 + }, + "max_cost": { + "base": 70, + "per_level_above_first": 0 + }, + "anvil_cost": 8, + "slots": [ + "any" + ], + "effects": {} +} diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/barbed/apply.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/barbed/apply.mcfunction new file mode 100644 index 0000000000..93cb08ac48 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/barbed/apply.mcfunction @@ -0,0 +1,24 @@ +# Applies the barbed damage to the hooked entity +# @s = hooked entity +# at bobber position +# with {damage} +# run from hooked_entity/select_type + +# immediate damage (amount scales with enchantment level) +execute store result score $show_death_messages gm4_reeling_rods.barbed_damage_timer run gamerule showDeathMessages +gamerule showDeathMessages false +$damage @s $(damage) cactus by @p[tag=gm4_reeling_rods.player] +playsound minecraft:entity.player.attack.crit player @a[distance=..16] ~ ~ ~ 1 1.82 + +# handle death (@e only selects entities which are alive) +# | this is of importance for entities which display death messages or re-spawn +tag @s add gm4_reeling_rods.victim +execute if entity @s[type=#gm4_reeling_rods:support_death_message] at @s unless entity @e[type=#gm4_reeling_rods:support_death_message,tag=gm4_reeling_rods.victim,distance=0,limit=1] run function gm4_reeling_rods:barbed/on_scratch_death + +# if the victim is still alive, schedule bleeding damage +execute at @s if entity @e[tag=gm4_reeling_rods.victim,distance=0,limit=1] run function gm4_reeling_rods:barbed/schedule_bleeding + +# reset scores, gamerule and tag +tag @s remove gm4_reeling_rods.victim +execute if score $show_death_messages gm4_reeling_rods.barbed_damage_timer matches 1 run gamerule showDeathMessages true +scoreboard players reset $show_death_messages gm4_reeling_rods.barbed_damage_timer diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/barbed/bleed.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/barbed/bleed.mcfunction new file mode 100644 index 0000000000..5f262a8af5 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/barbed/bleed.mcfunction @@ -0,0 +1,42 @@ +# updates the bleeding timer +# @s = entity recently hit by a barbed fishing rod +# at @s +# run from barbed/find_affected + +# advance timer +scoreboard players add @s gm4_reeling_rods.barbed_damage_timer 1 + +# clear if timer exceeds 3s +execute if score @s gm4_reeling_rods.barbed_damage_timer matches 61.. run return run function gm4_reeling_rods:barbed/clear + +# return unless phase of timer is 0 +scoreboard players operation $phase gm4_reeling_rods.barbed_damage_timer = @s gm4_reeling_rods.barbed_damage_timer +scoreboard players operation $phase gm4_reeling_rods.barbed_damage_timer %= @s gm4_reeling_rods.barbed_damage_period +execute unless score $phase gm4_reeling_rods.barbed_damage_timer matches 0 run return fail + +# find attacker +# | tags attacker with gm4_reeling_rods.barbed_attacker +# | sets $found_attacker gm4_reeling_rods.barbed_attacker_uuid0 +execute summon snowball run function gm4_reeling_rods:barbed/find_attacker + +# prepare to handle player death +execute store result score $show_death_messages gm4_reeling_rods.barbed_damage_timer run gamerule showDeathMessages +gamerule showDeathMessages false + +# apply damage +# | if the attacker was found, attribute it to the attacker, if not do not attribute it to anyone +# | use cactus damage type as it has no knockback and respects armor +# | print custom death message to obscure cactus death message +execute if score $found_attacker gm4_reeling_rods.barbed_attacker_uuid0 matches 1.. run damage @s 2 cactus by @p[tag=gm4_reeling_rods.barbed_attacker] +execute unless score $found_attacker gm4_reeling_rods.barbed_attacker_uuid0 matches 1.. run damage @s 2 cactus +playsound minecraft:block.pointed_dripstone.drip_lava neutral @a[distance=..6] ~ ~ ~ 1 1.8 +execute anchored eyes run particle damage_indicator ^ ^ ^ .2 .2 .2 0 3 +execute anchored eyes run particle damage_indicator ^ ^ ^1 .5 .5 .5 0 8 normal @s + +# handle death (@e only selects entities which are alive) +# | this is of importance for entities which display death messages or re-spawn +tag @s add gm4_reeling_rods.victim +execute if entity @s[type=#gm4_reeling_rods:support_death_message] at @s unless entity @e[type=#gm4_reeling_rods:support_death_message,tag=gm4_reeling_rods.victim,distance=0,limit=1] run function gm4_reeling_rods:barbed/on_bleeding_death +tag @s remove gm4_reeling_rods.victim +execute if score $show_death_messages gm4_reeling_rods.barbed_damage_timer matches 1 run gamerule showDeathMessages true +scoreboard players reset $show_death_messages gm4_reeling_rods.barbed_damage_timer diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/barbed/clear.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/barbed/clear.mcfunction new file mode 100644 index 0000000000..36cadb1fa5 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/barbed/clear.mcfunction @@ -0,0 +1,11 @@ +# stops bleeding damage +# @s = entity recently hit by a barbed fishing rod +# at @s +# run from barbed/bleed, barbed/on_bleeding_death, and barbed/on_scratch_death + +scoreboard players reset @s gm4_reeling_rods.barbed_attacker_uuid0 +scoreboard players reset @s gm4_reeling_rods.barbed_attacker_uuid1 +scoreboard players reset @s gm4_reeling_rods.barbed_attacker_uuid2 +scoreboard players reset @s gm4_reeling_rods.barbed_attacker_uuid3 +scoreboard players reset @s gm4_reeling_rods.barbed_damage_period +scoreboard players reset @s gm4_reeling_rods.barbed_damage_timer diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/barbed/find_affected.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/barbed/find_affected.mcfunction new file mode 100644 index 0000000000..4f645c471e --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/barbed/find_affected.mcfunction @@ -0,0 +1,10 @@ +# initiates bleeding damage on affected entities, de-schedules if no more entities are affected +# @s = undefined +# at undefined +# scheduled from barbed/schedule_bleeding and self + +# apply barbed damage +execute as @e[scores={gm4_reeling_rods.barbed_damage_timer=0..}] at @s run function gm4_reeling_rods:barbed/bleed + +# reschedule if there are still barbed entities +execute if entity @e[scores={gm4_reeling_rods.barbed_damage_timer=0..},limit=1] run schedule function gm4_reeling_rods:barbed/find_affected 1t replace diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/barbed/find_attacker.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/barbed/find_attacker.mcfunction new file mode 100644 index 0000000000..6095512db4 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/barbed/find_attacker.mcfunction @@ -0,0 +1,21 @@ +# locates the attacker, as commands do not accept int-array formatted strings in macros +# @s = temporary snowball +# at location of snowball +# run from barbed/bleed + +# build uuid array +data modify storage gm4_reeling_rods:temp barbed_attacker_uuid set value [I;0,0,0,0] +execute store result storage gm4_reeling_rods:temp barbed_attacker_uuid[0] int 1 run scoreboard players get @s gm4_reeling_rods.barbed_attacker_uuid0 +execute store result storage gm4_reeling_rods:temp barbed_attacker_uuid[1] int 1 run scoreboard players get @s gm4_reeling_rods.barbed_attacker_uuid1 +execute store result storage gm4_reeling_rods:temp barbed_attacker_uuid[2] int 1 run scoreboard players get @s gm4_reeling_rods.barbed_attacker_uuid2 +execute store result storage gm4_reeling_rods:temp barbed_attacker_uuid[3] int 1 run scoreboard players get @s gm4_reeling_rods.barbed_attacker_uuid3 + +# move uuid to snowball +data modify entity @s Owner set from storage gm4_reeling_rods:temp barbed_attacker_uuid + +# tag owner +scoreboard players set $found_attacker gm4_reeling_rods.barbed_attacker_uuid0 0 +execute on origin store success score $found_attacker gm4_reeling_rods.barbed_attacker_uuid0 run tag @s add gm4_reeling_rods.barbed_attacker + +# remove snowball +kill @s diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/barbed/on_bleeding_death.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/barbed/on_bleeding_death.mcfunction new file mode 100644 index 0000000000..0117e6dc39 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/barbed/on_bleeding_death.mcfunction @@ -0,0 +1,13 @@ +# handles entities bleeding to death +# @s = entity who died by bleeding to death from barbed damage +# at @s +# run from barbed/bleed + +# death message +execute if entity @s[type=player] run tellraw @a ["",{"translate":"text.gm4.reeling_rods.death.scratch","fallback":"%s succumbed to their injuries",with:[{"selector":"@s"}]}] +execute unless entity @s[type=player] on owner run tag @s add gm4_reeling_rods.owner +execute unless entity @s[type=player] run tellraw @p[tag=gm4_reeling_rods.owner] ["",{"translate":"text.gm4.reeling_rods.death.scratch","fallback":"%s succumbed to their injuries",with:[{"selector":"@s"}]}] +execute unless entity @s[type=player] on owner run tag @s remove gm4_reeling_rods.owner + +# reset barbed state +function gm4_reeling_rods:barbed/clear diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/barbed/on_scratch_death.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/barbed/on_scratch_death.mcfunction new file mode 100644 index 0000000000..eb1bcf8554 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/barbed/on_scratch_death.mcfunction @@ -0,0 +1,13 @@ +# handles entities scratched to death +# @s = entity who died by immediate damage from a barbed rod +# at @s +# run from barbed/apply + +# death message +execute if entity @s[type=player] run tellraw @a ["",{"translate":"text.gm4.reeling_rods.death.scratch","fallback":"%s was scratched to death by %s",with:[{"selector":"@s"},{"selector":"@p[tag=gm4_reeling_rods.player]"}]}] +execute unless entity @s[type=player] on owner run tag @s add gm4_reeling_rods.owner +execute unless entity @s[type=player] run tellraw @p[tag=gm4_reeling_rods.owner] ["",{"translate":"text.gm4.reeling_rods.death.scratch","fallback":"%s was scratched to death by %s",with:[{"selector":"@s"},{"selector":"@p[tag=gm4_reeling_rods.player]"}]}] +execute unless entity @s[type=player] on owner run tag @s remove gm4_reeling_rods.owner + +# reset barbed state +function gm4_reeling_rods:barbed/clear diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/barbed/schedule_bleeding.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/barbed/schedule_bleeding.mcfunction new file mode 100644 index 0000000000..f5a1b11deb --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/barbed/schedule_bleeding.mcfunction @@ -0,0 +1,16 @@ +# schedules bleeding damage for the entity that was just hit by barbed +# @s = entity just hit by barbed that has not died from the immediate damage +# at bobber position +# run from barbed/apply + +# store attacker uuid and period +data modify storage gm4_reeling_rods:temp enchanted.barbed.attacker_uuid set from entity @a[limit=1,tag=gm4_reeling_rods.player] UUID +execute store result score @s gm4_reeling_rods.barbed_attacker_uuid0 run data get storage gm4_reeling_rods:temp enchanted.barbed.attacker_uuid[0] +execute store result score @s gm4_reeling_rods.barbed_attacker_uuid1 run data get storage gm4_reeling_rods:temp enchanted.barbed.attacker_uuid[1] +execute store result score @s gm4_reeling_rods.barbed_attacker_uuid2 run data get storage gm4_reeling_rods:temp enchanted.barbed.attacker_uuid[2] +execute store result score @s gm4_reeling_rods.barbed_attacker_uuid3 run data get storage gm4_reeling_rods:temp enchanted.barbed.attacker_uuid[3] +execute store result score @s gm4_reeling_rods.barbed_damage_period run data get storage gm4_reeling_rods:temp enchanted.barbed.period + +# initiate timer +scoreboard players set @s gm4_reeling_rods.barbed_damage_timer 0 +schedule function gm4_reeling_rods:barbed/find_affected 1t replace diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/get_execution_pos.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/get_execution_pos.mcfunction new file mode 100644 index 0000000000..5059a5ae26 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/get_execution_pos.mcfunction @@ -0,0 +1,7 @@ +# stores position of a newly summoned marker and kills it +# @s = new marker +# at @s +# run from get_motion_to_player and reeling/enderman + +data modify storage gm4_reeling_rods:temp position set from entity @s Pos +kill @s diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/get_lookup.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/get_lookup.mcfunction new file mode 100644 index 0000000000..a0edd6f2b3 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/get_lookup.mcfunction @@ -0,0 +1,5 @@ +# Adds a value from the lookup table to Y motion +# with {lookup_key} +# run from get_motion_to_player + +$scoreboard players operation $motionY gm4_reeling_rods.math += $$(lookup_key) gm4_reeling_rods.lookup diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/get_motion_to_player.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/get_motion_to_player.mcfunction new file mode 100644 index 0000000000..beb2d92c43 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/get_motion_to_player.mcfunction @@ -0,0 +1,45 @@ +# Gets motion vector to launch entity to player. X and Z motion is 10% the block distance between the player and current position. Y motion uses the sum of the squares of position deltas as a lookup table key, the value of which is added to the Y position delta to get the Y motion. +# @s = entity with items to be yoinked +# at bobber in @s (most of the time) +# run from pull_items + +data modify storage gm4_reeling_rods:temp item_data.Motion set value [0d,0d,0d] + +# Store current position +execute summon marker run function gm4_reeling_rods:get_execution_pos +# | position stored in storage gm4_reeling_rods:temp position +execute store result score $currentX gm4_reeling_rods.math run data get storage gm4_reeling_rods:temp position[0] 1 +execute store result score $currentY gm4_reeling_rods.math run data get storage gm4_reeling_rods:temp position[1] 1 +execute store result score $currentZ gm4_reeling_rods.math run data get storage gm4_reeling_rods:temp position[2] 1 + +# Player postion is stored in $motionX... ect from player/find_hooked_entity + +# Get distance from current position to player +scoreboard players operation $motionX gm4_reeling_rods.math -= $currentX gm4_reeling_rods.math +scoreboard players operation $motionY gm4_reeling_rods.math -= $currentY gm4_reeling_rods.math +scoreboard players operation $motionZ gm4_reeling_rods.math -= $currentZ gm4_reeling_rods.math + +# store Motion, y to be edited after +execute store result storage gm4_reeling_rods:temp item_data.Motion[0] double 0.1 run scoreboard players get $motionX gm4_reeling_rods.math +execute store result storage gm4_reeling_rods:temp item_data.Motion[1] double 0.1 run scoreboard players get $motionY gm4_reeling_rods.math +execute store result storage gm4_reeling_rods:temp item_data.Motion[2] double 0.1 run scoreboard players get $motionZ gm4_reeling_rods.math + +# Square the distances on each axis +scoreboard players operation $motionX gm4_reeling_rods.math *= $motionX gm4_reeling_rods.math +scoreboard players operation $motionY gm4_reeling_rods.math *= $motionY gm4_reeling_rods.math +scoreboard players operation $motionZ gm4_reeling_rods.math *= $motionZ gm4_reeling_rods.math + +# Add the squares +scoreboard players operation $lookup_key gm4_reeling_rods.math = $motionX gm4_reeling_rods.math +scoreboard players operation $lookup_key gm4_reeling_rods.math += $motionY gm4_reeling_rods.math +execute store result storage gm4_reeling_rods:temp lookup_key int 1 \ + run scoreboard players operation $lookup_key gm4_reeling_rods.math += $motionZ gm4_reeling_rods.math + +# Get Y motion, scaled up to match the squared values of before +execute store result score $motionY gm4_reeling_rods.math run data get storage gm4_reeling_rods:temp item_data.Motion[1] 100 + +# Add looked up value to motionY above +function gm4_reeling_rods:get_lookup with storage gm4_reeling_rods:temp + +# Store the Completed motionY +execute store result storage gm4_reeling_rods:temp item_data.Motion[1] double 0.01 run scoreboard players get $motionY gm4_reeling_rods.math diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/hooked_entity/end_crystal.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/hooked_entity/end_crystal.mcfunction new file mode 100644 index 0000000000..2d8b8e5acc --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/hooked_entity/end_crystal.mcfunction @@ -0,0 +1,6 @@ +# Action for hooked end_crystal +# @s = end_crystal +# at bobber in @s +# run from hooked_entity/select_type + +damage @s 1 minecraft:player_attack by @p[tag=gm4_reeling_rods.player] diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/hooked_entity/is_passenger.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/hooked_entity/is_passenger.mcfunction new file mode 100644 index 0000000000..4094996fa6 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/hooked_entity/is_passenger.mcfunction @@ -0,0 +1,6 @@ +# checks if @s is a passenger +# @s = entity to check +# at @s +# run from hooked_entity/select_type + +return run execute on vehicle if entity @s diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/hooked_entity/item_frame.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/hooked_entity/item_frame.mcfunction new file mode 100644 index 0000000000..3d6db6119e --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/hooked_entity/item_frame.mcfunction @@ -0,0 +1,19 @@ +# Action for hooked item frame or glow item frame +# @s = item frame or glow item frame +# at bobber in @s +# with {type} +# run from hooked_entity/select_type + +# fail if fixed +execute if data entity @s {Fixed:1b} run return fail + +$data modify storage gm4_reeling_rods:temp item_data.Item set value {id:"$(type)",count:1} +data modify storage gm4_reeling_rods:temp item_data.Item set from entity @s Item +execute at @s align xz positioned ~0.5 ~ ~0.5 run function gm4_reeling_rods:pull_items +execute unless data entity @s Item run return run kill @s +data remove entity @s Item + +$execute if data storage gm4_reeling_rods:temp {item_data:{Item:{id:"$(type)"}}} \ + run return run playsound minecraft:entity.item_frame.break neutral @a[distance=..16] ~ ~ ~ + +playsound minecraft:entity.item_frame.remove_item neutral @a[distance=..16] ~ ~ ~ diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/hooked_entity/leash_knot/action.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/hooked_entity/leash_knot/action.mcfunction new file mode 100644 index 0000000000..b32d05023f --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/hooked_entity/leash_knot/action.mcfunction @@ -0,0 +1,15 @@ +# Action for hooked leash knot +# @s = leash knot +# at bobber in @s +# run from hooked_entity/select_type + +tag @s add gm4_reeling_rods.leash_knot + +# distance=..12 is leash distance +execute at @s as @e[type=#gm4_reeling_rods:leashable,distance=..12] \ + if function gm4_reeling_rods:hooked_entity/leash_knot/leaded_by_knot \ + run function gm4_reeling_rods:hooked_entity/leash_knot/change_leader + +kill @s + +execute at @p[tag=gm4_reeling_rods.player] run playsound minecraft:entity.leash_knot.place neutral @a[distance=..16] ~ ~ ~ diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/hooked_entity/leash_knot/change_leader.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/hooked_entity/leash_knot/change_leader.mcfunction new file mode 100644 index 0000000000..b05ffcb826 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/hooked_entity/leash_knot/change_leader.mcfunction @@ -0,0 +1,7 @@ +# Changes a leashed entities leader from a leash knot to a tagged player +# @s = entity leaded to leash knot +# at leash knot +# run from hooked_entity/leash_knot/action + +data remove entity @s leash +data modify entity @s leash.UUID set from entity @p[tag=gm4_reeling_rods.player] UUID diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/hooked_entity/leash_knot/leaded_by_knot.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/hooked_entity/leash_knot/leaded_by_knot.mcfunction new file mode 100644 index 0000000000..2d8177a07b --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/hooked_entity/leash_knot/leaded_by_knot.mcfunction @@ -0,0 +1,6 @@ +# Checks if an entity is leashed by the knot in question +# @s = a leashable entity +# at owner +# run from hooked_entity/leash_knot/action + +return run execute on leasher if entity @s[tag=gm4_reeling_rods.leash_knot] diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/hooked_entity/painting.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/hooked_entity/painting.mcfunction new file mode 100644 index 0000000000..52b146d268 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/hooked_entity/painting.mcfunction @@ -0,0 +1,10 @@ +# Action for hooked painting +# @s = painting +# at bobber in @s +# run from hooked_entity/select_type + +data modify storage gm4_reeling_rods:temp item_data.Item set value {id:"minecraft:painting",count:1} +execute at @s align xz positioned ~0.5 ~ ~0.5 run function gm4_reeling_rods:pull_items + +kill @s +playsound minecraft:entity.painting.break neutral @a[distance=..16] ~ ~ ~ diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/hooked_entity/select_type.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/hooked_entity/select_type.mcfunction new file mode 100644 index 0000000000..4ce4eb8462 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/hooked_entity/select_type.mcfunction @@ -0,0 +1,27 @@ +# Selects the right entity type or dismounts the entity. +# @s = hooked entity +# at bobber in entity +# run from player/find_hooked_entity + +# apply barbed damage +execute if data storage gm4_reeling_rods:temp enchanted.barbed if data entity @s Health unless entity @s[type=player,gamemode=creative] \ + run function gm4_reeling_rods:barbed/apply with storage gm4_reeling_rods:temp enchanted.barbed +execute if data storage gm4_reeling_rods:temp enchanted.barbed if entity @s[type=minecraft:tnt_minecart] \ + run return run data modify entity @s fuse set value 0s + +raw # non-dismountable entities +for entity in ctx.meta['non_dismountable_entities']: + if entity['needs_reeling'].as_bool(): + execute if entity @s[type=entity['id']] run return run execute if data storage gm4_reeling_rods:temp enchanted.reeling run function entity['function'] + else: + execute if entity @s[type=entity['id']] run return run function entity['function'] + +raw # dismounting logic +execute if function gm4_reeling_rods:hooked_entity/is_passenger run return run ride @s dismount + +raw # dismountable entities +for entity in ctx.meta['dismountable_entities']: + if entity['needs_reeling'].as_bool(): + execute if entity @s[type=entity['id']] run return run execute if data storage gm4_reeling_rods:temp enchanted.reeling run function entity['function'] + else: + execute if entity @s[type=entity['id']] run return run function entity['function'] diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/hooked_entity/shulker.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/hooked_entity/shulker.mcfunction new file mode 100644 index 0000000000..fff2b7575b --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/hooked_entity/shulker.mcfunction @@ -0,0 +1,6 @@ +# Action for hooked shulker +# @s = shulker +# at bobber in @s +# run from hooked_entity/select_type + +execute at @s facing entity @a[tag=gm4_reeling_rods.player,distance=..33,limit=1] eyes if block ^ ^ ^1 #gm4:replaceable run tp @s ^ ^ ^1 diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/id/clear.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/id/clear.mcfunction new file mode 100644 index 0000000000..2b12ec093b --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/id/clear.mcfunction @@ -0,0 +1,21 @@ +# clears id of @s +# @s = entity with tag gm4_reeling_rods.id.tagged +# run from id/loop + +scoreboard players reset @s gm4_reeling_rods.id_bit.0 +scoreboard players reset @s gm4_reeling_rods.id_bit.1 +scoreboard players reset @s gm4_reeling_rods.id_bit.2 +scoreboard players reset @s gm4_reeling_rods.id_bit.3 +scoreboard players reset @s gm4_reeling_rods.id_bit.4 +scoreboard players reset @s gm4_reeling_rods.id_bit.5 +scoreboard players reset @s gm4_reeling_rods.id_bit.6 +scoreboard players reset @s gm4_reeling_rods.id_bit.7 +scoreboard players reset @s gm4_reeling_rods.id_bit.8 +scoreboard players reset @s gm4_reeling_rods.id_bit.9 +scoreboard players reset @s gm4_reeling_rods.id_bit.10 +scoreboard players reset @s gm4_reeling_rods.id_bit.11 +scoreboard players reset @s gm4_reeling_rods.id_bit.12 +scoreboard players reset @s gm4_reeling_rods.id_bit.13 +scoreboard players reset @s gm4_reeling_rods.id_bit.14 +scoreboard players reset @s gm4_reeling_rods.id_bit.15 +tag @s remove gm4_reeling_rods.id.tagged diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/id/get_next.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/id/get_next.mcfunction new file mode 100644 index 0000000000..12c42af8c9 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/id/get_next.mcfunction @@ -0,0 +1,57 @@ +# Gets the next id +# @s = entity to be assigned id +# at @s +# run from id/set + +## Binary Counter +# change bit 0 -> 1, return nothing else to do +# change bit 1 -> 0, then go on to next bit + +# bit.0 +execute if score $next gm4_reeling_rods.id_bit.0 matches 0 run return run scoreboard players set $next gm4_reeling_rods.id_bit.0 1 +scoreboard players set $next gm4_reeling_rods.id_bit.0 0 +# bit.1 +execute if score $next gm4_reeling_rods.id_bit.1 matches 0 run return run scoreboard players set $next gm4_reeling_rods.id_bit.1 1 +scoreboard players set $next gm4_reeling_rods.id_bit.1 0 +# bit.2 +execute if score $next gm4_reeling_rods.id_bit.2 matches 0 run return run scoreboard players set $next gm4_reeling_rods.id_bit.2 1 +scoreboard players set $next gm4_reeling_rods.id_bit.2 0 +# bit.3 +execute if score $next gm4_reeling_rods.id_bit.3 matches 0 run return run scoreboard players set $next gm4_reeling_rods.id_bit.3 1 +scoreboard players set $next gm4_reeling_rods.id_bit.3 0 +# bit.4 +execute if score $next gm4_reeling_rods.id_bit.4 matches 0 run return run scoreboard players set $next gm4_reeling_rods.id_bit.4 1 +scoreboard players set $next gm4_reeling_rods.id_bit.4 0 +# bit.5 +execute if score $next gm4_reeling_rods.id_bit.5 matches 0 run return run scoreboard players set $next gm4_reeling_rods.id_bit.5 1 +scoreboard players set $next gm4_reeling_rods.id_bit.5 0 +# bit.6 +execute if score $next gm4_reeling_rods.id_bit.6 matches 0 run return run scoreboard players set $next gm4_reeling_rods.id_bit.6 1 +scoreboard players set $next gm4_reeling_rods.id_bit.6 0 +# bit.7 +execute if score $next gm4_reeling_rods.id_bit.7 matches 0 run return run scoreboard players set $next gm4_reeling_rods.id_bit.7 1 +scoreboard players set $next gm4_reeling_rods.id_bit.7 0 +# bit.8 +execute if score $next gm4_reeling_rods.id_bit.8 matches 0 run return run scoreboard players set $next gm4_reeling_rods.id_bit.8 1 +scoreboard players set $next gm4_reeling_rods.id_bit.8 0 +# bit.9 +execute if score $next gm4_reeling_rods.id_bit.9 matches 0 run return run scoreboard players set $next gm4_reeling_rods.id_bit.9 1 +scoreboard players set $next gm4_reeling_rods.id_bit.9 0 +# bit.10 +execute if score $next gm4_reeling_rods.id_bit.10 matches 0 run return run scoreboard players set $next gm4_reeling_rods.id_bit.10 1 +scoreboard players set $next gm4_reeling_rods.id_bit.10 0 +# bit.11 +execute if score $next gm4_reeling_rods.id_bit.11 matches 0 run return run scoreboard players set $next gm4_reeling_rods.id_bit.11 1 +scoreboard players set $next gm4_reeling_rods.id_bit.11 0 +# bit.12 +execute if score $next gm4_reeling_rods.id_bit.12 matches 0 run return run scoreboard players set $next gm4_reeling_rods.id_bit.12 1 +scoreboard players set $next gm4_reeling_rods.id_bit.12 0 +# bit.13 +execute if score $next gm4_reeling_rods.id_bit.13 matches 0 run return run scoreboard players set $next gm4_reeling_rods.id_bit.13 1 +scoreboard players set $next gm4_reeling_rods.id_bit.13 0 +# bit.14 +execute if score $next gm4_reeling_rods.id_bit.14 matches 0 run return run scoreboard players set $next gm4_reeling_rods.id_bit.14 1 +scoreboard players set $next gm4_reeling_rods.id_bit.14 0 +# bit.15 +execute if score $next gm4_reeling_rods.id_bit.15 matches 0 run return run scoreboard players set $next gm4_reeling_rods.id_bit.15 1 +scoreboard players set $next gm4_reeling_rods.id_bit.15 0 diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/id/loop.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/id/loop.mcfunction new file mode 100644 index 0000000000..2fc18e92c5 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/id/loop.mcfunction @@ -0,0 +1,8 @@ +# checks for bobbers and stops when there are none +# run from player/cast_line and scheduled from id/select_entities + +# assign new ids if there's a bobber +execute as @e[type=minecraft:fishing_bobber] at @s run return run function gm4_reeling_rods:id/select_entities + +# no fishing bobber, clear ids +execute as @e[tag=gm4_reeling_rods.id.tagged] run function gm4_reeling_rods:id/clear diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/id/select_entities.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/id/select_entities.mcfunction new file mode 100644 index 0000000000..7f0071927d --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/id/select_entities.mcfunction @@ -0,0 +1,11 @@ +# selects entities to assign an id and schedules the loop to run again +# @s = fishing_bobber +# at @s +# run from id/loop + +# set new id tags if needed +# distance from bobber to entity is ..42 as that represents a vanilla entity of 3.28 blocks tall at a max of 16x scale and then 80% of the height to find the fishing bobber +execute as @e[type=!#gm4_reeling_rods:ignore,tag=!gm4_reeling_rods.id.tagged,distance=..42] at @s run function gm4_reeling_rods:id/set + +# schedule again, since bobber still exists +schedule function gm4_reeling_rods:id/loop 2t diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/id/set.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/id/set.mcfunction new file mode 100644 index 0000000000..0bf1187a05 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/id/set.mcfunction @@ -0,0 +1,26 @@ +# set an id on an entity +# @s = entity to be assigned id +# at @s +# run from id/select_entities + +# get new id +function gm4_reeling_rods:id/get_next + +# assign new id +scoreboard players operation @s gm4_reeling_rods.id_bit.0 = $next gm4_reeling_rods.id_bit.0 +scoreboard players operation @s gm4_reeling_rods.id_bit.1 = $next gm4_reeling_rods.id_bit.1 +scoreboard players operation @s gm4_reeling_rods.id_bit.2 = $next gm4_reeling_rods.id_bit.2 +scoreboard players operation @s gm4_reeling_rods.id_bit.3 = $next gm4_reeling_rods.id_bit.3 +scoreboard players operation @s gm4_reeling_rods.id_bit.4 = $next gm4_reeling_rods.id_bit.4 +scoreboard players operation @s gm4_reeling_rods.id_bit.5 = $next gm4_reeling_rods.id_bit.5 +scoreboard players operation @s gm4_reeling_rods.id_bit.6 = $next gm4_reeling_rods.id_bit.6 +scoreboard players operation @s gm4_reeling_rods.id_bit.7 = $next gm4_reeling_rods.id_bit.7 +scoreboard players operation @s gm4_reeling_rods.id_bit.8 = $next gm4_reeling_rods.id_bit.8 +scoreboard players operation @s gm4_reeling_rods.id_bit.9 = $next gm4_reeling_rods.id_bit.9 +scoreboard players operation @s gm4_reeling_rods.id_bit.10 = $next gm4_reeling_rods.id_bit.10 +scoreboard players operation @s gm4_reeling_rods.id_bit.11 = $next gm4_reeling_rods.id_bit.11 +scoreboard players operation @s gm4_reeling_rods.id_bit.12 = $next gm4_reeling_rods.id_bit.12 +scoreboard players operation @s gm4_reeling_rods.id_bit.13 = $next gm4_reeling_rods.id_bit.13 +scoreboard players operation @s gm4_reeling_rods.id_bit.14 = $next gm4_reeling_rods.id_bit.14 +scoreboard players operation @s gm4_reeling_rods.id_bit.15 = $next gm4_reeling_rods.id_bit.15 +tag @s add gm4_reeling_rods.id.tagged diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/init.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/init.mcfunction new file mode 100644 index 0000000000..fde93b9391 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/init.mcfunction @@ -0,0 +1,35 @@ +execute unless score reeling_rods gm4_modules matches 1 run data modify storage gm4:log queue append value {type:"install",module:"Reeling Rods"} +execute unless score reeling_rods gm4_earliest_version < reeling_rods gm4_modules run scoreboard players operation reeling_rods gm4_earliest_version = reeling_rods gm4_modules +scoreboard players set reeling_rods gm4_modules 1 + +scoreboard objectives add gm4_reeling_rods.math dummy +scoreboard objectives add gm4_reeling_rods.lookup dummy +scoreboard objectives add gm4_reeling_rods.barbed_damage_timer dummy +scoreboard objectives add gm4_reeling_rods.barbed_damage_period dummy +scoreboard objectives add gm4_reeling_rods.barbed_attacker_uuid0 dummy +scoreboard objectives add gm4_reeling_rods.barbed_attacker_uuid1 dummy +scoreboard objectives add gm4_reeling_rods.barbed_attacker_uuid2 dummy +scoreboard objectives add gm4_reeling_rods.barbed_attacker_uuid3 dummy +scoreboard objectives add gm4_reeling_rods.rods_cast minecraft.used:minecraft.fishing_rod +# id +scoreboard objectives add gm4_reeling_rods.id_bit.0 dummy +scoreboard objectives add gm4_reeling_rods.id_bit.1 dummy +scoreboard objectives add gm4_reeling_rods.id_bit.2 dummy +scoreboard objectives add gm4_reeling_rods.id_bit.3 dummy +scoreboard objectives add gm4_reeling_rods.id_bit.4 dummy +scoreboard objectives add gm4_reeling_rods.id_bit.5 dummy +scoreboard objectives add gm4_reeling_rods.id_bit.6 dummy +scoreboard objectives add gm4_reeling_rods.id_bit.7 dummy +scoreboard objectives add gm4_reeling_rods.id_bit.8 dummy +scoreboard objectives add gm4_reeling_rods.id_bit.9 dummy +scoreboard objectives add gm4_reeling_rods.id_bit.10 dummy +scoreboard objectives add gm4_reeling_rods.id_bit.11 dummy +scoreboard objectives add gm4_reeling_rods.id_bit.12 dummy +scoreboard objectives add gm4_reeling_rods.id_bit.13 dummy +scoreboard objectives add gm4_reeling_rods.id_bit.14 dummy +scoreboard objectives add gm4_reeling_rods.id_bit.15 dummy + +# set_lookup_table is generated in generate_files.py +function gm4_reeling_rods:set_lookup_table + +schedule function gm4_reeling_rods:tick 5t diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/player/cast_line.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/player/cast_line.mcfunction new file mode 100644 index 0000000000..bee0f7935c --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/player/cast_line.mcfunction @@ -0,0 +1,7 @@ +# sets rods_cast to 0 and schedules id loop +# @s = player, scores={gm4_reeling_rods.rods_cast=1..} +# at @s +# run from tick + +scoreboard players set @s gm4_reeling_rods.rods_cast 0 +function gm4_reeling_rods:id/loop diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/player/find_hooked_entity.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/player/find_hooked_entity.mcfunction new file mode 100644 index 0000000000..add3c5e232 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/player/find_hooked_entity.mcfunction @@ -0,0 +1,31 @@ +# Finds the entity the player hooked +# @s = player who fished +# at @s +# with {bit_0, bit_1, bit_2, bit_3, bit_4, bit_5, bit_6, bit_7, bit_8, bit_9, bit_10, bit_11, bit_12, bit_13, bit_14, bit_15} +# run from player/received_bit + +# store fishing rod & caster properties +data remove storage gm4_reeling_rods:temp enchanted +execute if predicate gm4_reeling_rods:holding_reeling_rod run data modify storage gm4_reeling_rods:temp enchanted.reeling set value 1 +execute if predicate gm4_reeling_rods:holding_barbed_rod/level_1 run data modify storage gm4_reeling_rods:temp enchanted.barbed set value {period: 31,damage:3} +execute if predicate gm4_reeling_rods:holding_barbed_rod/level_2 run data modify storage gm4_reeling_rods:temp enchanted.barbed set value {period: 26,damage:6} +execute if predicate gm4_reeling_rods:holding_barbed_rod/level_3 run data modify storage gm4_reeling_rods:temp enchanted.barbed set value {period: 21,damage:9} +execute if predicate gm4_reeling_rods:holding_barbed_rod/level_4 run data modify storage gm4_reeling_rods:temp enchanted.barbed set value {period: 16,damage:12} +execute if predicate gm4_reeling_rods:holding_barbed_rod/level_5 run data modify storage gm4_reeling_rods:temp enchanted.barbed set value {period: 11,damage:15} +data modify storage gm4_reeling_rods:temp player_data.Pos set from entity @s Pos +execute store result score $motionX gm4_reeling_rods.math run data get storage gm4_reeling_rods:temp player_data.Pos[0] 1 +execute store result score $motionY gm4_reeling_rods.math run data get storage gm4_reeling_rods:temp player_data.Pos[1] 1 +execute store result score $motionZ gm4_reeling_rods.math run data get storage gm4_reeling_rods:temp player_data.Pos[2] 1 + +tag @s add gm4_reeling_rods.player + +# distance from bobber to entity is ..42 as that represents a vanilla entity of 3.28 blocks tall at a max of 16x scale and then 80% of the height to find the fishing bobber +$execute as @e[type=minecraft:fishing_bobber,distance=..33] \ + if function gm4_reeling_rods:player/owns_bobber \ + at @s as @e[\ + distance=..42, limit=1, type=!#gm4_reeling_rods:ignore, \ + scores={$(bit_0),$(bit_1),$(bit_2),$(bit_3),$(bit_4),$(bit_5),$(bit_6),$(bit_7),$(bit_8),$(bit_9),$(bit_10),$(bit_11),$(bit_12),$(bit_13),$(bit_14),$(bit_15)}\ + ] unless entity @s[tag=smithed.entity] unless data entity @s {Invulnerable:1b} \ + run function gm4_reeling_rods:hooked_entity/select_type + +tag @s remove gm4_reeling_rods.player diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/player/owns_bobber.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/player/owns_bobber.mcfunction new file mode 100644 index 0000000000..da45021cf7 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/player/owns_bobber.mcfunction @@ -0,0 +1,6 @@ +# Checks if a fishing bobber belongs to the targeted owner +# @s = a fishing bobber +# at owner +# run from player/find_hooked_entity + +return run execute on origin if entity @s[tag=gm4_reeling_rods.player] diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/player/received_bit.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/player/received_bit.mcfunction new file mode 100644 index 0000000000..8bd8354fe9 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/player/received_bit.mcfunction @@ -0,0 +1,17 @@ +# Logic for when a player receives a bit +# @s = player who received a bit +# at @s +# with {bit, UUID} +# run from player/bit_{bit}_{value} + +$data modify storage gm4_reeling_rods:players "$(UUID)".bit_$(bit) set from storage gm4_reeling_rods:temp bit_data.bit_score + +# fail if not all bits +$execute store result score $bit_count gm4_reeling_rods.math run data get storage gm4_reeling_rods:players "$(UUID)" +execute unless score $bit_count gm4_reeling_rods.math matches 16 run return fail + +# all bits received +$function gm4_reeling_rods:player/find_hooked_entity with storage gm4_reeling_rods:players "$(UUID)" + +# clear storage +$data remove storage gm4_reeling_rods:players "$(UUID)" diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/pull_items.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/pull_items.mcfunction new file mode 100644 index 0000000000..b809ad1f84 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/pull_items.mcfunction @@ -0,0 +1,13 @@ +# Separates an entity that needs it +# @s = entity with items to be yoinked +# at bobber in @s (most of the time) +# run from hooked_entity/* & reeling/* & reeling/*/action & reeling/stealable/steal_slot/* + +function gm4_reeling_rods:get_motion_to_player +function gm4_reeling_rods:summon_item with storage gm4_reeling_rods:temp + +execute unless data entity @s Items[] run return 0 + +# Entities with Items tag +data modify storage gm4_reeling_rods:temp motion_vector set from storage gm4_reeling_rods:temp entity_data.Motion +function gm4_reeling_rods:reeling/empty_container_entity diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/bee.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/bee.mcfunction new file mode 100644 index 0000000000..7f714d28ac --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/bee.mcfunction @@ -0,0 +1,16 @@ +# Action for reeled bee +# @s = bee +# at bobber in @s +# run from hooked_entity/select_type + +# fail if no nectar +execute unless data entity @s {HasNectar:1b} run return fail + +# Steal +data modify storage gm4_reeling_rods:temp item_data set value {} +data merge entity @s {HasNectar:0b,AngerTime:300} +data modify entity @s AngryAt set from entity @p[tag=gm4_reeling_rods.player] UUID +data modify storage gm4_reeling_rods:temp item_data.Item set value {id:"minecraft:honeycomb",count:1} +function gm4_reeling_rods:pull_items + +playsound entity.bee.hurt neutral @a[distance=..16] ~ ~ ~ diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/chest_boat/action.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/chest_boat/action.mcfunction new file mode 100644 index 0000000000..9f52a08f75 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/chest_boat/action.mcfunction @@ -0,0 +1,21 @@ +# Action for reeled chest_boat +# @s = chest_boat type +# at bobber in @s +# with {boat_type} +# run from hooked_entity/select_type + +# steal +data modify storage gm4_reeling_rods:temp item_data set value {} +data modify storage gm4_reeling_rods:temp item_data.Item set value {id:"minecraft:chest",count:1} +execute positioned ~ ~0.3 ~ run function gm4_reeling_rods:pull_items + +# replace with boat +data modify storage gm4_reeling_rods:temp entity_data set from entity @s +data remove storage gm4_reeling_rods:temp entity_data.UUID +data remove storage gm4_reeling_rods:temp entity_data.Passengers +$data modify storage gm4_reeling_rods:temp entity_type set value "$(boat_type)" +execute at @s run function gm4_reeling_rods:reeling/summon_entity with storage gm4_reeling_rods:temp +execute at @s on passengers run function gm4_reeling_rods:reeling/chest_boat/passenger_transfer +tp @s ~ -1000 ~ + +playsound minecraft:entity.item.pickup neutral @a[distance=..16] ~ ~ ~ diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/chest_boat/passenger_transfer.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/chest_boat/passenger_transfer.mcfunction new file mode 100644 index 0000000000..6ea64eff5f --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/chest_boat/passenger_transfer.mcfunction @@ -0,0 +1,7 @@ +# transfer old passenger to new boat +# @s = passengers of chest boat type +# at old chest boat type +# run from reeling/chest_boat/action + +ride @s dismount +ride @s mount @e[type=#gm4:boats,distance=..0.00001,limit=1] diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/chested_horse.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/chested_horse.mcfunction new file mode 100644 index 0000000000..8c9ced17b5 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/chested_horse.mcfunction @@ -0,0 +1,8 @@ +# Action for reeled #gm4_reeling_rods:chested_horse +# @s = #gm4_reeling_rods:chested_horse +# at bobber in @s +# run from hooked_entity/select_type + +# chest, then saddle +execute unless function gm4_reeling_rods:reeling/stealable/steal_slot/chested_horse \ + run function gm4_reeling_rods:reeling/stealable/steal_slot/saddle diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/empty_container_entity.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/empty_container_entity.mcfunction new file mode 100644 index 0000000000..43007ed4ab --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/empty_container_entity.mcfunction @@ -0,0 +1,35 @@ +# Loops through Items[] and creates an item entity for each item, setting a slightly random motion +# @s = entity with an Items[] tag +# at @s +# run from pull_items + +# Assumptions +# | storage gm4_reeling_rods:temp motion_vector is a Motion[] vector that reaches player +# | in storage gm4_reeling_rods:temp entity_data is an Items[] array of item data objects + +# pull item data to be processed +data modify storage gm4_reeling_rods:temp item_data.Item set from storage gm4_reeling_rods:temp entity_data.Items[0] + +# randomize motion slightly.... +execute store result score $motionX gm4_reeling_rods.math run data get storage gm4_reeling_rods:temp motion_vector[0] 100 +execute store result score $motionY gm4_reeling_rods.math run data get storage gm4_reeling_rods:temp motion_vector[1] 100 +execute store result score $motionZ gm4_reeling_rods.math run data get storage gm4_reeling_rods:temp motion_vector[2] 100 +execute store result score $randomX gm4_reeling_rods.math run random value -10..10 +execute store result score $randomY gm4_reeling_rods.math run random value 0..10 +execute store result score $randomZ gm4_reeling_rods.math run random value -10..10 +execute store result storage gm4_reeling_rods:temp item_data.Motion[0] double 0.006 run \ + scoreboard players operation $motionX gm4_reeling_rods.math += $randomX gm4_reeling_rods.math +execute store result storage gm4_reeling_rods:temp item_data.Motion[1] double 0.006 run \ + scoreboard players operation $motionY gm4_reeling_rods.math += $randomY gm4_reeling_rods.math +execute store result storage gm4_reeling_rods:temp item_data.Motion[2] double 0.006 run \ + scoreboard players operation $motionZ gm4_reeling_rods.math += $randomZ gm4_reeling_rods.math +# scale 0.01 for same magnitude as main item, currently 0.006 to be slower + +# summon item with data +function gm4_reeling_rods:summon_item with storage gm4_reeling_rods:temp + +# remove processed item +data remove storage gm4_reeling_rods:temp entity_data.Items[0] + +# run again if needed +execute if data storage gm4_reeling_rods:temp entity_data.Items[] run function gm4_reeling_rods:reeling/empty_container_entity diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/enderman/action.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/enderman/action.mcfunction new file mode 100644 index 0000000000..88c5ac2e2e --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/enderman/action.mcfunction @@ -0,0 +1,31 @@ +# Action for reeled enderman +# @s = enderman +# at bobber in @s +# run from hooked_entity/select_type + +# fail if no held block +execute unless data entity @s carriedBlockState run return fail + +## determine summon location +# | bobber sits at 80% up the hitbox, we want 30% up from the feet for the held block, which is also 50% of the hitbox height down from the bobber +# | this works out to taking 62.5% of the height from feet to bobber, and going down from the bobber that far +# | we can achieve this by dividing a 100x scaled up difference of feet and bobber height by 16 + +# bobber height +execute summon marker run function gm4_reeling_rods:get_execution_pos +# | position stored in storage gm4_reeling_rods:temp position +execute store result score $bobberY gm4_reeling_rods.math run data get storage gm4_reeling_rods:temp position[1] 100 + +# feet height +execute at @s summon marker run function gm4_reeling_rods:get_execution_pos +# | position stored in storage gm4_reeling_rods:temp position +execute store result score $feetY gm4_reeling_rods.math run data get storage gm4_reeling_rods:temp position[1] 100 + +scoreboard players operation $bobberY gm4_reeling_rods.math -= $feetY gm4_reeling_rods.math + +scoreboard players set #16 gm4_reeling_rods.math 16 +execute store result storage gm4_reeling_rods:temp displacement float 0.1 \ + run scoreboard players operation $bobberY gm4_reeling_rods.math /= #16 gm4_reeling_rods.math + +# use this as a macro for the falling block displacement +function gm4_reeling_rods:reeling/enderman/falling_block with storage gm4_reeling_rods:temp diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/enderman/falling_block.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/enderman/falling_block.mcfunction new file mode 100644 index 0000000000..2bfff2fa39 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/enderman/falling_block.mcfunction @@ -0,0 +1,14 @@ +# Steal falling block of the enderman's held block +# @s = enderman +# at bobber in @s +# with {displacement} +# run from reeling/enderman/action + +data modify storage gm4_reeling_rods:temp entity_data set value {} +$execute positioned ~ ~-$(displacement) ~ run function gm4_reeling_rods:get_motion_to_player +# | motion vector stored in gm4_reeling_rods:temp item_data.Motion +data modify storage gm4_reeling_rods:temp entity_type set value "minecraft:falling_block" +data modify storage gm4_reeling_rods:temp entity_data.Motion set from storage gm4_reeling_rods:temp item_data.Motion +data modify storage gm4_reeling_rods:temp entity_data.BlockState set from entity @s carriedBlockState +data remove entity @s carriedBlockState +$execute positioned ~ ~-$(displacement) ~ run function gm4_reeling_rods:reeling/summon_entity with storage gm4_reeling_rods:temp diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/horse.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/horse.mcfunction new file mode 100644 index 0000000000..049fec52ad --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/horse.mcfunction @@ -0,0 +1,8 @@ +# Action for reeled horse +# @s = horse +# at bobber in @s +# run from hooked_entity/select_type + +# armor, then saddle +execute unless function gm4_reeling_rods:reeling/stealable/steal_slot/body \ + run function gm4_reeling_rods:reeling/stealable/steal_slot/saddle diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/llama.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/llama.mcfunction new file mode 100644 index 0000000000..43c3b59ea7 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/llama.mcfunction @@ -0,0 +1,8 @@ +# Action for reeled llama or trader llama +# @s = llama or trader llama +# at bobber in @s +# run from hooked_entity/select_type + +# chest, then carpet +execute unless function gm4_reeling_rods:reeling/stealable/steal_slot/chested_horse \ + run function gm4_reeling_rods:reeling/stealable/steal_slot/body diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/minecart.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/minecart.mcfunction new file mode 100644 index 0000000000..0c37bbb105 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/minecart.mcfunction @@ -0,0 +1,22 @@ +# Action for reeled *_minecart +# @s = *_minecart +# at bobber in @s +# with {block} +# run from hooked_entity/select_type + +# fail if passengers +execute if data entity @s Passengers run return fail + +# steal +data modify storage gm4_reeling_rods:temp item_data set value {} +$data modify storage gm4_reeling_rods:temp item_data.Item set value {id:"$(block)",count:1} +function gm4_reeling_rods:pull_items + +# replace with minecart +data modify storage gm4_reeling_rods:temp entity_data set from entity @s +data remove storage gm4_reeling_rods:temp entity_data.UUID +data modify storage gm4_reeling_rods:temp entity_type set value "minecraft:minecart" +execute at @s run function gm4_reeling_rods:reeling/summon_entity with storage gm4_reeling_rods:temp +tp @s ~ -1000 ~ + +playsound minecraft:entity.item.pickup neutral @a[distance=..16] ~ ~ ~ diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/mooshroom.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/mooshroom.mcfunction new file mode 100644 index 0000000000..87340c2908 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/mooshroom.mcfunction @@ -0,0 +1,24 @@ +# Action for reeled mooshroom +# @s = mooshroom +# at bobber in @s +# run from hooked_entity/select_type + +# fails +execute unless data entity @s {Age:0} run return fail +execute if data entity @s Passengers run return fail + +# steal +data modify storage gm4_reeling_rods:temp item_data set value {} +execute if data entity @s {Type:"red"} run data modify storage gm4_reeling_rods:temp item_data.Item.id set value "minecraft:red_mushroom" +execute if data entity @s {Type:"brown"} run data modify storage gm4_reeling_rods:temp item_data.Item.id set value "minecraft:brown_mushroom" +data modify storage gm4_reeling_rods:temp item_data.Item.count set value 5 +function gm4_reeling_rods:pull_items + +# replace with cow +data modify storage gm4_reeling_rods:temp entity_data set from entity @s +data remove storage gm4_reeling_rods:temp entity_data.UUID +data modify storage gm4_reeling_rods:temp entity_type set value "minecraft:cow" +execute at @s run function gm4_reeling_rods:reeling/summon_entity with storage gm4_reeling_rods:temp +tp @s ~ -1000 ~ + +playsound entity.mooshroom.shear neutral @a[distance=..16] ~ ~ ~ diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/sheep.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/sheep.mcfunction new file mode 100644 index 0000000000..9eeeb74afb --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/sheep.mcfunction @@ -0,0 +1,30 @@ +# Action for reeled sheep +# @s = sheep +# at bobber in @s +# run from hooked_entity/select_type + +# fail if sheared +execute if data entity @s {Sheared:1} run return fail + +# steal +data modify entity @s Sheared set value true +data modify storage gm4_reeling_rods:temp item_data set value {} +execute if data entity @s {Color:0b} run data modify storage gm4_reeling_rods:temp item_data.Item set value {id:"minecraft:white_wool",count:1} +execute if data entity @s {Color:1b} run data modify storage gm4_reeling_rods:temp item_data.Item set value {id:"minecraft:orange_wool",count:1} +execute if data entity @s {Color:2b} run data modify storage gm4_reeling_rods:temp item_data.Item set value {id:"minecraft:magenta_wool",count:1} +execute if data entity @s {Color:3b} run data modify storage gm4_reeling_rods:temp item_data.Item set value {id:"minecraft:light_blue_wool",count:1} +execute if data entity @s {Color:4b} run data modify storage gm4_reeling_rods:temp item_data.Item set value {id:"minecraft:yellow_wool",count:1} +execute if data entity @s {Color:5b} run data modify storage gm4_reeling_rods:temp item_data.Item set value {id:"minecraft:lime_wool",count:1} +execute if data entity @s {Color:6b} run data modify storage gm4_reeling_rods:temp item_data.Item set value {id:"minecraft:pink_wool",count:1} +execute if data entity @s {Color:7b} run data modify storage gm4_reeling_rods:temp item_data.Item set value {id:"minecraft:gray_wool",count:1} +execute if data entity @s {Color:8b} run data modify storage gm4_reeling_rods:temp item_data.Item set value {id:"minecraft:light_gray_wool",count:1} +execute if data entity @s {Color:9b} run data modify storage gm4_reeling_rods:temp item_data.Item set value {id:"minecraft:cyan_wool",count:1} +execute if data entity @s {Color:10b} run data modify storage gm4_reeling_rods:temp item_data.Item set value {id:"minecraft:purple_wool",count:1} +execute if data entity @s {Color:11b} run data modify storage gm4_reeling_rods:temp item_data.Item set value {id:"minecraft:blue_wool",count:1} +execute if data entity @s {Color:12b} run data modify storage gm4_reeling_rods:temp item_data.Item set value {id:"minecraft:brown_wool",count:1} +execute if data entity @s {Color:13b} run data modify storage gm4_reeling_rods:temp item_data.Item set value {id:"minecraft:green_wool",count:1} +execute if data entity @s {Color:14b} run data modify storage gm4_reeling_rods:temp item_data.Item set value {id:"minecraft:red_wool",count:1} +execute if data entity @s {Color:15b} run data modify storage gm4_reeling_rods:temp item_data.Item set value {id:"minecraft:black_wool",count:1} +function gm4_reeling_rods:pull_items + +playsound minecraft:entity.sheep.shear neutral @a[distance=..16] ~ ~ ~ diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/snow_golem.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/snow_golem.mcfunction new file mode 100644 index 0000000000..8a5ee517f4 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/snow_golem.mcfunction @@ -0,0 +1,15 @@ +# Action for reeled snow_golem +# @s = snow_golem +# at bobber in @s +# run from hooked_entity/select_type + +# fail if no Pumpkin +execute unless data entity @s {Pumpkin:1b} run return fail + +# steal +data modify storage gm4_reeling_rods:temp item_data set value {} +data modify entity @s Pumpkin set value 0b +data modify storage gm4_reeling_rods:temp item_data.Item set value {id:"minecraft:carved_pumpkin",count:1} +function gm4_reeling_rods:pull_items + +playsound minecraft:entity.item.pickup neutral @a[distance=..16] ~ ~ ~ diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/break_slot/mainhand.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/break_slot/mainhand.mcfunction new file mode 100644 index 0000000000..23d46220b5 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/break_slot/mainhand.mcfunction @@ -0,0 +1,8 @@ +# Break Mainhand Slot +# @s = #gm4_reeling_rods:steal_hand or #gm4_reeling_rods:steal_equipment +# at bobber in @s +# run from reeling/stealable/steal_slot/mainhand + +item replace entity @s weapon.mainhand with minecraft:air +playsound minecraft:entity.item.break neutral @a[distance=..16] ~ ~ ~ +return fail diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/check_drop_chance.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/check_drop_chance.mcfunction new file mode 100644 index 0000000000..bc6f1fb292 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/check_drop_chance.mcfunction @@ -0,0 +1,6 @@ +# checks drop chance against random +# run from reeling/stealable/steal_slot/* + +execute store result score $rand gm4_reeling_rods.math run random value 1..1000 +execute if score $rand gm4_reeling_rods.math <= $drop_chance gm4_reeling_rods.math run return 1 +return fail diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/order/equipment_1.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/order/equipment_1.mcfunction new file mode 100644 index 0000000000..53c7aef045 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/order/equipment_1.mcfunction @@ -0,0 +1,25 @@ +# Checks slots to steal +# @s = #gm4_reeling_rods:steal_equipment +# at bobber in @s +# run from reeling/stealable/steal_equipment + +# 1 +execute if items entity @s weapon.mainhand * \ + run return run function gm4_reeling_rods:reeling/stealable/steal_slot/mainhand +# 3 +execute if items entity @s armor.head * unless items entity @s armor.head *[minecraft:enchantments={"minecraft:binding_curse":1}] \ + run return run function gm4_reeling_rods:reeling/stealable/steal_slot/head +# 5 +execute if items entity @s armor.legs * unless items entity @s armor.legs *[minecraft:enchantments={"minecraft:binding_curse":1}] \ + run return run function gm4_reeling_rods:reeling/stealable/steal_slot/legs +# 2 +execute if items entity @s weapon.offhand * \ + run return run function gm4_reeling_rods:reeling/stealable/steal_slot/offhand +# 4 +execute if items entity @s armor.chest * unless items entity @s armor.chest *[minecraft:enchantments={"minecraft:binding_curse":1}] \ + run return run function gm4_reeling_rods:reeling/stealable/steal_slot/chest +# 6 +execute if items entity @s armor.feet * unless items entity @s armor.feet *[minecraft:enchantments={"minecraft:binding_curse":1}] \ + run return run function gm4_reeling_rods:reeling/stealable/steal_slot/feet + +return fail diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/order/equipment_2.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/order/equipment_2.mcfunction new file mode 100644 index 0000000000..b60673774a --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/order/equipment_2.mcfunction @@ -0,0 +1,25 @@ +# Checks slots to steal +# @s = #gm4_reeling_rods:steal_equipment +# at bobber in @s +# run from reeling/stealable/steal_equipment + +# 2 +execute if items entity @s weapon.offhand * \ + run return run function gm4_reeling_rods:reeling/stealable/steal_slot/offhand +# 4 +execute if items entity @s armor.chest * unless items entity @s armor.chest *[minecraft:enchantments={"minecraft:binding_curse":1}] \ + run return run function gm4_reeling_rods:reeling/stealable/steal_slot/chest +# 6 +execute if items entity @s armor.feet * unless items entity @s armor.feet *[minecraft:enchantments={"minecraft:binding_curse":1}] \ + run return run function gm4_reeling_rods:reeling/stealable/steal_slot/feet +# 1 +execute if items entity @s weapon.mainhand * \ + run return run function gm4_reeling_rods:reeling/stealable/steal_slot/mainhand +# 3 +execute if items entity @s armor.head * unless items entity @s armor.head *[minecraft:enchantments={"minecraft:binding_curse":1}] \ + run return run function gm4_reeling_rods:reeling/stealable/steal_slot/head +# 5 +execute if items entity @s armor.legs * unless items entity @s armor.legs *[minecraft:enchantments={"minecraft:binding_curse":1}] \ + run return run function gm4_reeling_rods:reeling/stealable/steal_slot/legs + +return fail diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/order/equipment_3.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/order/equipment_3.mcfunction new file mode 100644 index 0000000000..5a5399568c --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/order/equipment_3.mcfunction @@ -0,0 +1,25 @@ +# Checks slots to steal +# @s = #gm4_reeling_rods:steal_equipment +# at bobber in @s +# run from reeling/stealable/steal_equipment + +# 3 +execute if items entity @s armor.head * unless items entity @s armor.head *[minecraft:enchantments={"minecraft:binding_curse":1}] \ + run return run function gm4_reeling_rods:reeling/stealable/steal_slot/head +# 5 +execute if items entity @s armor.legs * unless items entity @s armor.legs *[minecraft:enchantments={"minecraft:binding_curse":1}] \ + run return run function gm4_reeling_rods:reeling/stealable/steal_slot/legs +# 2 +execute if items entity @s weapon.offhand * \ + run return run function gm4_reeling_rods:reeling/stealable/steal_slot/offhand +# 4 +execute if items entity @s armor.chest * unless items entity @s armor.chest *[minecraft:enchantments={"minecraft:binding_curse":1}] \ + run return run function gm4_reeling_rods:reeling/stealable/steal_slot/chest +# 6 +execute if items entity @s armor.feet * unless items entity @s armor.feet *[minecraft:enchantments={"minecraft:binding_curse":1}] \ + run return run function gm4_reeling_rods:reeling/stealable/steal_slot/feet +# 1 +execute if items entity @s weapon.mainhand * \ + run return run function gm4_reeling_rods:reeling/stealable/steal_slot/mainhand + +return fail diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/order/equipment_4.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/order/equipment_4.mcfunction new file mode 100644 index 0000000000..e786d8157d --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/order/equipment_4.mcfunction @@ -0,0 +1,25 @@ +# Checks slots to steal +# @s = #gm4_reeling_rods:steal_equipment +# at bobber in @s +# run from reeling/stealable/steal_equipment + +# 4 +execute if items entity @s armor.chest * unless items entity @s armor.chest *[minecraft:enchantments={"minecraft:binding_curse":1}] \ + run return run function gm4_reeling_rods:reeling/stealable/steal_slot/chest +# 6 +execute if items entity @s armor.feet * unless items entity @s armor.feet *[minecraft:enchantments={"minecraft:binding_curse":1}] \ + run return run function gm4_reeling_rods:reeling/stealable/steal_slot/feet +# 1 +execute if items entity @s weapon.mainhand * \ + run return run function gm4_reeling_rods:reeling/stealable/steal_slot/mainhand +# 3 +execute if items entity @s armor.head * unless items entity @s armor.head *[minecraft:enchantments={"minecraft:binding_curse":1}] \ + run return run function gm4_reeling_rods:reeling/stealable/steal_slot/head +# 5 +execute if items entity @s armor.legs * unless items entity @s armor.legs *[minecraft:enchantments={"minecraft:binding_curse":1}] \ + run return run function gm4_reeling_rods:reeling/stealable/steal_slot/legs +# 2 +execute if items entity @s weapon.offhand * \ + run return run function gm4_reeling_rods:reeling/stealable/steal_slot/offhand + +return fail diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/order/equipment_5.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/order/equipment_5.mcfunction new file mode 100644 index 0000000000..3b986da543 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/order/equipment_5.mcfunction @@ -0,0 +1,25 @@ +# Checks slots to steal +# @s = #gm4_reeling_rods:steal_equipment +# at bobber in @s +# run from reeling/stealable/steal_equipment + +# 5 +execute if items entity @s armor.legs * unless items entity @s armor.legs *[minecraft:enchantments={"minecraft:binding_curse":1}] \ + run return run function gm4_reeling_rods:reeling/stealable/steal_slot/legs +# 2 +execute if items entity @s weapon.offhand * \ + run return run function gm4_reeling_rods:reeling/stealable/steal_slot/offhand +# 4 +execute if items entity @s armor.chest * unless items entity @s armor.chest *[minecraft:enchantments={"minecraft:binding_curse":1}] \ + run return run function gm4_reeling_rods:reeling/stealable/steal_slot/chest +# 6 +execute if items entity @s armor.feet * unless items entity @s armor.feet *[minecraft:enchantments={"minecraft:binding_curse":1}] \ + run return run function gm4_reeling_rods:reeling/stealable/steal_slot/feet +# 1 +execute if items entity @s weapon.mainhand * \ + run return run function gm4_reeling_rods:reeling/stealable/steal_slot/mainhand +# 3 +execute if items entity @s armor.head * unless items entity @s armor.head *[minecraft:enchantments={"minecraft:binding_curse":1}] \ + run return run function gm4_reeling_rods:reeling/stealable/steal_slot/head + +return fail diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/order/equipment_6.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/order/equipment_6.mcfunction new file mode 100644 index 0000000000..082a9a49d1 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/order/equipment_6.mcfunction @@ -0,0 +1,25 @@ +# Checks slots to steal +# @s = #gm4_reeling_rods:steal_equipment +# at bobber in @s +# run from reeling/stealable/steal_equipment + +# 6 +execute if items entity @s armor.feet * unless items entity @s armor.feet *[minecraft:enchantments={"minecraft:binding_curse":1}] \ + run return run function gm4_reeling_rods:reeling/stealable/steal_slot/feet +# 1 +execute if items entity @s weapon.mainhand * \ + run return run function gm4_reeling_rods:reeling/stealable/steal_slot/mainhand +# 3 +execute if items entity @s armor.head * unless items entity @s armor.head *[minecraft:enchantments={"minecraft:binding_curse":1}] \ + run return run function gm4_reeling_rods:reeling/stealable/steal_slot/head +# 5 +execute if items entity @s armor.legs * unless items entity @s armor.legs *[minecraft:enchantments={"minecraft:binding_curse":1}] \ + run return run function gm4_reeling_rods:reeling/stealable/steal_slot/legs +# 2 +execute if items entity @s weapon.offhand * \ + run return run function gm4_reeling_rods:reeling/stealable/steal_slot/offhand +# 4 +execute if items entity @s armor.chest * unless items entity @s armor.chest *[minecraft:enchantments={"minecraft:binding_curse":1}] \ + run return run function gm4_reeling_rods:reeling/stealable/steal_slot/chest + +return fail diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/steal_equipment.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/steal_equipment.mcfunction new file mode 100644 index 0000000000..69be3320af --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/steal_equipment.mcfunction @@ -0,0 +1,13 @@ +# Pick an order to check equipment slots for stealing +# @s = #gm4_reeling_rods:steal_equipment +# at bobber in @s +# run from hooked_entity/select_type & reeling/villager/action + +execute store result score $order gm4_reeling_rods.math run random value 1..6 + +execute if score $order gm4_reeling_rods.math matches 1 run return run function gm4_reeling_rods:reeling/stealable/order/equipment_1 +execute if score $order gm4_reeling_rods.math matches 2 run return run function gm4_reeling_rods:reeling/stealable/order/equipment_2 +execute if score $order gm4_reeling_rods.math matches 3 run return run function gm4_reeling_rods:reeling/stealable/order/equipment_3 +execute if score $order gm4_reeling_rods.math matches 4 run return run function gm4_reeling_rods:reeling/stealable/order/equipment_4 +execute if score $order gm4_reeling_rods.math matches 5 run return run function gm4_reeling_rods:reeling/stealable/order/equipment_5 +execute if score $order gm4_reeling_rods.math matches 6 run return run function gm4_reeling_rods:reeling/stealable/order/equipment_6 diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/steal_hand.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/steal_hand.mcfunction new file mode 100644 index 0000000000..3b93d711b2 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/steal_hand.mcfunction @@ -0,0 +1,12 @@ +# Pick an order to check hand slots for stealing +# @s = #gm4_reeling_rods:steal_hand +# at bobber in @s +# run from hooked_entity/select_type + +execute store result score $mainhand_first gm4_reeling_rods.math run random value 0..1 + +execute if score $mainhand_first gm4_reeling_rods.math matches 1 if items entity @s weapon.mainhand * run return run function gm4_reeling_rods:reeling/stealable/steal_slot/mainhand +execute if items entity @s weapon.offhand * run return run function gm4_reeling_rods:reeling/stealable/steal_slot/offhand +execute if score $mainhand_first gm4_reeling_rods.math matches 0 if items entity @s weapon.mainhand * run return run function gm4_reeling_rods:reeling/stealable/steal_slot/mainhand + +return fail diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/steal_slot/body.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/steal_slot/body.mcfunction new file mode 100644 index 0000000000..8a8b8f8564 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/steal_slot/body.mcfunction @@ -0,0 +1,17 @@ +# Steal Body +# @s = wolf, llama or horse +# at bobber in @s +# run from hooked_entity/select_type & reeling/llama & reeling/horse + +# fails +execute unless data entity @s equipment.body run return fail +execute if data entity @s {drop_chances:{body:0.0f}} run return run function gm4_reeling_rods:reeling/stealable/zero_chance + +# steal slot +data modify storage gm4_reeling_rods:temp item_data set value {} +data modify storage gm4_reeling_rods:temp item_data.Item set from entity @s equipment.body +function gm4_reeling_rods:pull_items +item replace entity @s armor.body with minecraft:air + +playsound minecraft:entity.item.pickup neutral @a[distance=..16] ~ ~ ~ +return 8 diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/steal_slot/chest.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/steal_slot/chest.mcfunction new file mode 100644 index 0000000000..5ea5b9a4a1 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/steal_slot/chest.mcfunction @@ -0,0 +1,17 @@ +# Steal Chest +# @s = #gm4_reeling_rods:steal_equipment +# at bobber in @s +# run from reeling/stealable/order/equipment_* + +# fail if 0% drop chance +execute if data entity @s {drop_chances:{chest:0.0f}} run return run function gm4_reeling_rods:reeling/stealable/zero_chance + +# steal slot +data modify storage gm4_reeling_rods:temp item_data.Item set value {} +data modify storage gm4_reeling_rods:temp item_data.Item set from entity @s equipment.chest +data modify storage gm4_reeling_rods:temp item_data.PickupDelay set value 10s +function gm4_reeling_rods:pull_items +item replace entity @s armor.chest with minecraft:air + +playsound minecraft:entity.item.pickup neutral @a[distance=..16] ~ ~ ~ +return 4 diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/steal_slot/chested_horse.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/steal_slot/chested_horse.mcfunction new file mode 100644 index 0000000000..ac340ffee6 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/steal_slot/chested_horse.mcfunction @@ -0,0 +1,16 @@ +# Steal Chested Horse chest and items inside +# @s = #gm4_reeling_rods:chested_horse or llama / trader llama +# at bobber in @s +# run from reeling/llama & reeling/chested_horse + +# fail if not chested horse +execute unless data entity @s {ChestedHorse:1b} run return fail + +# steal slot +data modify storage gm4_reeling_rods:temp item_data set value {} +data modify storage gm4_reeling_rods:temp item_data.Item set value {id:"minecraft:chest",count:1} +function gm4_reeling_rods:pull_items +data modify entity @s ChestedHorse set value 0b + +playsound minecraft:entity.item.pickup neutral @a[distance=..16] ~ ~ ~ +return 9 diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/steal_slot/feet.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/steal_slot/feet.mcfunction new file mode 100644 index 0000000000..522971108c --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/steal_slot/feet.mcfunction @@ -0,0 +1,17 @@ +# Steal Feet +# @s = #gm4_reeling_rods:steal_equipment +# at bobber in @s +# run from reeling/stealable/order/equipment_* + +# fail if 0% drop chance +execute if data entity @s {drop_chances:{feet:0.0f}} run return run function gm4_reeling_rods:reeling/stealable/zero_chance + +# steal slot +data modify storage gm4_reeling_rods:temp item_data.Item set value {} +data modify storage gm4_reeling_rods:temp item_data.Item set from entity @s equipment.feet +data modify storage gm4_reeling_rods:temp item_data.PickupDelay set value 10s +function gm4_reeling_rods:pull_items +item replace entity @s armor.feet with minecraft:air + +playsound minecraft:entity.item.pickup neutral @a[distance=..16] ~ ~ ~ +return 6 diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/steal_slot/head.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/steal_slot/head.mcfunction new file mode 100644 index 0000000000..72aadd04a8 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/steal_slot/head.mcfunction @@ -0,0 +1,17 @@ +# Steal Head +# @s = #gm4_reeling_rods:steal_equipment +# at bobber in @s +# run from reeling/stealable/order/equipment_* + +# fail if 0% drop chance +execute if data entity @s {drop_chances:{head:0.0f}} run return run function gm4_reeling_rods:reeling/stealable/zero_chance + +# steal slot +data modify storage gm4_reeling_rods:temp item_data.Item set value {} +data modify storage gm4_reeling_rods:temp item_data.Item set from entity @s equipment.head +data modify storage gm4_reeling_rods:temp item_data.PickupDelay set value 10s +function gm4_reeling_rods:pull_items +item replace entity @s armor.head with minecraft:air + +playsound minecraft:entity.item.pickup neutral @a[distance=..16] ~ ~ ~ +return 3 diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/steal_slot/legs.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/steal_slot/legs.mcfunction new file mode 100644 index 0000000000..d82c016ba0 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/steal_slot/legs.mcfunction @@ -0,0 +1,17 @@ +# Steal Legs +# @s = #gm4_reeling_rods:steal_equipment +# at bobber in @s +# run from reeling/stealable/order/equipment_* + +# fail if 0% drop chance +execute if data entity @s {drop_chances:{legs:0.0f}} run return run function gm4_reeling_rods:reeling/stealable/zero_chance + +# steal slot +data modify storage gm4_reeling_rods:temp item_data.Item set value {} +data modify storage gm4_reeling_rods:temp item_data.Item set from entity @s equipment.legs +data modify storage gm4_reeling_rods:temp item_data.PickupDelay set value 10s +function gm4_reeling_rods:pull_items +item replace entity @s armor.legs with minecraft:air + +playsound minecraft:entity.item.pickup neutral @a[distance=..16] ~ ~ ~ +return 5 diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/steal_slot/mainhand.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/steal_slot/mainhand.mcfunction new file mode 100644 index 0000000000..91fee2d576 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/steal_slot/mainhand.mcfunction @@ -0,0 +1,27 @@ +# Steal Mainhand +# @s = #gm4_reeling_rods:steal_hand or #gm4_reeling_rods:steal_equipment +# at bobber in @s +# run from reeling/stealable/order/* and reeling/stealable/steal_hand + +## drop chance fail conditions +# to use default drop chances, we'd use 85 here as 8.5%, but we're setting it to 11.5% to match looting 3 chances +scoreboard players set $drop_chance gm4_reeling_rods.math 115 +execute if data entity @s drop_chances.mainhand store result score $drop_chance gm4_reeling_rods.math run data get entity @s drop_chances.mainhand 1000 +# villager and vex should ignore 0% drop chance on mainhand, otherwise fail if 0% +execute if entity @s[type=!vex,type=!villager] if score $drop_chance gm4_reeling_rods.math matches 0 run return run function gm4_reeling_rods:reeling/stealable/zero_chance +# drowned holding trident needs to roll chance +execute if entity @s[type=drowned] if items entity @s weapon.mainhand trident \ + unless function gm4_reeling_rods:reeling/stealable/check_drop_chance \ + run return run function gm4_reeling_rods:reeling/stealable/break_slot/mainhand + +## steal slot +data modify storage gm4_reeling_rods:temp item_data.Item set value {} +# need SelectedItem to work with players since players don't use equipment.mainhand +data modify storage gm4_reeling_rods:temp item_data.Item set from entity @s SelectedItem +data modify storage gm4_reeling_rods:temp item_data.Item set from entity @s equipment.mainhand +data modify storage gm4_reeling_rods:temp item_data.PickupDelay set value 10s +function gm4_reeling_rods:pull_items +item replace entity @s weapon.mainhand with minecraft:air + +playsound minecraft:entity.item.pickup neutral @a[distance=..16] ~ ~ ~ +return 1 diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/steal_slot/offhand.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/steal_slot/offhand.mcfunction new file mode 100644 index 0000000000..8b50fc578a --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/steal_slot/offhand.mcfunction @@ -0,0 +1,17 @@ +# Steal Offhand +# @s = #gm4_reeling_rods:steal_hand or #gm4_reeling_rods:steal_equipment +# at bobber in @s +# run from reeling/stealable/order/* and reeling/stealable/steal_hand + +# fail if 0% drop chance +execute if data entity @s {drop_chances:{offhand:0.0f}} run return run function gm4_reeling_rods:reeling/stealable/zero_chance + +## steal slot +data modify storage gm4_reeling_rods:temp item_data.Item set value {} +data modify storage gm4_reeling_rods:temp item_data.Item set from entity @s equipment.offhand +data modify storage gm4_reeling_rods:temp item_data.PickupDelay set value 10s +function gm4_reeling_rods:pull_items +item replace entity @s weapon.offhand with minecraft:air + +playsound minecraft:entity.item.pickup neutral @a[distance=..16] ~ ~ ~ +return 2 diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/steal_slot/saddle.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/steal_slot/saddle.mcfunction new file mode 100644 index 0000000000..284f8a74ef --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/steal_slot/saddle.mcfunction @@ -0,0 +1,17 @@ +# Steal Saddle +# @s = #gm4_reeling_rods:steal_saddle +# at bobber in @s +# run from hooked_entity/select_type + +# fails +execute unless data entity @s equipment.saddle run return fail +execute if data entity @s {drop_chances:{saddle:0.0f}} run return run function gm4_reeling_rods:reeling/stealable/zero_chance + +# steal slot +data modify storage gm4_reeling_rods:temp item_data set value {} +data modify storage gm4_reeling_rods:temp item_data.Item set from entity @s equipment.saddle +function gm4_reeling_rods:pull_items +item replace entity @s saddle with minecraft:air + +playsound minecraft:entity.item.pickup neutral @a[distance=..16] ~ ~ ~ +return 7 diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/zero_chance.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/zero_chance.mcfunction new file mode 100644 index 0000000000..2afb04172d --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/stealable/zero_chance.mcfunction @@ -0,0 +1,6 @@ +# slot has a 0% drop chance, play sound and fail +# at @s +# run from reeling/stealable/steal_slot/* + +playsound minecraft:item.spyglass.stop_using neutral @a[distance=16] ~ ~ ~ +return fail diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/summon_entity.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/summon_entity.mcfunction new file mode 100644 index 0000000000..9c3e279a4a --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/summon_entity.mcfunction @@ -0,0 +1,7 @@ +# Summons a generic entity with data +# @s = entity that was hooked +# at @s (unless run from enderman) +# with {entity_type, entity_data} +# run from reeling/chest_boat/action and reeling/{minecart|mooshroom} and reeling/enderman/falling_block + +$summon $(entity_type) ~ ~ ~ $(entity_data) diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/villager/action.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/villager/action.mcfunction new file mode 100644 index 0000000000..104fe35583 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/villager/action.mcfunction @@ -0,0 +1,26 @@ +# Action for reeled villager +# @s = villager +# at bobber in @s +# run from hooked_entity/select_type + +# store mainhand data for a potential trade steal +data modify storage gm4_reeling_rods:temp entity_data set value {} +data modify storage gm4_reeling_rods:temp entity_data.mainhand set from entity @s equipment.mainhand + +# try to steal +execute store result score $slot gm4_reeling_rods.math run function gm4_reeling_rods:reeling/stealable/steal_equipment +# if not mainhand, return +execute unless score $slot gm4_reeling_rods.math matches 1 run return fail + +## mainhand stolen (TRADED ITEM) + +# find trade and sell it out +function gm4_reeling_rods:reeling/villager/sell_out with storage gm4_reeling_rods:temp entity_data + +# add 20 "major_negative" gossip of the player to the villager +data modify storage gm4_reeling_rods:temp entity_data.gossip.Target set from entity @p[tag=gm4_reeling_rods.player] UUID +function gm4_reeling_rods:reeling/villager/add_gossip with storage gm4_reeling_rods:temp entity_data.gossip + +# feedback +particle minecraft:angry_villager ~ ~ ~ 0.3 0.3 0.3 20 3 +playsound minecraft:entity.villager.hurt neutral @a[distance=..16] ~ ~ ~ diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/villager/add_gossip.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/villager/add_gossip.mcfunction new file mode 100644 index 0000000000..124843ef67 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/villager/add_gossip.mcfunction @@ -0,0 +1,16 @@ +# adds a "major_negaive" gossip of the player to the villager +# @s = villager +# at bobber in @s +# with {Target} +# run from reeling/villager/action + +$execute store success score $success gm4_reeling_rods.math run \ + data modify storage gm4_reeling_rods:temp entity_data.gossip merge from entity @s Gossips[{Type:"major_negative",Target:$(Target)}] + +execute unless score $success gm4_reeling_rods.math matches 1 run data modify storage gm4_reeling_rods:temp entity_data.gossip merge value {Type:"major_negative",Value:0} + +execute store result score $gossip_value gm4_reeling_rods.math run data get storage gm4_reeling_rods:temp entity_data.gossip.Value +execute unless score $gossip_value gm4_reeling_rods.math matches ..80 run scoreboard players set $gossip_value gm4_reeling_rods.math 100 +execute if score $gossip_value gm4_reeling_rods.math matches ..80 run scoreboard players add $gossip_value gm4_reeling_rods.math 20 +execute store result storage gm4_reeling_rods:temp entity_data.gossip.Value int 1 run scoreboard players get $gossip_value gm4_reeling_rods.math +data modify entity @s Gossips append from storage gm4_reeling_rods:temp entity_data.gossip diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/villager/sell_out.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/villager/sell_out.mcfunction new file mode 100644 index 0000000000..1dc0f5d815 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/reeling/villager/sell_out.mcfunction @@ -0,0 +1,10 @@ +# sells out a trade +# @s = villager +# at bobber in @s +# with {mainhand} +# run from reeling/villager/action + +# for some reason on the first item after a restock?? it fails to set uses, but succeeds after that? This double set doesn't fix that though +# | needs more investigation +$data modify entity @s Offers.Recipes[{sell:$(mainhand)}] merge value {uses:0} +$data modify entity @s Offers.Recipes[{sell:$(mainhand)}].uses set from entity @s Offers.Recipes[{sell:$(mainhand)}].maxUses diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/summon_item.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/summon_item.mcfunction new file mode 100644 index 0000000000..91469011f3 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/summon_item.mcfunction @@ -0,0 +1,6 @@ +# Summons item with data +# @s = entity with items to be yoinked +# at bobber in @s (most of the time) +# run from pull_items & reeling/empty_container_entity + +$summon minecraft:item ~ ~ ~ $(item_data) diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/function/tick.mcfunction b/gm4_reeling_rods/data/gm4_reeling_rods/function/tick.mcfunction new file mode 100644 index 0000000000..dfcd00fbc3 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/function/tick.mcfunction @@ -0,0 +1,5 @@ +# checks if players have cast a line, then will assign ids to entities around bobber +execute as @a[scores={gm4_reeling_rods.rods_cast=1..}] run function gm4_reeling_rods:player/cast_line + +# 5 ticks is good enough response time +schedule function gm4_reeling_rods:tick 5t diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/guidebook/reeling_rods.json b/gm4_reeling_rods/data/gm4_reeling_rods/guidebook/reeling_rods.json new file mode 100644 index 0000000000..b9697f4236 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/guidebook/reeling_rods.json @@ -0,0 +1,110 @@ +{ + "id": "reeling_rods", + "name": "Reeling Rods", + "module_type": "module", + "icon": { + "id": "minecraft:fishing_rod" + }, + "criteria": { + "obtain_fishing_rod": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": "minecraft:fishing_rod" + } + ] + } + }, + "obtain_reeling_rod": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": "minecraft:fishing_rod", + "predicates": { + "minecraft:enchantments": [ + { + "enchantments": "gm4_reeling_rods:reeling" + } + ] + } + } + ] + } + }, + "obtain_barbed_rod": { + "trigger": "minecraft:inventory_changed", + "conditions": { + "items": [ + { + "items": "minecraft:fishing_rod", + "predicates": { + "minecraft:enchantments": [ + { + "enchantments": "gm4_reeling_rods:barbed" + } + ] + } + } + ] + } + } + }, + "sections": [ + { + "name": "description", + "enable": [], + "requirements": [ + [ + "obtain_fishing_rod" + ] + ], + "pages": [ + [ + { + "insert": "title" + }, + { + "translate": "text.gm4.guidebook.reeling_rods.description", + "fallback": "All fishing rods have extra abilities when hooking Paintings, Item Frames, Leash Knots, Shulkers and End Crystals. Hooking any entity will also dismount them from their vehicle." + } + ] + ] + }, + { + "name": "reeling", + "enable": [], + "requirements": [ + [ + "obtain_reeling_rod" + ] + ], + "pages": [ + [ + { + "translate": "text.gm4.guidebook.reeling_rods.reeling", + "fallback": "Reeling is an enchantment that revolves around stealing from entities. Pull the chest from chest boats and so much more!" + } + ] + ] + }, + { + "name": "barbed", + "enable": [], + "requirements": [ + [ + "obtain_barbed_rod" + ] + ], + "pages": [ + [ + { + "translate": "text.gm4.guidebook.reeling_rods.barbed", + "fallback": "Barbed turns a fishing rod into a lethal weapon. With 5 levels, it applies a scratching damage to the hooked mob and then bleeding damage." + } + ] + ] + } + ] +} diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/predicate/holding_barbed_rod/level_1.json b/gm4_reeling_rods/data/gm4_reeling_rods/predicate/holding_barbed_rod/level_1.json new file mode 100644 index 0000000000..71a4a8225b --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/predicate/holding_barbed_rod/level_1.json @@ -0,0 +1,18 @@ +{ + "condition": "minecraft:entity_properties", + "entity": "this", + "predicate": { + "slots": { + "weapon.*": { + "predicates": { + "minecraft:enchantments": [ + { + "enchantments": "gm4_reeling_rods:barbed", + "levels": 1 + } + ] + } + } + } + } +} diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/predicate/holding_barbed_rod/level_2.json b/gm4_reeling_rods/data/gm4_reeling_rods/predicate/holding_barbed_rod/level_2.json new file mode 100644 index 0000000000..9f4cf88480 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/predicate/holding_barbed_rod/level_2.json @@ -0,0 +1,18 @@ +{ + "condition": "minecraft:entity_properties", + "entity": "this", + "predicate": { + "slots": { + "weapon.*": { + "predicates": { + "minecraft:enchantments": [ + { + "enchantments": "gm4_reeling_rods:barbed", + "levels": 2 + } + ] + } + } + } + } +} diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/predicate/holding_barbed_rod/level_3.json b/gm4_reeling_rods/data/gm4_reeling_rods/predicate/holding_barbed_rod/level_3.json new file mode 100644 index 0000000000..2d60bcd513 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/predicate/holding_barbed_rod/level_3.json @@ -0,0 +1,18 @@ +{ + "condition": "minecraft:entity_properties", + "entity": "this", + "predicate": { + "slots": { + "weapon.*": { + "predicates": { + "minecraft:enchantments": [ + { + "enchantments": "gm4_reeling_rods:barbed", + "levels": 3 + } + ] + } + } + } + } +} diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/predicate/holding_barbed_rod/level_4.json b/gm4_reeling_rods/data/gm4_reeling_rods/predicate/holding_barbed_rod/level_4.json new file mode 100644 index 0000000000..8e2fd83d79 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/predicate/holding_barbed_rod/level_4.json @@ -0,0 +1,18 @@ +{ + "condition": "minecraft:entity_properties", + "entity": "this", + "predicate": { + "slots": { + "weapon.*": { + "predicates": { + "minecraft:enchantments": [ + { + "enchantments": "gm4_reeling_rods:barbed", + "levels": 4 + } + ] + } + } + } + } +} diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/predicate/holding_barbed_rod/level_5.json b/gm4_reeling_rods/data/gm4_reeling_rods/predicate/holding_barbed_rod/level_5.json new file mode 100644 index 0000000000..5059ebeb28 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/predicate/holding_barbed_rod/level_5.json @@ -0,0 +1,18 @@ +{ + "condition": "minecraft:entity_properties", + "entity": "this", + "predicate": { + "slots": { + "weapon.*": { + "predicates": { + "minecraft:enchantments": [ + { + "enchantments": "gm4_reeling_rods:barbed", + "levels": 5 + } + ] + } + } + } + } +} diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/predicate/holding_reeling_rod.json b/gm4_reeling_rods/data/gm4_reeling_rods/predicate/holding_reeling_rod.json new file mode 100644 index 0000000000..cd7a1fba2e --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/predicate/holding_reeling_rod.json @@ -0,0 +1,17 @@ +{ + "condition": "minecraft:entity_properties", + "entity": "this", + "predicate": { + "slots": { + "weapon.*": { + "predicates": { + "minecraft:enchantments": [ + { + "enchantments": "gm4_reeling_rods:reeling" + } + ] + } + } + } + } +} diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/tags/entity_type/chested_horse.json b/gm4_reeling_rods/data/gm4_reeling_rods/tags/entity_type/chested_horse.json new file mode 100644 index 0000000000..4cd85e4a5b --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/tags/entity_type/chested_horse.json @@ -0,0 +1,6 @@ +{ + "values": [ + "minecraft:donkey", + "minecraft:mule" + ] +} diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/tags/entity_type/ignore.json b/gm4_reeling_rods/data/gm4_reeling_rods/tags/entity_type/ignore.json new file mode 100644 index 0000000000..dbb3066de7 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/tags/entity_type/ignore.json @@ -0,0 +1,39 @@ +{ + "values": [ + "minecraft:area_effect_cloud", + "minecraft:arrow", + "minecraft:block_display", + "minecraft:breeze_wind_charge", + "minecraft:command_block_minecart", + "minecraft:dragon_fireball", + "minecraft:egg", + "minecraft:ender_pearl", + "minecraft:evoker_fangs", + "minecraft:experience_bottle", + "minecraft:experience_orb", + "minecraft:eye_of_ender", + "minecraft:falling_block", + "minecraft:fireball", + "minecraft:firework_rocket", + "minecraft:fishing_bobber", + "minecraft:interaction", + "minecraft:item", + "minecraft:item_display", + "minecraft:lightning_bolt", + "minecraft:lingering_potion", + "minecraft:llama_spit", + "minecraft:marker", + "minecraft:ominous_item_spawner", + "minecraft:splash_potion", + "minecraft:shulker_bullet", + "minecraft:small_fireball", + "minecraft:snowball", + "minecraft:spawner_minecart", + "minecraft:spectral_arrow", + "minecraft:text_display", + "minecraft:tnt", + "minecraft:trident", + "minecraft:wind_charge", + "minecraft:wither_skull" + ] +} diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/tags/entity_type/leashable.json b/gm4_reeling_rods/data/gm4_reeling_rods/tags/entity_type/leashable.json new file mode 100644 index 0000000000..162cc4b03e --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/tags/entity_type/leashable.json @@ -0,0 +1,38 @@ +{ + "values": [ + "#gm4:boats", + "#gm4:chest_boats", + "#gm4_reeling_rods:llamas", + "#gm4_reeling_rods:steal_saddle", + "minecraft:allay", + "minecraft:armadillo", + "minecraft:axolotl", + "minecraft:bee", + "minecraft:camel", + "minecraft:cat", + "minecraft:chicken", + "minecraft:cow", + "minecraft:dolphin", + "minecraft:donkey", + "minecraft:fox", + "minecraft:frog", + "minecraft:glow_squid", + "minecraft:goat", + { "id": "minecraft:happy_ghast", "required": false }, + "minecraft:hoglin", + "minecraft:horse", + "minecraft:iron_golem", + "minecraft:mooshroom", + "minecraft:mule", + "minecraft:ocelot", + "minecraft:parrot", + "minecraft:polar_bear", + "minecraft:rabbit", + "minecraft:sheep", + "minecraft:sniffer", + "minecraft:snow_golem", + "minecraft:squid", + "minecraft:wolf", + "minecraft:zoglin" + ] +} diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/tags/entity_type/llamas.json b/gm4_reeling_rods/data/gm4_reeling_rods/tags/entity_type/llamas.json new file mode 100644 index 0000000000..4560fcfee3 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/tags/entity_type/llamas.json @@ -0,0 +1,6 @@ +{ + "values": [ + "minecraft:llama", + "minecraft:trader_llama" + ] +} diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/tags/entity_type/steal_body.json b/gm4_reeling_rods/data/gm4_reeling_rods/tags/entity_type/steal_body.json new file mode 100644 index 0000000000..b6bdf88134 --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/tags/entity_type/steal_body.json @@ -0,0 +1,6 @@ +{ + "values": [ + { "id": "minecraft:happy_ghast", "required": false }, + "minecraft:wolf" + ] +} diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/tags/entity_type/steal_equipment.json b/gm4_reeling_rods/data/gm4_reeling_rods/tags/entity_type/steal_equipment.json new file mode 100644 index 0000000000..4744b7d6be --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/tags/entity_type/steal_equipment.json @@ -0,0 +1,17 @@ +{ + "values": [ + "minecraft:armor_stand", + "minecraft:bogged", + "minecraft:drowned", + "minecraft:husk", + "minecraft:piglin", + "minecraft:piglin_brute", + "minecraft:player", + "minecraft:skeleton", + "minecraft:stray", + "minecraft:wither_skeleton", + "minecraft:zombie", + "minecraft:zombie_villager", + "minecraft:zombified_piglin" + ] +} diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/tags/entity_type/steal_hand.json b/gm4_reeling_rods/data/gm4_reeling_rods/tags/entity_type/steal_hand.json new file mode 100644 index 0000000000..76c8c7602e --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/tags/entity_type/steal_hand.json @@ -0,0 +1,12 @@ +{ + "values": [ + "minecraft:allay", + "minecraft:fox", + "minecraft:illusioner", + "minecraft:pillager", + "minecraft:vex", + "minecraft:vindicator", + "minecraft:wandering_trader", + "minecraft:witch" + ] +} diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/tags/entity_type/steal_saddle.json b/gm4_reeling_rods/data/gm4_reeling_rods/tags/entity_type/steal_saddle.json new file mode 100644 index 0000000000..aef60be58a --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/tags/entity_type/steal_saddle.json @@ -0,0 +1,9 @@ +{ + "values": [ + "minecraft:camel", + "minecraft:pig", + "minecraft:skeleton_horse", + "minecraft:strider", + "minecraft:zombie_horse" + ] +} diff --git a/gm4_reeling_rods/data/gm4_reeling_rods/tags/entity_type/support_death_message.json b/gm4_reeling_rods/data/gm4_reeling_rods/tags/entity_type/support_death_message.json new file mode 100644 index 0000000000..bec44856dc --- /dev/null +++ b/gm4_reeling_rods/data/gm4_reeling_rods/tags/entity_type/support_death_message.json @@ -0,0 +1,8 @@ +{ + "values": [ + "minecraft:cat", + "minecraft:parrot", + "minecraft:player", + "minecraft:wolf" + ] +} diff --git a/gm4_reeling_rods/data/minecraft/tags/enchantment/non_treasure.json b/gm4_reeling_rods/data/minecraft/tags/enchantment/non_treasure.json new file mode 100644 index 0000000000..5e9cb723ff --- /dev/null +++ b/gm4_reeling_rods/data/minecraft/tags/enchantment/non_treasure.json @@ -0,0 +1,6 @@ +{ + "values": [ + "gm4_reeling_rods:reeling", + "gm4_reeling_rods:barbed" + ] +} diff --git a/gm4_reeling_rods/entities.csv b/gm4_reeling_rods/entities.csv new file mode 100644 index 0000000000..58162aeafa --- /dev/null +++ b/gm4_reeling_rods/entities.csv @@ -0,0 +1,34 @@ +id,needs_reeling,can_dismount,function +#gm4_reeling_rods:chested_horse,TRUE,TRUE,"gm4_reeling_rods:reeling/chested_horse" +#gm4_reeling_rods:llamas,TRUE,TRUE,"gm4_reeling_rods:reeling/llama" +#gm4_reeling_rods:steal_body,TRUE,TRUE,"gm4_reeling_rods:reeling/stealable/steal_slot/body" +#gm4_reeling_rods:steal_equipment,TRUE,TRUE,"gm4_reeling_rods:reeling/stealable/steal_equipment" +#gm4_reeling_rods:steal_hand,TRUE,TRUE,"gm4_reeling_rods:reeling/stealable/steal_hand" +#gm4_reeling_rods:steal_saddle,TRUE,TRUE,"gm4_reeling_rods:reeling/stealable/steal_slot/saddle" +minecraft:bee,TRUE,TRUE,"gm4_reeling_rods:reeling/bee" +minecraft:enderman,TRUE,TRUE,"gm4_reeling_rods:reeling/enderman/action" +minecraft:horse,TRUE,TRUE,"gm4_reeling_rods:reeling/horse" +minecraft:mooshroom,TRUE,TRUE,"gm4_reeling_rods:reeling/mooshroom" +minecraft:sheep,TRUE,TRUE,"gm4_reeling_rods:reeling/sheep" +minecraft:snow_golem,TRUE,TRUE,"gm4_reeling_rods:reeling/snow_golem" +minecraft:villager,TRUE,TRUE,"gm4_reeling_rods:reeling/villager/action" +minecraft:chest_minecart,TRUE,FALSE,"gm4_reeling_rods:reeling/minecart {block:'minecraft:chest'}" +minecraft:furnace_minecart,TRUE,FALSE,"gm4_reeling_rods:reeling/minecart {block:'minecraft:furnace'}" +minecraft:hopper_minecart,TRUE,FALSE,"gm4_reeling_rods:reeling/minecart {block:'minecraft:hopper'}" +minecraft:tnt_minecart,TRUE,FALSE,"gm4_reeling_rods:reeling/minecart {block:'minecraft:tnt'}" +minecraft:acacia_chest_boat,TRUE,FALSE,"gm4_reeling_rods:reeling/chest_boat/action {boat_type:'minecraft:acacia_boat'}" +minecraft:bamboo_chest_raft,TRUE,FALSE,"gm4_reeling_rods:reeling/chest_boat/action {boat_type:'minecraft:bamboo_raft'}" +minecraft:birch_chest_boat,TRUE,FALSE,"gm4_reeling_rods:reeling/chest_boat/action {boat_type:'minecraft:birch_boat'}" +minecraft:cherry_chest_boat,TRUE,FALSE,"gm4_reeling_rods:reeling/chest_boat/action {boat_type:'minecraft:cherry_boat'}" +minecraft:dark_oak_chest_boat,TRUE,FALSE,"gm4_reeling_rods:reeling/chest_boat/action {boat_type:'minecraft:dark_oak_boat'}" +minecraft:jungle_chest_boat,TRUE,FALSE,"gm4_reeling_rods:reeling/chest_boat/action {boat_type:'minecraft:jungle_boat'}" +minecraft:mangrove_chest_boat,TRUE,FALSE,"gm4_reeling_rods:reeling/chest_boat/action {boat_type:'minecraft:mangrove_boat'}" +minecraft:oak_chest_boat,TRUE,FALSE,"gm4_reeling_rods:reeling/chest_boat/action {boat_type:'minecraft:oak_boat'}" +minecraft:pale_oak_chest_boat,TRUE,FALSE,"gm4_reeling_rods:reeling/chest_boat/action {boat_type:'minecraft:pale_oak_boat'}" +minecraft:spruce_chest_boat,TRUE,FALSE,"gm4_reeling_rods:reeling/chest_boat/action {boat_type:'minecraft:spruce_boat'}" +minecraft:shulker,FALSE,TRUE,"gm4_reeling_rods:hooked_entity/shulker" +minecraft:end_crystal,FALSE,FALSE,"gm4_reeling_rods:hooked_entity/end_crystal" +minecraft:glow_item_frame,FALSE,FALSE,"gm4_reeling_rods:hooked_entity/item_frame {type:'minecraft:glow_item_frame'}" +minecraft:item_frame,FALSE,FALSE,"gm4_reeling_rods:hooked_entity/item_frame {type:'minecraft:item_frame'}" +minecraft:leash_knot,FALSE,FALSE,"gm4_reeling_rods:hooked_entity/leash_knot/action" +minecraft:painting,FALSE,FALSE,"gm4_reeling_rods:hooked_entity/painting" diff --git a/gm4_reeling_rods/generate_files.py b/gm4_reeling_rods/generate_files.py new file mode 100644 index 0000000000..f599decd72 --- /dev/null +++ b/gm4_reeling_rods/generate_files.py @@ -0,0 +1,72 @@ +from beet import Context, Advancement, Function +import math +from pathlib import Path +from gm4.utils import CSV, CSVRow +from itertools import product + +def beet_default(ctx: Context): + """ + - generates set_lookup_table.mcfunction + - generates advancements and reward functions for every bit state of an entity's scoreboard id + - reads csv to ctx.meta for hooked_entity/select_type.mcfunction + """ + create_lookup_file(ctx) + create_bit_advancements(ctx) + + entity_list = CSV.from_file(Path('gm4_reeling_rods','entities.csv')) + dismountable_entities: list[CSVRow] = [] + non_dismountable_entities: list[CSVRow] = [] + for entity_type in entity_list: + if entity_type['can_dismount'].as_bool(): + dismountable_entities.append(entity_type) + continue + non_dismountable_entities.append(entity_type) + ctx.meta['dismountable_entities'] = dismountable_entities + ctx.meta['non_dismountable_entities'] = non_dismountable_entities + +def create_lookup_file(ctx: Context): + ctx.data["gm4_reeling_rods:set_lookup_table"] = Function( + [ + f"scoreboard players set ${key} gm4_reeling_rods.lookup {value}" + for key, value in { + (x**2 + y**2 + z**2): int( + 100 * (0.08 * math.sqrt(math.sqrt(x**2 + y**2 + z**2))) + ) + for x, y, z in product(range(0, 34), range(0, 34), range(0, 34)) + }.items() if math.sqrt(key) <= 33 + ] + ) + +def create_bit_advancements(ctx: Context): + for bit in range(16): + for value in range(2): + ctx.data[f"gm4_reeling_rods:fished/bit_{bit}_{value}"] = Advancement({ + "criteria":{ + "fishing_rod_hooked":{ + "trigger":"minecraft:fishing_rod_hooked", + "conditions":{ + "entity": [ + { + "condition": "minecraft:entity_scores", + "entity": "this", + "scores": { + f"gm4_reeling_rods.id_bit.{bit}": value + } + } + ] + } + } + }, + "rewards":{ + "function": f"gm4_reeling_rods:player/bit_{bit}_{value}" + } + }) + ctx.data[f"gm4_reeling_rods:player/bit_{bit}_{value}"] = Function([ + f"# player adv logic for getting bit {bit} at value {value}. Generated by generate_files.py.", + f"# run from advancement fished/bit_{bit}_{value}\n", + f"advancement revoke @s only gm4_reeling_rods:fished/bit_{bit}_{value}\n", + "execute if entity @s[gamemode=adventure] run return fail\n", + "data modify storage gm4_reeling_rods:temp bit_data set value {bit_score:\"" + f"gm4_reeling_rods.id_bit.{bit}={value}\", bit:\"{bit}\"" + "}", + "data modify storage gm4_reeling_rods:temp bit_data.UUID set from entity @s UUID", + "function gm4_reeling_rods:player/received_bit with storage gm4_reeling_rods:temp bit_data" + ]) diff --git a/gm4_reeling_rods/pack.png b/gm4_reeling_rods/pack.png new file mode 100644 index 0000000000..61680dcdc4 Binary files /dev/null and b/gm4_reeling_rods/pack.png differ diff --git a/gm4_reeling_rods/pack.svg b/gm4_reeling_rods/pack.svg new file mode 100644 index 0000000000..1b652976c7 --- /dev/null +++ b/gm4_reeling_rods/pack.svg @@ -0,0 +1,126 @@ + + + +