148 lines
4.1 KiB
C++
148 lines
4.1 KiB
C++
|
|
#include "PyFOV.h"
|
||
|
|
#include "McRFPy_API.h"
|
||
|
|
|
||
|
|
// Static storage for cached enum class reference
|
||
|
|
PyObject* PyFOV::fov_enum_class = nullptr;
|
||
|
|
|
||
|
|
PyObject* PyFOV::create_enum_class(PyObject* module) {
|
||
|
|
// Import IntEnum from enum module
|
||
|
|
PyObject* enum_module = PyImport_ImportModule("enum");
|
||
|
|
if (!enum_module) {
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
PyObject* int_enum = PyObject_GetAttrString(enum_module, "IntEnum");
|
||
|
|
Py_DECREF(enum_module);
|
||
|
|
if (!int_enum) {
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Create dict of enum members
|
||
|
|
PyObject* members = PyDict_New();
|
||
|
|
if (!members) {
|
||
|
|
Py_DECREF(int_enum);
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Add all FOV algorithm members
|
||
|
|
struct {
|
||
|
|
const char* name;
|
||
|
|
int value;
|
||
|
|
} fov_members[] = {
|
||
|
|
{"BASIC", FOV_BASIC},
|
||
|
|
{"DIAMOND", FOV_DIAMOND},
|
||
|
|
{"SHADOW", FOV_SHADOW},
|
||
|
|
{"PERMISSIVE_0", FOV_PERMISSIVE_0},
|
||
|
|
{"PERMISSIVE_1", FOV_PERMISSIVE_1},
|
||
|
|
{"PERMISSIVE_2", FOV_PERMISSIVE_2},
|
||
|
|
{"PERMISSIVE_3", FOV_PERMISSIVE_3},
|
||
|
|
{"PERMISSIVE_4", FOV_PERMISSIVE_4},
|
||
|
|
{"PERMISSIVE_5", FOV_PERMISSIVE_5},
|
||
|
|
{"PERMISSIVE_6", FOV_PERMISSIVE_6},
|
||
|
|
{"PERMISSIVE_7", FOV_PERMISSIVE_7},
|
||
|
|
{"PERMISSIVE_8", FOV_PERMISSIVE_8},
|
||
|
|
{"RESTRICTIVE", FOV_RESTRICTIVE},
|
||
|
|
{"SYMMETRIC_SHADOWCAST", FOV_SYMMETRIC_SHADOWCAST},
|
||
|
|
};
|
||
|
|
|
||
|
|
for (const auto& m : fov_members) {
|
||
|
|
PyObject* value = PyLong_FromLong(m.value);
|
||
|
|
if (!value) {
|
||
|
|
Py_DECREF(members);
|
||
|
|
Py_DECREF(int_enum);
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
if (PyDict_SetItemString(members, m.name, value) < 0) {
|
||
|
|
Py_DECREF(value);
|
||
|
|
Py_DECREF(members);
|
||
|
|
Py_DECREF(int_enum);
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
Py_DECREF(value);
|
||
|
|
}
|
||
|
|
|
||
|
|
// Call IntEnum("FOV", members) to create the enum class
|
||
|
|
PyObject* name = PyUnicode_FromString("FOV");
|
||
|
|
if (!name) {
|
||
|
|
Py_DECREF(members);
|
||
|
|
Py_DECREF(int_enum);
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
// IntEnum(name, members) using functional API
|
||
|
|
PyObject* args = PyTuple_Pack(2, name, members);
|
||
|
|
Py_DECREF(name);
|
||
|
|
Py_DECREF(members);
|
||
|
|
if (!args) {
|
||
|
|
Py_DECREF(int_enum);
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
PyObject* fov_class = PyObject_Call(int_enum, args, NULL);
|
||
|
|
Py_DECREF(args);
|
||
|
|
Py_DECREF(int_enum);
|
||
|
|
|
||
|
|
if (!fov_class) {
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Cache the reference for fast type checking
|
||
|
|
fov_enum_class = fov_class;
|
||
|
|
Py_INCREF(fov_enum_class);
|
||
|
|
|
||
|
|
// Add to module
|
||
|
|
if (PyModule_AddObject(module, "FOV", fov_class) < 0) {
|
||
|
|
Py_DECREF(fov_class);
|
||
|
|
fov_enum_class = nullptr;
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
return fov_class;
|
||
|
|
}
|
||
|
|
|
||
|
|
int PyFOV::from_arg(PyObject* arg, TCOD_fov_algorithm_t* out_algo, bool* was_none) {
|
||
|
|
if (was_none) *was_none = false;
|
||
|
|
|
||
|
|
// Accept None -> caller should use default
|
||
|
|
if (arg == Py_None) {
|
||
|
|
if (was_none) *was_none = true;
|
||
|
|
*out_algo = FOV_BASIC;
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Accept FOV enum member (check if it's an instance of our enum)
|
||
|
|
if (fov_enum_class && PyObject_IsInstance(arg, fov_enum_class)) {
|
||
|
|
// IntEnum members have a 'value' attribute
|
||
|
|
PyObject* value = PyObject_GetAttrString(arg, "value");
|
||
|
|
if (!value) {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
long val = PyLong_AsLong(value);
|
||
|
|
Py_DECREF(value);
|
||
|
|
if (val == -1 && PyErr_Occurred()) {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
*out_algo = (TCOD_fov_algorithm_t)val;
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Accept int (for backwards compatibility)
|
||
|
|
if (PyLong_Check(arg)) {
|
||
|
|
long val = PyLong_AsLong(arg);
|
||
|
|
if (val == -1 && PyErr_Occurred()) {
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
if (val < 0 || val >= NB_FOV_ALGORITHMS) {
|
||
|
|
PyErr_Format(PyExc_ValueError,
|
||
|
|
"Invalid FOV algorithm value: %ld. Must be 0-%d or use mcrfpy.FOV enum.",
|
||
|
|
val, NB_FOV_ALGORITHMS - 1);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
*out_algo = (TCOD_fov_algorithm_t)val;
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
PyErr_SetString(PyExc_TypeError,
|
||
|
|
"FOV algorithm must be mcrfpy.FOV enum member, int, or None");
|
||
|
|
return 0;
|
||
|
|
}
|