|  | 
| 8 | 8 | 
 | 
| 9 | 9 | import re | 
| 10 | 10 | import math | 
|  | 11 | +import inspect | 
| 11 | 12 | 
 | 
| 12 | 13 | if TYPE_CHECKING: | 
| 13 | 14 |     from . import ManualWorld | 
| @@ -93,7 +94,8 @@ def checkRequireStringForArea(state: CollectionState, area: dict): | 
| 93 | 94 | 
 | 
| 94 | 95 |             if not callable(func): | 
| 95 | 96 |                 raise ValueError(f"Invalid function `{func_name}` in {area}.") | 
| 96 |  | - | 
|  | 97 | +            if func_args: | 
|  | 98 | +                convert_req_function_args(func, func_args, area["name"]) | 
| 97 | 99 |             result = func(world, multiworld, state, player, *func_args) | 
| 98 | 100 |             if isinstance(result, bool): | 
| 99 | 101 |                 requires_list = requires_list.replace("{" + func_name + "(" + item[1] + ")}", "1" if result else "0") | 
| @@ -271,6 +273,51 @@ def allRegionsAccessible(state): | 
| 271 | 273 |     # Victory requirement | 
| 272 | 274 |     multiworld.completion_condition[player] = lambda state: state.has("__Victory__", player) | 
| 273 | 275 | 
 | 
|  | 276 | +    def convert_req_function_args(func, args: list[str], areaName: str): | 
|  | 277 | +        parameters = inspect.signature(func).parameters | 
|  | 278 | +        knownArguments = ["world", "multiworld", "state", "player"] | 
|  | 279 | +        index = 0 | 
|  | 280 | +        for parameter, info in parameters.items(): | 
|  | 281 | +            if parameter in knownArguments: | 
|  | 282 | +                continue | 
|  | 283 | + | 
|  | 284 | +            argType = info.annotation | 
|  | 285 | +            try: | 
|  | 286 | +                value = args[index].strip().lower() | 
|  | 287 | + | 
|  | 288 | +            except IndexError: | 
|  | 289 | +                if info is not inspect.Parameter.empty: | 
|  | 290 | +                    value = info.default | 
|  | 291 | + | 
|  | 292 | +                else: | 
|  | 293 | +                    raise Exception(f"A call of the {func.__name__} function in '{areaName}'s requirement, asks for a value of type {argType}\nfor its argument '{info.name}' but its missing") | 
|  | 294 | + | 
|  | 295 | +            if not isinstance(value, argType): | 
|  | 296 | +                if issubclass(argType, bool): | 
|  | 297 | +                    #Special conversion to bool | 
|  | 298 | +                    if value in ['true', '1']: | 
|  | 299 | +                        value = True | 
|  | 300 | + | 
|  | 301 | +                    elif value in ['false', '0']: | 
|  | 302 | +                        value = False | 
|  | 303 | + | 
|  | 304 | +                    else: | 
|  | 305 | +                        # warning here spam the console, might be worth to make it a data validation instead | 
|  | 306 | +                        # logging.warn(f"A function in '{areaName}'s requirement, asks for a value of type {argType}\nfor its argument '{info.name}' but an unknown string was passed") | 
|  | 307 | +                        value = bool(value) | 
|  | 308 | + | 
|  | 309 | +                else: | 
|  | 310 | +                    try: | 
|  | 311 | +                        value = argType(value) | 
|  | 312 | + | 
|  | 313 | +                    except ValueError: | 
|  | 314 | +                        raise Exception(f"A call of the {func.__name__} function in '{areaName}'s requirement, asks for a value of type {argType}\nfor its argument '{info.name}' but its value '{value}' cannot be converted to {argType}") | 
|  | 315 | + | 
|  | 316 | +                args[index] = value | 
|  | 317 | + | 
|  | 318 | +            index += 1 | 
|  | 319 | + | 
|  | 320 | + | 
| 274 | 321 | def YamlEnabled(world: "ManualWorld", multiworld: MultiWorld, state: CollectionState, player: int, param: str) -> bool: | 
| 275 | 322 |     """Is a yaml option enabled?""" | 
| 276 | 323 |     return is_option_enabled(multiworld, player, param) | 
|  | 
0 commit comments