Skip to content

Commit

Permalink
[python] add: bindings for the core script api in the nwn1 module
Browse files Browse the repository at this point in the history
  • Loading branch information
jd28 committed Jan 9, 2025
1 parent 9682005 commit ecf7065
Show file tree
Hide file tree
Showing 7 changed files with 235 additions and 5 deletions.
167 changes: 166 additions & 1 deletion docs/fake/rollnw/nwn1.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,172 @@
Waypoint,
)

from typing import Optional, Tuple
from typing import List, Optional, Tuple

# == CORE SCRIPT API ==========================================================
# =============================================================================


def apply_effect(obj: "ObjectBase", effect: "Effect") -> bool:
"""
Applies an effect to an object.
Args:
obj: The object to which the effect is applied.
effect: The effect to apply.
Returns:
bool: True if the effect was successfully applied, False otherwise.
"""
pass


def has_effect_applied(obj: "ObjectBase", type: int, subtype: int = -1) -> bool:
"""
Determines if an effect type is applied to an object.
Args:
obj: The object to check.
type: The type of the effect.
subtype: The subtype of the effect. Defaults to -1.
Returns:
bool: True if the effect type is applied, False otherwise.
"""
pass


def remove_effect(obj: "ObjectBase", effect: "Effect", destroy: bool = True) -> bool:
"""
Removes an effect from an object.
Args:
obj: The object from which the effect is removed.
effect: The effect to remove.
destroy: Whether to destroy the effect after removal. Defaults to True.
Returns:
bool: True if the effect was successfully removed, False otherwise.
"""
pass


def remove_effects_by(obj: "ObjectBase", creator: "ObjectHandle") -> int:
"""
Removes effects by creator.
Args:
obj: The object from which the effects are removed.
creator: The creator of the effects.
Returns:
int: The number of effects removed.
"""
pass


def count_feats_in_range(obj: "Creature", start: int, end: int) -> int:
"""
Counts the number of known feats in the range [start, end].
Args:
obj: The creature to check.
start: The starting feat in the range.
end: The ending feat in the range.
Returns:
int: The number of known feats in the range.
"""
pass


def get_all_available_feats(obj: "Creature") -> List[int]:
"""
Gets all feats for which requirements are met.
Args:
obj: The creature to check.
Returns:
list: A list of feats for which requirements are met.
"""
pass


def has_feat_successor(obj: "Creature", feat: int) -> Tuple[int, int]:
"""
Gets the highest known successor feat.
Args:
obj: The creature to check.
feat: The feat to find a successor for.
Returns:
tuple: A pair of the highest successor feat and an ``int`` representing that the feat is the nth successor.
Returns ``(-1, 0)`` if no successor exists.
"""
pass


def highest_feat_in_range(obj: "Creature", start: int, end: int) -> int:
"""
Gets the highest known feat in range [start, end].
Args:
obj: The creature to check.
start: The starting feat in the range.
end: The ending feat in the range.
Returns:
int: The highest known feat in the range.
"""
pass


def knows_feat(obj: "Creature", feat: int) -> bool:
"""
Checks if an entity knows a given feat.
Args:
obj: The creature to check.
feat: The feat to check.
Returns:
bool: True if the creature knows the feat, False otherwise.
"""
pass


def item_has_property(item: "Item", type: int, subtype: int = -1) -> bool:
"""
Determines if an item has a particular item property.
Args:
item: The item to check.
type: The type of the property.
subtype: The subtype of the property. Defaults to -1.
Returns:
bool: True if the item has the property, False otherwise.
"""
pass


def itemprop_to_string(ip: "ItemProperty") -> str:
"""
Converts an item property to an in-game style string.
Args:
ip: The item property to convert.
Returns:
str: The in-game style string representation of the item property.
"""
pass

# == PROFILE SCRIPT API =======================================================
# =============================================================================


# == Abilities ===============================================================
# ============================================================================
Expand Down
1 change: 1 addition & 0 deletions rollnw-py/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pybind11_add_module(rollnw NO_EXTRAS
glm/glm_util.cpp
glm/wrap_vmath.cpp

wrapper_core_scriptapi.cpp
wrapper_formats.cpp
wrapper_i18n.cpp
wrapper_kernel.cpp
Expand Down
5 changes: 4 additions & 1 deletion rollnw-py/wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ void init_resources(py::module& nw);
void init_rules(py::module& nw);
void init_serialization(py::module& nw);
void init_util(py::module& nw);

void init_kernel(py::module& kernel);
void init_model(py::module& nw);
void init_script(py::module& nw);

void init_core_scriptapi(py::module& m);
void init_nwn1(py::module& m);

PYBIND11_MODULE(rollnw, nw)
Expand All @@ -45,6 +45,9 @@ PYBIND11_MODULE(rollnw, nw)
init_script(script);
py::module model = nw.def_submodule("model");
init_model(model);

// Profiles - NWN1
py::module nwn1 = nw.def_submodule("nwn1");
init_core_scriptapi(nwn1);
init_nwn1(nwn1);
}
30 changes: 30 additions & 0 deletions rollnw-py/wrapper_core_scriptapi.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#include "casters.hpp"

