2006-04-24 01:14:18 +02:00
|
|
|
#include "stdafx.h"
|
|
|
|
#include "api.h"
|
|
|
|
#include "rmgen.h"
|
|
|
|
#include "random.h"
|
|
|
|
#include "map.h"
|
|
|
|
#include "object.h"
|
|
|
|
#include "convert.h"
|
|
|
|
#include "terrain.h"
|
|
|
|
#include "simpleconstraints.h"
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
|
|
|
// Function specs
|
|
|
|
|
|
|
|
JSFunctionSpec globalFunctions[] = {
|
|
|
|
// {name, native, args}
|
|
|
|
{"init", init, 3},
|
|
|
|
{"initFromScenario", initFromScenario, 2},
|
|
|
|
{"print", print, 1},
|
|
|
|
{"error", error, 1},
|
|
|
|
{"getTexture", getTexture, 2},
|
|
|
|
{"setTexture", setTexture, 3},
|
|
|
|
{"getHeight", getHeight, 2},
|
|
|
|
{"setHeight", setHeight, 3},
|
|
|
|
{"getMapSize", getMapSize, 0},
|
|
|
|
{"randInt", randInt, 2},
|
|
|
|
{"randFloat", randFloat, 1},
|
|
|
|
{"placeObject", placeObject, 4},
|
|
|
|
{"createArea", createArea, 3},
|
|
|
|
{"createObjectGroup", createObjectGroup, 3},
|
|
|
|
{"createTileClass", createTileClass, 0},
|
|
|
|
{0, 0, 0}
|
|
|
|
};
|
|
|
|
|
|
|
|
// Helper function to validate argument types; the types string can contain the following:
|
|
|
|
// i (integers), s (strings), n (numbers), . (anything); for example ValidateArgs("iin",...)
|
|
|
|
// would check that arguments 1 and 2 are integers while the third is a number.
|
|
|
|
void ValidateArgs(const char* types, JSContext* cx, uintN argc, jsval* argv, const char* function) {
|
|
|
|
int num = strlen(types);
|
|
|
|
if(argc != num) {
|
|
|
|
JS_ReportError(cx, "%s: requires %d arguments but got %d", function, num, argc);
|
|
|
|
}
|
|
|
|
JSObject* obj;
|
|
|
|
for(int i=0; i<num; i++) {
|
|
|
|
switch(types[i]) {
|
|
|
|
case 'i':
|
|
|
|
if(!JSVAL_IS_INT(argv[i])) {
|
|
|
|
JS_ReportError(cx, "%s: argument %d must be an integer", function, i+1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 's':
|
|
|
|
if(!JSVAL_IS_STRING(argv[i])) {
|
|
|
|
JS_ReportError(cx, "%s: argument %d must be a string", function, i+1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'n':
|
|
|
|
if(!JSVAL_IS_NUMBER(argv[i])) {
|
|
|
|
JS_ReportError(cx, "%s: argument %d must be an integer", function, i+1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'a':
|
|
|
|
if(!JSVAL_IS_OBJECT(argv[i])) {
|
|
|
|
JS_ReportError(cx, "%s: argument %d must be an array", function, i+1);
|
|
|
|
}
|
|
|
|
obj = JSVAL_TO_OBJECT(argv[i]);
|
|
|
|
if(!JS_IsArrayObject(cx, obj)) {
|
|
|
|
JS_ReportError(cx, "%s: argument %d must be an array", function, i+1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case '*':
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
cerr << "Internal Error: Invalid type passed to ValidateArgs: " << types[i] << "." << endl;
|
|
|
|
Shutdown(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Helper function to check whether map was initialized
|
|
|
|
void CheckInit(bool shouldBeInitialized, JSContext* cx, const char* function) {
|
|
|
|
if(shouldBeInitialized) {
|
|
|
|
if(theMap == 0) {
|
|
|
|
JS_ReportError(cx, "%s: cannot be called before map is initialized", function);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if(theMap != 0) {
|
|
|
|
JS_ReportError(cx, "%s: map was already initialized by an earlier call", function);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// JS API implementation
|
|
|
|
|
|
|
|
JSBool print(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|
|
|
{
|
|
|
|
ValidateArgs("*", cx, argc, argv, __FUNCTION__);
|
|
|
|
|
|
|
|
cout << JS_GetStringBytes(JS_ValueToString(cx, argv[0]));
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
JSBool error(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|
|
|
{
|
|
|
|
ValidateArgs("*", cx, argc, argv, __FUNCTION__);
|
|
|
|
|
|
|
|
JS_ReportError(cx, JS_GetStringBytes(JS_ValueToString(cx, argv[0])));
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
JSBool init(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|
|
|
{
|
|
|
|
CheckInit(false, cx, __FUNCTION__);
|
|
|
|
ValidateArgs("i*n", cx, argc, argv, __FUNCTION__);
|
|
|
|
|
|
|
|
int size = JSVAL_TO_INT(argv[0]);
|
|
|
|
Terrain* baseTerrain = ParseTerrain(cx, argv[1]);
|
|
|
|
if(!baseTerrain) {
|
|
|
|
JS_ReportError(cx, "init: argument 2 must be a terrain");
|
|
|
|
}
|
|
|
|
jsdouble baseHeight;
|
|
|
|
JS_ValueToNumber(cx, argv[2], &baseHeight);
|
|
|
|
|
|
|
|
theMap = new Map(size, baseTerrain, (float) baseHeight);
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
JSBool initFromScenario(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|
|
|
{
|
|
|
|
CheckInit(false, cx, __FUNCTION__);
|
|
|
|
ValidateArgs("si", cx, argc, argv, __FUNCTION__);
|
|
|
|
|
|
|
|
string fileName = JS_GetStringBytes(JSVAL_TO_STRING(argv[0]));
|
|
|
|
int loadObjectLevel = JSVAL_TO_INT(argv[1]);
|
|
|
|
|
|
|
|
theMap = new Map(fileName, loadObjectLevel);
|
|
|
|
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
JSBool getTexture(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|
|
|
{
|
|
|
|
CheckInit(true, cx, __FUNCTION__);
|
|
|
|
ValidateArgs("ii", cx, argc, argv, __FUNCTION__);
|
|
|
|
|
|
|
|
int x = JSVAL_TO_INT(argv[0]);
|
|
|
|
int y = JSVAL_TO_INT(argv[1]);
|
|
|
|
string texture = theMap->getTexture(x, y);
|
|
|
|
*rval = NewJSString(texture);
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
JSBool setTexture(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|
|
|
{
|
|
|
|
CheckInit(true, cx, __FUNCTION__);
|
|
|
|
ValidateArgs("iis", cx, argc, argv, __FUNCTION__);
|
|
|
|
|
|
|
|
int x = JSVAL_TO_INT(argv[0]);
|
|
|
|
int y = JSVAL_TO_INT(argv[1]);
|
|
|
|
char* texture = JS_GetStringBytes(JSVAL_TO_STRING(argv[2]));
|
|
|
|
theMap->setTexture(x, y, texture);
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
JSBool getHeight(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|
|
|
{
|
|
|
|
CheckInit(true, cx, __FUNCTION__);
|
|
|
|
ValidateArgs("ii", cx, argc, argv, __FUNCTION__);
|
|
|
|
|
|
|
|
int x = JSVAL_TO_INT(argv[0]);
|
|
|
|
int y = JSVAL_TO_INT(argv[1]);
|
|
|
|
jsdouble height = theMap->getHeight(x, y);
|
|
|
|
JS_NewDoubleValue(cx, height, rval);
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
JSBool setHeight(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|
|
|
{
|
|
|
|
CheckInit(true, cx, __FUNCTION__);
|
|
|
|
ValidateArgs("iin", cx, argc, argv, __FUNCTION__);
|
|
|
|
|
|
|
|
int x = JSVAL_TO_INT(argv[0]);
|
|
|
|
int y = JSVAL_TO_INT(argv[1]);
|
|
|
|
jsdouble height;
|
|
|
|
JS_ValueToNumber(cx, argv[2], &height);
|
|
|
|
theMap->setHeight(x, y, (float) height);
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
JSBool randInt(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|
|
|
{
|
|
|
|
if(argc!=1 && argc!=2) {
|
|
|
|
JS_ReportError(cx, "randInt: requires 1 or 2 arguments but got %d", argc);
|
|
|
|
}
|
|
|
|
if(!JSVAL_IS_INT(argv[0])) {
|
|
|
|
JS_ReportError(cx, "randInt: argument 1 must be an integer");
|
|
|
|
}
|
|
|
|
if(argc==2 && !JSVAL_IS_INT(argv[1])) {
|
|
|
|
JS_ReportError(cx, "randInt: argument 2 must be an integer");
|
|
|
|
}
|
|
|
|
|
|
|
|
int minVal = argc==1 ? 0 : JSVAL_TO_INT(argv[0]);
|
|
|
|
int maxVal = argc==1 ? JSVAL_TO_INT(argv[0]) : JSVAL_TO_INT(argv[1])-1;
|
|
|
|
if(maxVal < minVal) {
|
|
|
|
JS_ReportError(cx, argc==1 ? "randInt: argument must be positive"
|
|
|
|
: "randInt: argument 2 must be greater than or equal to argument 1");
|
|
|
|
}
|
|
|
|
int r = RandInt(minVal, maxVal);
|
|
|
|
*rval = INT_TO_JSVAL(r);
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
JSBool randFloat(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|
|
|
{
|
|
|
|
if(argc!=0 && argc!=2) {
|
|
|
|
JS_ReportError(cx, "randFloat: requires 0 or 2 arguments but got %d", argc);
|
|
|
|
}
|
|
|
|
|
|
|
|
jsdouble r;
|
|
|
|
|
|
|
|
if(argc==0) {
|
|
|
|
r = RandFloat();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if(!JSVAL_IS_NUMBER(argv[0])) {
|
|
|
|
JS_ReportError(cx, "randFloat: argument 1 must be a number");
|
|
|
|
}
|
|
|
|
if(!JSVAL_IS_NUMBER(argv[1])) {
|
|
|
|
JS_ReportError(cx, "randFloat: argument 2 must be a number");
|
|
|
|
}
|
|
|
|
|
|
|
|
jsdouble minVal, maxVal;
|
|
|
|
JS_ValueToNumber(cx, argv[0], &minVal);
|
|
|
|
JS_ValueToNumber(cx, argv[1], &maxVal);
|
|
|
|
|
|
|
|
if(maxVal < minVal) {
|
|
|
|
JS_ReportError(cx, "randFloat: argument 2 must be greater than or equal to argument 1");
|
|
|
|
}
|
|
|
|
|
|
|
|
r = RandFloat(minVal, maxVal);
|
|
|
|
}
|
|
|
|
|
|
|
|
JS_NewDoubleValue(cx, r, rval);
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
JSBool placeObject(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|
|
|
{
|
|
|
|
CheckInit(true, cx, __FUNCTION__);
|
|
|
|
ValidateArgs("sinnn", cx, argc, argv, __FUNCTION__);
|
|
|
|
|
|
|
|
string type = JS_GetStringBytes(JS_ValueToString(cx, argv[0]));
|
|
|
|
int player = JSVAL_TO_INT(argv[1]);
|
|
|
|
jsdouble x, y, orientation;
|
|
|
|
JS_ValueToNumber(cx, argv[2], &x);
|
|
|
|
JS_ValueToNumber(cx, argv[3], &y);
|
|
|
|
JS_ValueToNumber(cx, argv[4], &orientation);
|
|
|
|
|
|
|
|
theMap->addObject(new Object(type, player, x,y, orientation));
|
|
|
|
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
JSBool placeTerrain(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|
|
|
{
|
|
|
|
CheckInit(true, cx, __FUNCTION__);
|
|
|
|
ValidateArgs("ii*", cx, argc, argv, __FUNCTION__);
|
|
|
|
|
|
|
|
int x = JSVAL_TO_INT(argv[0]);
|
|
|
|
int y = JSVAL_TO_INT(argv[1]);
|
|
|
|
Terrain* terrain = ParseTerrain(cx, argv[2]);
|
|
|
|
if(!terrain) {
|
|
|
|
JS_ReportError(cx, "placeTerrain: invalid terrain argument");
|
|
|
|
}
|
|
|
|
theMap->placeTerrain(x, y, terrain);
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
JSBool createArea(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|
|
|
{
|
|
|
|
CheckInit(true, cx, __FUNCTION__);
|
|
|
|
if(argc != 2 && argc != 3) {
|
|
|
|
JS_ReportError(cx, "createArea: expected 2 or 3 arguments but got %d", argc);
|
|
|
|
}
|
|
|
|
|
|
|
|
AreaPlacer* placer;
|
|
|
|
AreaPainter* painter;
|
|
|
|
Constraint* constr;
|
|
|
|
|
|
|
|
if(!(placer = ParseAreaPlacer(cx, argv[0]))) {
|
|
|
|
JS_ReportError(cx, "createArea: argument 1 must be a valid area placer");
|
|
|
|
}
|
|
|
|
if(!(painter = ParseAreaPainter(cx, argv[1]))) {
|
|
|
|
JS_ReportError(cx, "createArea: argument 2 must be a valid area painter");
|
|
|
|
}
|
|
|
|
if(argc == 3) {
|
|
|
|
if(!(constr = ParseConstraint(cx, argv[2]))) {
|
|
|
|
JS_ReportError(cx, "createArea: argument 3 must be a valid constraint");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
constr = new NullConstraint();
|
|
|
|
}
|
|
|
|
|
|
|
|
Area* area = theMap->createArea(placer, painter, constr);
|
|
|
|
|
|
|
|
delete placer;
|
|
|
|
delete painter;
|
|
|
|
delete constr;
|
|
|
|
|
|
|
|
if(!area) {
|
|
|
|
*rval = INT_TO_JSVAL(0);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
*rval = INT_TO_JSVAL(theMap->areas.size());
|
|
|
|
}
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
JSBool createObjectGroup(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|
|
|
{
|
|
|
|
CheckInit(true, cx, __FUNCTION__);
|
|
|
|
if(argc != 2 && argc != 3) {
|
|
|
|
JS_ReportError(cx, "createObjectGroup: expected 1 or 2 arguments but got %d", argc);
|
|
|
|
}
|
|
|
|
|
|
|
|
ObjectGroupPlacer* placer;
|
|
|
|
Constraint* constr;
|
|
|
|
|
|
|
|
if(!(placer = ParseObjectGroupPlacer(cx, argv[0]))) {
|
|
|
|
JS_ReportError(cx, "createObjectGroup: argument 1 must be a valid object group placer");
|
|
|
|
}
|
|
|
|
if(!JSVAL_IS_INT(argv[1])) {
|
|
|
|
JS_ReportError(cx, "createObjectGroup: argument 2 must be a valid player number");
|
|
|
|
}
|
|
|
|
|
|
|
|
if(argc == 3) {
|
|
|
|
if(!(constr = ParseConstraint(cx, argv[2]))) {
|
|
|
|
JS_ReportError(cx, "createObjectGroup: argument 3 must be a valid constraint");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
constr = new NullConstraint();
|
|
|
|
}
|
|
|
|
|
|
|
|
int player = JSVAL_TO_INT(argv[1]);
|
|
|
|
|
|
|
|
bool ret = theMap->createObjectGroup(placer, player, constr);
|
|
|
|
|
|
|
|
delete placer;
|
|
|
|
delete constr;
|
|
|
|
|
|
|
|
*rval = BOOLEAN_TO_JSVAL(ret);
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
JSBool createTileClass(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|
|
|
{
|
|
|
|
CheckInit(true, cx, __FUNCTION__);
|
|
|
|
if(argc != 0) {
|
|
|
|
JS_ReportError(cx, "createTileClass: expected 0 arguments but got %d", argc);
|
|
|
|
}
|
|
|
|
|
|
|
|
int id = theMap->createTileClass();
|
|
|
|
|
|
|
|
*rval = INT_TO_JSVAL(id);
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
JSBool getMapSize(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|
|
|
{
|
|
|
|
CheckInit(true, cx, __FUNCTION__);
|
|
|
|
if(argc != 0) {
|
|
|
|
JS_ReportError(cx, "getMapSize: expected 0 arguments but got %d", argc);
|
|
|
|
}
|
|
|
|
|
|
|
|
*rval = INT_TO_JSVAL(theMap->size);
|
|
|
|
return JS_TRUE;
|
|
|
|
}
|