2005-05-23 05:51:37 +02:00
|
|
|
#include "stdafx.h"
|
|
|
|
#include "objparse.h"
|
|
|
|
#include "rmgen.h"
|
2005-06-06 09:46:28 +02:00
|
|
|
#include "simpleconstraints.h"
|
|
|
|
#include "simplepainters.h"
|
|
|
|
#include "rectplacer.h"
|
|
|
|
#include "layeredpainter.h"
|
|
|
|
#include "clumpplacer.h"
|
2005-05-23 05:51:37 +02:00
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
|
|
|
bool GetRaw(JSContext* cx, jsval val, JSObject** retObj, int* retType) {
|
2005-06-06 09:46:28 +02:00
|
|
|
if(!JSVAL_IS_OBJECT(val)) return false;
|
2005-05-23 05:51:37 +02:00
|
|
|
JSObject* obj = JSVAL_TO_OBJECT(val);
|
|
|
|
jsval ret;
|
|
|
|
if(!JS_CallFunctionName(cx, obj, "raw", 0, 0, &ret)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if(!JSVAL_IS_OBJECT(ret)) return false;
|
|
|
|
*retObj = JSVAL_TO_OBJECT(ret);
|
|
|
|
if(!JS_IsArrayObject(cx, *retObj)) return false;
|
|
|
|
jsuint len;
|
|
|
|
JS_GetArrayLength(cx, *retObj, &len);
|
|
|
|
if(len==0) return false;
|
|
|
|
jsval rval;
|
|
|
|
JS_GetElement(cx, *retObj, 0, &rval);
|
|
|
|
if(!JSVAL_IS_INT(rval)) return 0;
|
|
|
|
*retType = JSVAL_TO_INT(rval);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ParseFields(JSContext* cx, JSObject* array, const char* format, ...) {
|
|
|
|
int len = strlen(format);
|
|
|
|
jsuint arLen;
|
|
|
|
JS_GetArrayLength(cx, array, &arLen);
|
|
|
|
if(arLen != len+1) return false;
|
|
|
|
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, format); // start at next arg after format
|
|
|
|
|
|
|
|
for(int i=0; i<len; i++)
|
|
|
|
{
|
|
|
|
jsval val;
|
|
|
|
JS_GetElement(cx, array, i+1, &val);
|
|
|
|
|
|
|
|
if(format[i] == 'i') {
|
|
|
|
int* r = va_arg(ap, int*);
|
|
|
|
if(!JSVAL_IS_INT(val)) return false;
|
|
|
|
*r = JSVAL_TO_INT(val);
|
|
|
|
}
|
|
|
|
else if(format[i] == 'n') {
|
|
|
|
float* r = va_arg(ap, float*);
|
|
|
|
if(!JSVAL_IS_NUMBER(val)) return false;
|
|
|
|
jsdouble jsd;
|
|
|
|
JS_ValueToNumber(cx, val, &jsd);
|
|
|
|
*r = jsd;
|
|
|
|
}
|
|
|
|
else if(format[i] == 's') {
|
|
|
|
string* r = va_arg(ap, string*);
|
|
|
|
if(!JSVAL_IS_STRING(val)) return false;
|
|
|
|
*r = JS_GetStringBytes(JS_ValueToString(cx, val));
|
|
|
|
}
|
|
|
|
else if(format[i] == '*') {
|
|
|
|
jsval* r = va_arg(ap, jsval*);
|
|
|
|
*r = val;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2005-06-06 09:46:28 +02:00
|
|
|
cerr << "Internal Error: unsupported type '" << format[i] << "' for ParseFields!\n";
|
2005-05-23 05:51:37 +02:00
|
|
|
Shutdown(1);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
va_end(ap);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2005-06-06 09:46:28 +02:00
|
|
|
bool ParseArray(JSContext* cx, jsval val, vector<jsval>& ret) {
|
|
|
|
ret.clear();
|
|
|
|
if(!JSVAL_IS_OBJECT(val)) return false;
|
|
|
|
JSObject* obj = JSVAL_TO_OBJECT(val);
|
|
|
|
if(!JS_IsArrayObject(cx, obj)) return false;
|
|
|
|
jsuint len;
|
|
|
|
JS_GetArrayLength(cx, obj, &len);
|
|
|
|
for(int i=0; i<len; i++) {
|
|
|
|
jsval rval;
|
|
|
|
JS_GetElement(cx, obj, i, &rval);
|
|
|
|
ret.push_back(rval);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
AreaPainter* ParsePainter(JSContext* cx, jsval val) {
|
|
|
|
JSObject* obj; int type;
|
|
|
|
if(!GetRaw(cx, val, &obj, &type)) return 0;
|
|
|
|
|
|
|
|
jsval jsv, jsv2;
|
|
|
|
Terrain* terrain = 0;
|
|
|
|
vector<jsval> array;
|
|
|
|
vector<Terrain*> terrains;
|
|
|
|
vector<int> widths;
|
|
|
|
|
|
|
|
switch(type) {
|
|
|
|
case TYPE_TERRAINPAINTER:
|
|
|
|
if(!ParseFields(cx, obj, "*", &jsv)) return 0;
|
|
|
|
terrain = ParseTerrain(cx, jsv);
|
|
|
|
if(terrain==0) return 0;
|
|
|
|
return new TerrainPainter(terrain);
|
|
|
|
|
|
|
|
case TYPE_LAYEREDPAINTER:
|
|
|
|
if(!ParseFields(cx, obj, "**", &jsv, &jsv2)) return 0;
|
|
|
|
if(!ParseArray(cx, jsv, array)) return 0;
|
|
|
|
for(int i=0; i<array.size(); i++) {
|
|
|
|
if(!JSVAL_IS_INT(array[i])) return 0;
|
|
|
|
widths.push_back(JSVAL_TO_INT(array[i]));
|
|
|
|
}
|
|
|
|
if(!ParseArray(cx, jsv2, array)) return 0;
|
|
|
|
for(int i=0; i<array.size(); i++) {
|
|
|
|
terrain = ParseTerrain(cx, array[i]);
|
|
|
|
if(terrain==0) return 0;
|
|
|
|
terrains.push_back(terrain);
|
|
|
|
}
|
|
|
|
if(terrains.size() != 1+widths.size()) return 0;
|
|
|
|
return new LayeredPainter(terrains, widths);
|
|
|
|
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-05-23 05:51:37 +02:00
|
|
|
AreaPlacer* ParsePlacer(JSContext* cx, jsval val) {
|
|
|
|
JSObject* obj; int type;
|
|
|
|
if(!GetRaw(cx, val, &obj, &type)) return 0;
|
|
|
|
|
2005-06-06 09:46:28 +02:00
|
|
|
jsval jsv;
|
|
|
|
int x, y, x1, y1, x2, y2, num, maxFail;
|
2005-06-07 09:21:55 +02:00
|
|
|
float size, coherence, smoothness;
|
2005-05-23 05:51:37 +02:00
|
|
|
|
|
|
|
switch(type) {
|
|
|
|
case TYPE_RECTPLACER:
|
2005-06-06 09:46:28 +02:00
|
|
|
if(!ParseFields(cx, obj, "iiii", &x1, &y1, &x2, &y2)) return 0;
|
2005-05-23 05:51:37 +02:00
|
|
|
return new RectPlacer(x1, y1, x2, y2);
|
2005-06-06 09:46:28 +02:00
|
|
|
|
|
|
|
case TYPE_CLUMPPLACER:
|
2005-06-07 09:21:55 +02:00
|
|
|
if(!ParseFields(cx, obj, "nnnii", &size, &coherence, &smoothness, &x, &y)) return 0;
|
|
|
|
return new ClumpPlacer(size, coherence, smoothness, x, y);
|
2005-06-06 09:46:28 +02:00
|
|
|
|
2005-05-23 05:51:37 +02:00
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Constraint* ParseConstraint(JSContext* cx, jsval val) {
|
|
|
|
if(JSVAL_IS_NULL(val)) return new NullConstraint();
|
|
|
|
|
|
|
|
JSObject* obj; int type;
|
|
|
|
if(!GetRaw(cx, val, &obj, &type)) return 0;
|
|
|
|
|
2005-06-06 09:46:28 +02:00
|
|
|
int areaId;
|
|
|
|
string texture;
|
|
|
|
jsval jsv, jsv2;
|
|
|
|
Constraint* c1, *c2;
|
|
|
|
|
2005-05-23 05:51:37 +02:00
|
|
|
switch(type) {
|
|
|
|
case TYPE_NULLCONSTRAINT:
|
2005-06-06 09:46:28 +02:00
|
|
|
if(!ParseFields(cx, obj, "")) return 0;
|
2005-05-23 05:51:37 +02:00
|
|
|
return new NullConstraint();
|
2005-06-06 09:46:28 +02:00
|
|
|
|
|
|
|
case TYPE_AVOIDAREACONSTRAINT:
|
|
|
|
if(!ParseFields(cx, obj, "i", &areaId)) return 0;
|
|
|
|
if(areaId <= 0 || areaId > theMap->areas.size()) return 0;
|
|
|
|
return new AvoidAreaConstraint(theMap->areas[areaId-1]);
|
|
|
|
|
|
|
|
case TYPE_AVOIDTERRAINCONSTRAINT:
|
|
|
|
if(!ParseFields(cx, obj, "s", &texture)) return 0;
|
|
|
|
return new AvoidTerrainConstraint(theMap->getId(texture));
|
|
|
|
|
|
|
|
case TYPE_ANDCONSTRAINT:
|
|
|
|
if(!ParseFields(cx, obj, "**", &jsv, &jsv2)) return 0;
|
|
|
|
if(!(c1 = ParseConstraint(cx, jsv))) return 0;
|
|
|
|
if(!(c2 = ParseConstraint(cx, jsv2))) return 0;
|
|
|
|
return new AndConstraint(c1, c2);
|
|
|
|
|
2005-05-23 05:51:37 +02:00
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
2005-06-06 09:46:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Terrain* ParseTerrain(JSContext* cx, jsval val) {
|
|
|
|
if(JSVAL_IS_STRING(val)) {
|
|
|
|
// simple terrains are just encoded as strings
|
|
|
|
string str = JS_GetStringBytes(JS_ValueToString(cx, val));
|
|
|
|
return SimpleTerrain::parse(str);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// complex terrain type
|
|
|
|
JSObject* obj; int type;
|
|
|
|
if(!GetRaw(cx, val, &obj, &type)) return 0;
|
|
|
|
|
|
|
|
jsval jsv;
|
|
|
|
Terrain* terrain = 0;
|
|
|
|
vector<jsval> array;
|
|
|
|
vector<Terrain*> terrains;
|
|
|
|
|
|
|
|
switch(type) {
|
|
|
|
case TYPE_RANDOMTERRAIN:
|
|
|
|
if(!ParseFields(cx, obj, "*", &jsv)) return 0;
|
|
|
|
if(!ParseArray(cx, jsv, array)) return 0;
|
|
|
|
for(int i=0; i<array.size(); i++) {
|
|
|
|
terrain = ParseTerrain(cx, array[i]);
|
|
|
|
if(terrain==0) return 0;
|
|
|
|
terrains.push_back(terrain);
|
|
|
|
}
|
|
|
|
return new RandomTerrain(terrains);
|
|
|
|
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2005-05-23 05:51:37 +02:00
|
|
|
}
|