#include "nw/objects/Creature.hpp"
#include "nw/objects/Item.hpp"
#include "nw/objects/ObjectBase.hpp"
#include "nw/rules/Effect.hpp"
#include "nw/rules/items.hpp"
#include "nw/scriptapi.hpp"

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>

namespace py = pybind11;

void init_core_scriptapi(py::module& m)
{
m.def("apply_effect", &nw::apply_effect, py::arg("obj"), py::arg("effect"));
m.def("has_effect_applied", &nw::has_effect_applied, py::arg("obj"), py::arg("type"), py::arg("subtype") = -1);
m.def("remove_effect", &nw::remove_effect, py::arg("obj"), py::arg("effect"), py::arg("destroy") = true);
m.def("remove_effects_by", &nw::remove_effects_by, py::arg("obj"), py::arg("creator"));

m.def("count_feats_in_range", &nw::count_feats_in_range, py::arg("obj"), py::arg("start"), py::arg("end"));
m.def("get_all_available_feats", &nw::get_all_available_feats, py::arg("obj"));
m.def("has_feat_successor", &nw::has_feat_successor, py::arg("obj"), py::arg("feat"));
m.def("highest_feat_in_range", &nw::highest_feat_in_range, py::arg("obj"), py::arg("start"), py::arg("end"));
m.def("knows_feat", &nw::knows_feat, py::arg("obj"), py::arg("feat"));

m.def("item_has_property", &nw::item_has_property, py::arg("item"), py::arg("type"), py::arg("subtype") = -1);
m.def("itemprop_to_string", &nw::itemprop_to_string, py::arg("ip"));
}
32 changes: 31 additions & 1 deletion rollnw-stubs/nwn1.pyi
Original file line number Diff line number Diff line change
@@ -1,6 +1,36 @@
from typing import Any, Tuple
from typing import Any, Tuple, List

import rollnw
from rollnw import Creature, Effect, Item, ItemProperty, ObjectBase, ObjectHandle

# == CORE SCRIPT API ==========================================================
# =============================================================================


def apply_effect(obj: ObjectBase, effect: Effect) -> bool: ...


def has_effect_applied(obj: ObjectBase, type: int,
subtype: int = -1) -> bool: ...
def remove_effect(obj: ObjectBase, effect: Effect,
destroy: bool = True) -> bool: ...


def remove_effects_by(obj: ObjectBase, creator: ObjectHandle) -> int: ...


def count_feats_in_range(obj: Creature, start: int, end: int) -> int: ...
def get_all_available_feats(obj: Creature) -> List[int]: ...
def has_feat_successor(obj: Creature, feat: int) -> Tuple[int, int]: ...
def highest_feat_in_range(obj: Creature, start: int, end: int) -> int: ...
def knows_feat(obj: Creature, feat: int) -> bool: ...


def item_has_property(item: Item, type: int, subtype: int = -1) -> bool: ...
def itemprop_to_string(ip: ItemProperty) -> str: ...

# == PROFILE SCRIPT API =======================================================
# =============================================================================


def base_attack_bonus(arg0: rollnw.Creature) -> int: ...
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def build_extension(self, ext):
preset = "linux"
debug = int(os.environ.get("DEBUG", 0)
) if self.debug is None else self.debug
cfg = "Debug" if debug else "RelWithDebInfo"
cfg = "Debug" if debug else "Release"

cmake_args = [
f"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY={extdir}",
Expand Down
3 changes: 2 additions & 1 deletion tests/test_creature.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import rollnw
from rollnw import Creature, EquipIndex
from rollnw.nwn1 import *
import json
import pytest

Expand Down Expand Up @@ -41,7 +42,7 @@ def test_creature_stats():
assert cre.stats.get_ability_score(0) == 41

# Feats
assert cre.stats.has_feat(105)
assert knows_feat(cre, 105)
assert not cre.stats.add_feat(105)
assert cre.stats.add_feat(1)
assert cre.stats.has_feat(1)
Expand Down

0 comments on commit ecf7065

Please sign in to comment.