Пример #1
0
/// Rotate a 2d vector around (0, 0) by a specified angle.
// @function rotate2d
// @tparam number pos_x the x coordinate of the vector to be rotated
// @tparam number pos_y the y coordinate of the vector to be rotated
// @tparam number angle the angle by which the vector should be rotated
// @treturn number the X coordinate of the rotated vector
// @treturn number the Y coordinate of the rotated vector
int luafuncs_vector_rotate2d(lua_State* l) {
    const char func[] = "vector.rotate2d";
    if (lua_type(l, 1) != LUA_TNUMBER) {
        return haveluaerror(l, badargument1, 1, func, "number",
        lua_strtype(l, 1));
    }
    if (lua_type(l, 2) != LUA_TNUMBER) {
        return haveluaerror(l, badargument1, 2, func, "number",
        lua_strtype(l, 2));
    }
    if (lua_type(l, 3) != LUA_TNUMBER) {
        return haveluaerror(l, badargument1, 3, func, "number",
        lua_strtype(l, 3));
    }
    double x = lua_tonumber(l, 1);
    double y = lua_tonumber(l, 2);
    if (x == 0 && y == 0) {
        lua_pushnumber(l, 0);
        lua_pushnumber(l, 0);
        return 2;
    }
    double angle = lua_tonumber(l, 3);
    rotatevec(x, y, angle, &x, &y);
    lua_pushnumber(l, x);
    lua_pushnumber(l, y);
    return 2;
}
Пример #2
0
/// Set the mass and the center of an object. Only applicable for
// objects with movable collision enabled. (objects with static
// collision have infinite mass since they're not movable)
// @function setMass
// @tparam number mass Set the mass of the object in kilograms. You should experiment and pick mass here which works well for you (it shouldn't be very small or very large), rather than using the most truthful numbers.
// @tparam number mass_center_x (optional) Set the x coordinate of the mass center (default: 0)
// @tparam number mass_center_y (optional) Set the y coordinate of the mass center (default: 0)
// @tparam number mass_center_z (optional) Set the z coordinate of the mass center (default: 0)
int luafuncs_setMass(lua_State* l) {
    struct blitwizardobject* obj = toblitwizardobject(l, 1, 0,
    "blitwizard.object:setMass");
    if (obj->deleted) {
        lua_pushstring(l, "Object was deleted");
        return lua_error(l);
    }
    if (!obj->physics || !obj->physics->object) {
        lua_pushstring(l, "Object has no shape");
        return lua_error(l);
    }
    if (!obj->physics->movable) {
        lua_pushstring(l, "Mass can be only set on movable objects");
        return lua_error(l);
    }
    if (lua_gettop(l) < 2 || lua_type(l, 2) != LUA_TNUMBER || lua_tonumber(l, 2) <= 0) {
        return haveluaerror(l, badargument1, 1, "blitwizard.object:setMass",
        "number", lua_strtype(l, 2));
    }
    double centerx = 0;
    double centery = 0;
    double centerz = 0;
    double mass = lua_tonumber(l, 2);
    if (lua_gettop(l) >= 3 && lua_type(l, 3) != LUA_TNIL) {
        if (lua_type(l, 3) != LUA_TNUMBER) {
            return haveluaerror(l, badargument1, 2, "blitwizard.object:setMass",
            "number", lua_strtype(l, 3));
        }
        centerx = lua_tonumber(l, 3);

        if (lua_type(l, 4) != LUA_TNUMBER) {
            return haveluaerror(l, badargument1, 3, "blitwizard.object:setMass",
            "number", lua_strtype(l, 4));
        }
        centery = lua_tonumber(l, 4);

        if (lua_type(l, 5) != LUA_TNUMBER) {
            return haveluaerror(l, badargument1, 4, "blitwiz.object:setMass", "number", lua_strtype(l, 5));
        }
        centerz = lua_tonumber(l, 5);
    }
    physics_SetMass(obj->physics->object, mass);
    if (obj->is3d) {
        physics_Set3dMassCenterOffset(obj->physics->object,
        centerx, centery, centerz);
    } else {
        physics_Set2dMassCenterOffset(obj->physics->object,
        centerx, centery);
    }
    return 0;
}
Пример #3
0
/// Restrict the ability to rotate for a given object. For 2d, the rotation
// can be totally restricted or not, for 3d it can be restricted around a specific
// axis (e.g. like a door), completely (object can not rotate at all), or not at all.
//
// For 2d and complete 3d restriction, specify 'true'. For no restriction, 'false'.
//
// For 3d restriction around a specific axis (only available for 3d objects obviously),
// specify 3 coordinates for an axis direction vector, then optionally an additional 3 coordinates
// for the point where the axis should go through (if not specified the object's center).
// @function restrictRotation
// @tparam number/boolean total_or_axis_x Specify true or false for either full restriction or none, or the first coordinate of an axis
// @tparam number axis_y If the first parameter was the first coordinate of an axis, specify the second here
// @tparam number axis_z If the first parameter was the first coordinate of an axis, specify the third here
// @tparam number axis_point_x (optional) If you want to specify a point the axis goes through, specify its x coordinate here
// @tparam number axis_point_y (optional) y coordinate
// @tparam number axis_point_z (optional) z coordinate
int luafuncs_restrictRotation(lua_State* l) {
    char func[] = "blitwizard.object:restrictRotation";
    struct blitwizardobject* obj = toblitwizardobject(l, 1, 0,
    "blitwizard.object:restrictRotation");
    if (obj->deleted) {
        lua_pushstring(l, "Object was deleted");
        return lua_error(l);
    }
    if (!obj->physics || !obj->physics->object) {
        lua_pushstring(l, "Object has no shape");
        return lua_error(l);
    }
    if (!obj->is3d) {
        if (lua_type(l, 2) != LUA_TBOOLEAN) {
            lua_pushstring(l, "Second parameter is not a valid rotation restriction boolean");
            return lua_error(l);
        }
        if (!obj->physics->movable) {
            lua_pushstring(l, "Rotation restriction can be only set on movable objects");
            return lua_error(l);
        }
        obj->physics->rotationrestriction2d = lua_toboolean(l, 2);
        applyobjectsettings(obj);
    } else {
        if (lua_type(l, 2) != LUA_TBOOLEAN && lua_type(l, 2) != LUA_TNUMBER) {
            return haveluaerror(l, badargument2, 1, func, "string or number", lua_strtype(l, 2));
        }
        if (!obj->physics->movable) {
            return haveluaerror(l, "Rotation restriction can only be set on movable objects");
        }
        if (lua_type(l, 2) == LUA_TBOOLEAN) {
            obj->physics->rotationrestriction3dfull = lua_toboolean(l, 2);
            obj->physics->rotationrestriction3daxis = 0;
        } else {
            if (lua_type(l, 3) != LUA_TNUMBER) {
                return haveluaerror(l, badargument2, 2, func, "number", lua_strtype(l, 3));
            }
            if (lua_type(l, 4) != LUA_TNUMBER) {
                return haveluaerror(l, badargument2, 3, func, "number", lua_strtype(l, 3));
            }
            obj->physics->rotationrestriction3dfull = 0;
            obj->physics->rotationrestriction3daxis = 1;
            obj->physics->rotationrestriction3daxisx = lua_tonumber(l, 2);
            obj->physics->rotationrestriction3daxisy = lua_tonumber(l, 3);
            obj->physics->rotationrestriction3daxisz = lua_tonumber(l, 4);
        }
        applyobjectsettings(obj);
    }
    return 0;
}
Пример #4
0
/// Set a gravity vector onto an object with movable collision enabled
// (see @{object:enableMovableCollision|object:enableMovableCollision}).
// If no parameters are provided,
// the object gravity will be removed again.
// Please note you would normally want to use
// @{blitwizard.physics.set2dGravity|blitwizard.physics.set2dGravity} or
// @{blitwizard.physics.set3dGravity|blitwizard.physics.set3dGravity}
// instead.
// @function setGravity
// @tparam number gravity_x x coordinate of gravity vector
// @tparam number gravity_y y coordinate of gravity vector
// @tparam number gravity_z (only for 3d objects) z coordinate of gravity vector
int luafuncs_setGravity(lua_State* l) {
    struct blitwizardobject* obj = toblitwizardobject(l, 1, 0,
    "blitwizard.object:restrictRotation");
    if (obj->deleted) {
        lua_pushstring(l, "Object was deleted");
        return lua_error(l);
    }
    if (!obj->physics || !obj->physics->object) {
        lua_pushstring(l, "Object has no shape");
        return lua_error(l);
    }

    int set = 0;
    double gx,gy,gz;

    // if the necessary amount of vector coordinates is given,
    // set new gravity vector:
    if ((!obj->is3d && lua_gettop(l) >= 3 && lua_type(l, 3) != LUA_TNIL) ||
    (obj->is3d && lua_gettop(l) >= 4 && lua_type(l, 4) != LUA_TNIL)) {
        if (lua_type(l, 2) != LUA_TNUMBER) {
            return haveluaerror(l, badargument1, 1,
            "blitwizard.object:setGravity", "number", lua_strtype(l, 2));
        }
        if (lua_type(l, 3) != LUA_TNUMBER) {
            return haveluaerror(l, badargument1, 2,
            "blitwizard.object:setGravity", "number", lua_strtype(l, 3));
        }
        if (obj->is3d && lua_type(l, 4) != LUA_TNUMBER) {
            return haveluaerror(l, badargument1, 3,
            "blitwizard.object:setGravity", "number", lua_strtype(l, 4));
        }
        gx = lua_tonumber(l, 2);
        gy = lua_tonumber(l, 3);
        if (obj->is3d) {
            gz = lua_tonumber(l, 4);
        }
        set = 1;
    }
    if (set) {
        if (obj->is3d) {
            physics_Set3dGravity(obj->physics->object, gx, gy, gz);
        } else {
            physics_Set2dGravity(obj->physics->object, gx, gy);
        }
    } else {
        physics_UnsetGravity(obj->physics->object);
    }
    return 0;
}
Пример #5
0
/// Get the size of the camera in game units (so the size of the
// visible world area it shows).
//
// consider_zoom = false gives you the area of
// @{blitwizard.object:pinToCamera|pinned objects} which the camera
// shows, which is not influenced by zoom. (this is the default if
// consider_zoom is no specified at all)
//
// consider_zoom = true is a special case useful for 2d,
// which gives you the camera's dimensions according to the current
// zoom factor.
//
// The result of this function depends on the camera's
// @{blitwizard.graphics.camera:getPixelDimensionsOnScreen|
// actual size in pixels on the screen}, the camera's
// @{blitwizard.graphics.camera:get2dZoomFactor|
// 2d zoom factor} (for consider_zoom set to true) and the camera's
// @{blitwizard.graphics.camera:get2dAspectRatio|
// 2d aspect ratio}.
//
// <i>Note on @{blitwizard.object:pinToCamera|pinned} 2d objects:</i>
// If you want to know the area visible in game units for
// @{blitwizard.object:pinToCamera|pinned objects} which are unaffected
// by camera zoom when drawn, specify <i>false</i> as first parameter
// for not taking the zoom into account.
// @function getDimensions
// @tparam boolean consider_zoom (optional) defaults to false.
// Specifies whether the 2d zoom factor should be taken into account.
// Set to <i>true</i> if yes, <i>false</i> if not.
// @treturn number width the width of the camera in game units
// @treturn number height the height of the camera in game units
int luafuncs_camera_getDimensions(lua_State* l) {
    struct luacameralistentry* e = toluacameralistentry(
                                       l, 1, 0, "blitwizard.graphics.camera:getDimensions");

    // if the camera default unit -> pixel conversion size isn't known yet:
    if (!unittopixelsset) {
        return haveluaerror(l, "this function is unavailable before the "
                            "first blitwizard.graphics.setMode call");
    }

    int considerzoom = 0;
    // get consider_zoom parameter:
    if (lua_gettop(l) >= 2 && lua_type(l, 2) != LUA_TNIL) {
        if (lua_type(l, 2) != LUA_TBOOLEAN) {
            return haveluaerror(l, badargument1, 1,
                                "blitwizard.graphics.camera:"
                                "getDimensions", "boolean", lua_strtype(l, 2));
        }
        considerzoom = lua_toboolean(l, 2);
    }

    // return visible area dimensions:
    // FIXME: take aspect ratio into account once it can be changed
    double w = graphics_getCameraWidth(e->cameraslot);
    double h = graphics_getCameraHeight(e->cameraslot);
    double z = graphics_getCamera2DZoom(e->cameraslot);
    if (!considerzoom) {
        z = 1;
    }
    lua_pushnumber(l, (w/UNIT_TO_PIXELS) * z);
    lua_pushnumber(l, (h/UNIT_TO_PIXELS) * z);
    return 2;
}
Пример #6
0
/// Check if a given path to a file or directory exists
// (it points to a valid file or directory).
// Returns true if that is the case, or false if not.
// @function exists
// @tparam string path file or directory path
// @treturn boolean true if target exists, false if not
int luafuncs_exists(lua_State *l) {
    const char *p = lua_tostring(l, 1);
    if (!p) {
        return haveluaerror(l, badargument1, 1, "os.exists", "string", lua_strtype(l, 1));
    }
    if (file_doesFileExist(p)) {
        lua_pushboolean(l, 1);
    } else {
#ifdef USE_PHYSFS
        char *path = file_getAbsolutePathFromRelativePath(p);
        if (!path) {
            return haveluaerror(l, "allocation failed");
        }
        file_makeSlashesCrossplatform(path);
        file_removeDoubleSlashes(path);
        file_makePathRelative(path, main_getRunDir()); 

        if (file_IsPathRelative(path)) {
            if (resources_locateResource(path, NULL)) {
                free(path);
                lua_pushboolean(l, 1);
                return 1;
            }
        }
        free(path);
#endif
        lua_pushboolean(l, 0);
    }
    return 1;
}
Пример #7
0
/// Set the camera's 2d center which is the position in the 2d world
// centered by the camera. This allows you to move the camera's shown
// part of the 2d world around, focussing on other places.
//
// The position is specified in <b>game units</b> (the same units used
// for specifying the @{blitwizard.object:setPosition|position of objects}).
// The camera initially looks at position 0, 0.
//
// If you want the camera to follow a 2d object, simply use this function
// to set the 2d center to the coordinates of the object (you can do this
// in the object's @{blitwizard.object:doAlways|doAlways} function).
// @function set2dCenter
// @tparam number x_position X position of the 2d point to look at
// @tparam number y_position Y position of the 2d point to look at
// @usage
// -- make the default camera look at position 3, 3:
// local camera = blitwizard.graphics.getCameras()[1]
// camera:set2dCenter(3, 3)
int luafuncs_camera_set2dCenter(lua_State* l) {
    struct luacameralistentry* e = toluacameralistentry(
                                       l, 1, 0, "blitwizard.graphics.camera:set2dCenter");
    if (lua_type(l, 2) != LUA_TNUMBER) {
        return haveluaerror(l, badargument1, 1,
                            "blitwizard.graphics.camera:set2dCenter", "number",
                            lua_strtype(l, 2));
    }
    if (lua_type(l, 3) != LUA_TNUMBER) {
        return haveluaerror(l, badargument1, 2,
                            "blitwizard.graphics.camera:set3dCenter", "number",
                            lua_strtype(l, 3));
    }
    graphics_setCamera2DCenterXY(e->cameraslot, lua_tonumber(l, 2),
                                 lua_tonumber(l, 3));
    return 0;
}
Пример #8
0
/// Set the dimensions of a camera on the screen.
// @function setPixelDimensionsOnScreen
// @tparam number width Width of the camera on the screen in pixels
// @tparam number height Height of the camera on the screen in pixels
int luafuncs_camera_setPixelDimensionsOnScreen(lua_State* l) {
#ifdef USE_SDL_GRAPHICS
    return haveluaerror(l, "the SDL renderer doesn't support resizing "
                        "cameras");
#else
    struct luacameralistentry* e = toluacameralistentry(
                                       l, 1, 0, "blitwizad.graphics.camera:setPixelDimensionsOnScreen");
    if (lua_type(l, 2) != LUA_TNUMBER) {
        return haveluaerror(l, badargument1, 1, "blitwizard.graphics.camera:"
                            "setPixelDimensionsOnScreen", "number", lua_strtype(l, 2));
    }
    if (lua_type(l, 3) != LUA_TNUMBER) {
        return haveluaerror(l, badargument1, 2, "blitwizard.graphics.camera:"
                            "setPixelDimensionsOnScreen", "number", lua_strtype(l, 3));
    }
    graphics_setCameraSize(e->cameraslot, lua_tonumber(l, 2),
                           lua_tonumber(l, 3));
    return 0;
#endif
}
Пример #9
0
/// Create a new blitwizard object which is represented as a 2d or
// 3d object in the game world.
// 2d objects are on a separate 2d plane, and 3d objects are inside
// the 3d world.
// Objects can have behaviour and collision info attached and move
// around. They are what eventually makes the action in your game!
// @function new
// @tparam boolean 3d specify 'true' if you wish this object to be a 3d object, or 'false' if you want it to be a flat 2d object
// @tparam string resource (optional) if you specify the file path to a resource here (optional), this resource will be loaded and used as a visual representation for the object. The resource must be a supported graphical object, e.g. an image (.png) or a 3d model (.mesh). You can also specify nil here if you don't want any resource to be used.
// @tparam function behaviour (optional) the behaviour function which will be executed immediately after object creation.
// @treturn userdata Returns a @{blitwizard.object|blitwizard object}
int luafuncs_object_new(lua_State* l) {
    // first argument needs to be 2d/3d boolean:
    if (lua_type(l, 1) != LUA_TBOOLEAN) {
        return haveluaerror(l, badargument1, 1, "blitwizard.object:new",
        "boolean", lua_strtype(l, 1));
    }
    int is3d = lua_toboolean(l, 1);

    // second argument, if present, needs to be the resource:
    const char* resource = NULL;
    if (lua_gettop(l) >= 2 && lua_type(l, 2) != LUA_TNIL) {
        if (lua_type(l, 2) != LUA_TSTRING) {
            return haveluaerror(l, badargument1, 2, "blitwizard.object:new",
            "string", lua_strtype(l, 2));
        }
        resource = lua_tostring(l, 2);
    }

    // create new object
    struct blitwizardobject* o = malloc(sizeof(*o));
    if (!o) {
        return haveluaerror(l, "Failed to allocate new object");
    }
    memset(o, 0, sizeof(*o));
    o->is3d = is3d;

    // add us to the object list:
    o->next = objects;
    if (objects) {
        objects->prev = o;
    }
    objects = o;

    // if resource is present, start loading it:
    luafuncs_objectgraphics_load(o, resource);
    return 0;
}
Пример #10
0
/// Set the 2d zoom factor. Only the 2d layer will be affected.
//
// A large zoom factor will zoom into the details of the scene,
// a small zoom factor will show more surroundings from a larger distance.
// (e.g. 2 means twice as large, 0.5 means half as large)
// @function set2dZoomFactor
// @tparam number zoom_factor the new zoom factor
int luafuncs_camera_set2dZoomFactor(lua_State* l) {
    struct luacameralistentry* e = toluacameralistentry(
                                       l, 1, 0, "blitwizard.graphics.camera:set2dZoomFactor");
    if (lua_type(l, 2) != LUA_TNUMBER) {
        return haveluaerror(l, badargument1, 1,
                            "blitwizard.graphics.camera:set2dZoomFactor",
                            "number", lua_strtype(l, 2));
    }
    if (lua_tonumber(l, 2) <= 0) {
        return haveluaerror(l, badargument2, 1,
                            "blitwizard.graphics.camera:set2dZoomFactor",
                            "zoom factor is zero or negative");
    }
    graphics_setCamera2DZoom(e->cameraslot, lua_tonumber(l, 2));
    return 0;
}
Пример #11
0
/// Set the surface friction on the given object.
// Only useful on objects with collision enabled.
// @function setFriction
// @tparam number friction Friction value from 0 to 1 (0 is no friction, 1 is full friction)
int luafuncs_setFriction(lua_State* l) {
    struct blitwizardobject* obj = toblitwizardobject(l, 1, 0,
    "blitwizard.object:setFriction");
    if (obj->deleted) {
        lua_pushstring(l, "Object was deleted");
        return lua_error(l);
    }
    if (lua_type(l, 2) != LUA_TNUMBER) {
        return haveluaerror(l, badargument1, 1,
        "blitwizard.object:setFriction",
        "number", lua_strtype(l, 2));
    }
    obj->physics->friction = lua_tonumber(l, 2);
    applyobjectsettings(obj);
    return 0;
}
Пример #12
0
/// Check if a given path to a file or directory exists
// (it points to a valid file or directory).
// Returns true if that is the case, or false if not.
// @function exists
// @tparam string path file or directory path
// @treturn boolean true if target exists, false if not
int luafuncs_exists(lua_State* l) {
    const char* p = lua_tostring(l, 1);
    if (!p) {
        return haveluaerror(l, badargument1, 1, "os.exists", "string", lua_strtype(l, 1));
    }
    if (file_DoesFileExist(p)) {
        lua_pushboolean(l, 1);
    } else {
#ifdef USE_PHYSFS
        if (resources_LocateResource(p, NULL)) {
            lua_pushboolean(l, 1);
            return 1;
        }
#endif
        lua_pushboolean(l, 0);
    }
    return 1;
}
Пример #13
0
struct blitwizardobject* toblitwizardobject(lua_State* l, int index, int arg, const char* func) {
    if (lua_type(l, index) != LUA_TUSERDATA) {
        haveluaerror(l, badargument1, arg, func, "blitwizard object", lua_strtype(l, index));
    }
    if (lua_rawlen(l, index) != sizeof(struct luaidref)) {
        haveluaerror(l, badargument2, arg, func, "not a valid blitwizard object");
    }
    struct luaidref* idref = lua_touserdata(l, index);
    if (!idref || idref->magic != IDREF_MAGIC
    || idref->type != IDREF_BLITWIZARDOBJECT) {
        haveluaerror(l, badargument2, arg, func, "not a valid blitwizard object");
    }
    struct blitwizardobject* o = idref->ref.bobj;
    if (o->deleted) {
        haveluaerror(l, badargument2, arg, func, "this blitwizard object was deleted");
    }
    return o;
}
Пример #14
0
struct luacameralistentry* toluacameralistentry(lua_State* l,
        int index, int arg, const char* func) {
    if (lua_type(l, index) != LUA_TUSERDATA) {
        haveluaerror(l, badargument1, arg, func, "camera",
                     lua_strtype(l, index));
    }
    if (lua_rawlen(l, index) != sizeof(struct luaidref)) {
        haveluaerror(l, badargument2, arg, func, "not a valid camera");
        return NULL;
    }
    struct luaidref* idref = lua_touserdata(l, index);
    if (!idref || idref->magic != IDREF_MAGIC
            || idref->type != IDREF_CAMERA) {
        haveluaerror(l, badargument2, arg, func, "not a valid camera");
        return NULL;
    }
    struct luacameralistentry* c = idref->ref.camera;
    if (c->cameraslot < 0) {
        haveluaerror(l, badargument2, arg, func, "this camera was deleted");
        return NULL;
    }
    return c;
}
Пример #15
0
/// Specify a 2d position in the range from 0,0 to
// w,h with w,h being the camera visible area size
// as from @{blitwizard.graphics.camera:getDimensions|
// getDimensions} with consider_zoom set to <b>false</b>.
//
// (So the position you specify is the coordinates a
// @{blitwizard.object:pinToCamera|pinned object} would have on screen
// or the coordinates you get from @{blitwizard.onMouseMove})
//
// The position can also be smaller than 0,0 or larger than the
// actual camera dimensions, in which case you'll get an out-of-screen
// world position as a result.
// @function screenPosTo2dWorldPos
// @tparam number pos_x the X coordinate of the screen position
// @tparam number pos_y the Y coordinate of the screen position
// @tparam number parallax (optional) if you want, specify the @{blitwizard.object:setParallax|parallax} effect strength to get the world position displaced accordingly for an object with that parallax effect strength
// @treturn number X coordinate of the resulting world position
// @treturn number Y coordinate of the resulting world position
int luafuncs_camera_screenPosTo2dWorldPos(lua_State* l) {
    struct luacameralistentry* e = toluacameralistentry(
                                       l, 1, 0, "blitwizard.graphics.camera:screenPosTo2dWorldPos");

    if (lua_type(l, 2) != LUA_TNUMBER) {
        return haveluaerror(l, badargument1, 1,
                            "blitwizard.graphics.camera:screenPosTo2dWorldPos", "number", lua_strtype(l, 2));
    }
    if (lua_type(l, 3) != LUA_TNUMBER) {
        return haveluaerror(l, badargument1, 2,
                            "blitwizard.graphics.camera:screenPosTo2dWorldPos", "number", lua_strtype(l, 3));
    }
    double parallax = 1;
    if (lua_gettop(l) >= 4 && lua_type(l, 4) != LUA_TNIL) {
        if (lua_type(l, 4) != LUA_TNUMBER) {
            return haveluaerror(l, badargument1, 3,
                                "blitwizard.graphics.camera:screenPosTo2dWorldPos", "number", lua_strtype(l, 4));
        }
        if (lua_tonumber(l, 4) <= 0) {
            return haveluaerror(l, badargument2, 3,
                                "blitwizard.graphics.camera:screenPosTo2dWorldPos",
                                "parallax effect strength needs to be greater than zero");
        }
        parallax = lua_tonumber(l, 4);
    }
    double x = lua_tonumber(l, 2);
    double y = lua_tonumber(l, 3);

    // calculate camera top left world position:
    double tx = graphics_getCamera2DCenterX(e->cameraslot);
    double ty = graphics_getCamera2DCenterY(e->cameraslot);
    double zoomscale =
        (UNIT_TO_PIXELS * graphics_getCamera2DZoom(e->cameraslot))
        / (double)UNIT_TO_PIXELS_DEFAULT;
    double cameraWidth = graphics_getCameraWidth(e->cameraslot)
                         / (double)UNIT_TO_PIXELS;
    double cameraHeight = graphics_getCameraHeight(e->cameraslot)
                          / (double)UNIT_TO_PIXELS;
    tx -= (cameraWidth / zoomscale) * 0.5f;
    ty -= (cameraHeight / zoomscale) * 0.5f;

    // apply parallax effect as desired with screen center as parallax center:
    x -= cameraWidth / 2;
    y -= cameraHeight / 2;
    x /= parallax;
    y /= parallax;
    x += cameraWidth / 2;
    y += cameraHeight / 2;

    // the onscreen coordinates need to be translated into "zoomed" space:
    x /= graphics_getCamera2DZoom(e->cameraslot);
    y /= graphics_getCamera2DZoom(e->cameraslot);

    lua_pushnumber(l, tx + x);
    lua_pushnumber(l, ty + y);
    return 2;
}
Пример #16
0
/// Returns a table array containing all the file names of the
// files in the specified directory.
//
// <b>Important</b>: this function lists both files from actual directories on
// hard disk, and virtual directories loaded through
// @{blitwizard.loadResourceArchive|loaded zip resource archives}.
// Virtual files will take precedence over real files (you won't
// receive duplicates).
//
// If you don't want virtual files listed (e.g. because you want
// to examine any directory supplied by the user and not part of your
// project)
// @function ls
// @tparam string directory path, empty string ("") for current directory
// @tparam boolean virtual_files (optional) Specify true to list virtual files inside virtual directories aswell (the default behaviour), false to list only files in the actual file system on disk
// @usage
//   -- list all files in current directory:
//   for i,file in ipairs(os.ls("")) do
//       print("file name: " .. file)
//   end
int luafuncs_ls(lua_State *l) {
    const char *p = lua_tostring(l, 1);
    if (!p) {
        lua_pushstring(l, "First argument is not a valid path string");
        return lua_error(l);
    }
    char *pnative = file_getAbsolutePathFromRelativePath(p);
    char *pcross = strdup(pnative);
    char *pcrossResourceDir = strdup(pnative);
    if (!pnative || !pcross || !pcrossResourceDir) {
        free(pnative);
        free(pcross);
        free(pcrossResourceDir);
        return haveluaerror(l, "failed to allocate file paths");
    }
    file_makeSlashesNative(pnative);
    file_makeSlashesCrossplatform(pcross);
    file_makePathRelative(pcrossResourceDir, main_getRunDir());
    if (!file_IsPathRelative(pcrossResourceDir)) {
        free(pcrossResourceDir);
        pcrossResourceDir = NULL;
    }
    
    // check parameter if we want to list internal zip stuff or not:
    int list_virtual = 1;
    if (lua_gettop(l) >= 2 && lua_type(l, 2) != LUA_TNIL) {
        if (lua_type(l, 2) != LUA_TNUMBER) {
            free(pnative);
            free(pcross);
            free(pcrossResourceDir);
            return haveluaerror(l, badargument1, 2, "os.ls", "boolean or nil",
            lua_strtype(l, 2));
        }
        list_virtual = lua_toboolean(l, 2);
    }

    // get virtual filelist:
    char **filelist = NULL;
#ifdef USE_PHYSFS
    if (list_virtual && pcrossResourceDir) {
        filelist = resource_getFileList(pcrossResourceDir);
        //printf("got filelist for %s: %p\n", pcrossrelative, filelist);
        char **p = filelist;
        if (p) {
            while (*p) {
                assert(strlen(*p) <= 512);
                assert(*p[0] >= 32);
                p++;
            }
        }
    }
#endif

    // get iteration context for "real" on disk directory:
    struct filelistcontext *ctx = filelist_Create(pnative);

    if (!ctx && (!list_virtual || !filelist)) {
        char errmsg[500];
        snprintf(errmsg, sizeof(errmsg), "failed to ls folder: %s", pnative);
        errmsg[sizeof(errmsg)-1] = 0;
        lua_pushstring(l, errmsg);
        free(pnative);
        free(pcross);
        free(pcrossResourceDir);
        if (filelist) {
            size_t i = 0;
            while (filelist[i]) {
                free(filelist[i]);
                i++;
            }
            free(filelist);
        }
        return lua_error(l);
    }

    // create file listing table
    lua_newtable(l);

    // add all files/folders to file listing table
    char filenamebuf[500];
    int isdir;
    int returnvalue = 0;
    unsigned int i = 0;
    // loop through all files:
    if (ctx) {
        while ((returnvalue = filelist_GetNextFile(ctx,
                filenamebuf, sizeof(filenamebuf), &isdir)) == 1) {
            i++;
            lua_checkstack(l, 3);

            int duplicate = 0;
            // if we list against virtual folders too,
            // check for this being a duplicate:
            if (filelist) {
                unsigned int i2 = 0;
                while (filelist[i2]) {
                    if (strcasecmp(filelist[i2], filenamebuf) == 0) {
                        duplicate = 1;
                        break;
                    }
                    i2++;
                }
            }
            if (duplicate) {
                // don't add this one.
                i--;
                continue;
            }
            lua_pushinteger(l, i);
            lua_pushstring(l, filenamebuf);
            lua_settable(l, -3);
        }

        // free file list
        filelist_Free(ctx);
    }

    if (filelist) {
        // add file list to table:
        i = 0;
        while (filelist[i]) {
            lua_pushinteger(l, i + 1);
            lua_pushstring(l, filelist[i]);
            lua_settable(l, -3);
            i++;
        }

        // free virtual file list:
        i = 0;
        while (filelist[i]) {
            free(filelist[i]);
            i++;
        }
        free(filelist);
    }

    // process error during listing
    if (returnvalue < 0) {
        lua_pop(l, 1); // remove file listing table

        char errmsg[500];
        snprintf(errmsg, sizeof(errmsg),
            "Error while processing ls in folder: %s", pnative);
        errmsg[sizeof(errmsg)-1] = 0;
        lua_pushstring(l, errmsg);
        free(pnative);
        free(pcross);
        free(pcrossResourceDir);
        return lua_error(l);
    }

    // return file list
    free(pnative);
    free(pcross);
    free(pcrossResourceDir);
    return 1;
}
Пример #17
0
/// Returns a table array containing all the file names of the
// files in the specified directory.
//
// <b>Important</b>: this function lists both files from actual directories on
// hard disk, and virtual directories loaded through
// @{blitwizard.loadResourceArchive|loaded zip resource archives}.
// Virtual files will take precedence over real files (you won't
// receive duplicates).
//
// If you don't want virtual files listed (e.g. because you want
// to examine any directory supplied by the user and not part of your
// project)
// @function ls
// @tparam string directory path, empty string ("") for current directory
// @tparam boolean virtual_files (optional) Specify true to list virtual files inside virtual directories aswell (the default behaviour), false to list only files in the actual file system on disk
// @usage
//   -- list all files in current directory:
//   for i,file in ipairs(os.ls("")) do
//       print("file name: " .. file)
//   end
int luafuncs_ls(lua_State* l) {
    const char* p = lua_tostring(l, 1);
    if (!p) {
        lua_pushstring(l, "First argument is not a valid path string");
        return lua_error(l);
    }
    int list_virtual = 1;
    if (lua_gettop(l) >= 2 && lua_type(l, 2) != LUA_TNIL) {
        if (lua_type(l, 2) != LUA_TNUMBER) {
            return haveluaerror(l, badargument1, 2, "os.ls", "boolean or nil",
            lua_strtype(l, 2));
        }
        list_virtual = lua_toboolean(l, 2);
    }

    // get virtual filelist:
    char** filelist = NULL;
#ifdef USE_PHYSFS
    if (list_virtual) {
        filelist = resource_FileList(p);
    }
#endif

    // get iteration context for "real" on disk directory:
    struct filelistcontext* ctx = filelist_Create(p);

    if (!ctx && (!list_virtual || !filelist)) {
        char errmsg[500];
        snprintf(errmsg, sizeof(errmsg), "Failed to ls folder: %s", p);
        errmsg[sizeof(errmsg)-1] = 0;
        lua_pushstring(l, errmsg);
        return lua_error(l);
    }

    // create file listing table
    lua_newtable(l);

    // add all files/folders to file listing table
    char filenamebuf[500];
    int isdir;
    int returnvalue;
    int i = 0;
    // loop through all files:
    while ((returnvalue = filelist_GetNextFile(ctx,
    filenamebuf, sizeof(filenamebuf), &isdir)) == 1) {
        i++;
        lua_checkstack(l, 3);

        int duplicate = 0;
        // if we list against virtual folders too,
        // check for this being a duplicate:
        if (filelist) {
            size_t i = 0;
            while (filelist[i]) {
                if (strcasecmp(filelist[i], filenamebuf) == 0) {
                    duplicate = 1;
                    break;
                }
                i++;
            }
        }
        if (duplicate) {
            // don't add this one.
            i--;
            continue;
        }
        lua_pushinteger(l, i);
        lua_pushstring(l, filenamebuf);
        lua_settable(l, -3);
    }

    // free file list
    filelist_Free(ctx);

    // free virtual file list:
    if (filelist) {
        size_t i = 0;
        while (filelist[i]) {
            free(filelist[i]);
            i++;
        }
        free(filelist);
    }

    // process error during listing
    if (returnvalue < 0) {
        lua_pop(l, 1); // remove file listing table

        char errmsg[500];
        snprintf(errmsg, sizeof(errmsg), "Error while processing ls in folder: %s", p);
        errmsg[sizeof(errmsg)-1] = 0;
        lua_pushstring(l, errmsg);
        return lua_error(l);
    }

    // return file list
    return 1;
}
Пример #18
0
int luafuncs_ray(lua_State* l, int use3d) {
    char func[64];
    if (use3d) {
        strcpy(func, "blitwizard.physics.ray3d");
    } else {
        strcpy(func, "blitwizard.physics.ray2d");
    }
    if (lua_type(l, 1) != LUA_TNUMBER) {
        return haveluaerror(l, badargument1, 1, func, "number",
        lua_strtype(l, 1));
    }
    if (lua_type(l, 2) != LUA_TNUMBER) {
        lua_pushstring(l, "Second parameter is not a valid start y position");
        return lua_error(l);
    }
    if (use3d) {
        if (lua_type(l, 3) != LUA_TNUMBER) {
            lua_pushstring(l, "Fourth parameter is not a valid start z position");
            return lua_error(l);
        }
    }
    if (lua_type(l, 3 + use3d) != LUA_TNUMBER) {
        lua_pushstring(l, "Third parameter is not a valid target x position");
        return lua_error(l);
    }
    if (lua_type(l, 4 + use3d) != LUA_TNUMBER) {
        lua_pushstring(l, "Fourth parameter is not a valid target y position");
        return lua_error(l);
    }
    if (use3d) {
        if (lua_type(l, 6) != LUA_TNUMBER) {
            lua_pushstring(l, "Fourth parameter is not a valid target z position");
            return lua_error(l);
        }
    }

    double startx = lua_tonumber(l, 1);
    double starty = lua_tonumber(l, 2);
    double startz;
    if (use3d) {
        startz = lua_tonumber(l, 3);
    }
    double targetx = lua_tonumber(l, 3+use3d);
    double targety = lua_tonumber(l, 4+use3d);
    double targetz;
    if (use3d) {
        targetz = lua_tonumber(l, 6);
    }

    struct physicsobject* obj;
    double hitpointx,hitpointy,hitpointz;
    double normalx,normaly,normalz;

    int returnvalue;
    if (use3d) {
        returnvalue = physics_Ray3d(main_DefaultPhysics2dPtr(),
        startx, starty, startz,
        targetx, targety, targetz,
        &hitpointx, &hitpointy, &hitpointz,
        &obj,
        &normalx, &normaly, &normalz);
    } else {
        returnvalue = physics_Ray2d(main_DefaultPhysics2dPtr(),
        startx, starty,
        targetx, targety,
        &hitpointx, &hitpointy,
        &obj,
        &normalx, &normaly);
    }

    if (returnvalue) {
        // create a new reference to the (existing) object the ray has hit:
        luafuncs_pushbobjidref(l, (struct blitwizardobject*)physics_GetObjectUserdata(obj));

        // push the other information we also want to return:
        lua_pushnumber(l, hitpointx);
        lua_pushnumber(l, hitpointy);
        if (use3d) {
            lua_pushnumber(l, hitpointz);
        }
        lua_pushnumber(l, normalx);
        lua_pushnumber(l, normaly);
        if (use3d) {
            lua_pushnumber(l, normalz);
        }
        return 5+2*use3d;  // return it all
    }
    lua_pushnil(l);
    return 1;
}
Пример #19
0
/// Apply a physics impulse onto an object (which will make it move,
// for example as if someone had pushed it).
// This will only work if the object has movable collision enabled through @{object:enableMovableCollision|object:enableMovableCollision}.
// IMPORTANT: Some parameters are not present for 2d objects, see list below.
// @function impulse
// @tparam number source_x the x source coordinate from where the push will be given
// @tparam number source_y the y source coordinate
// @tparam number source_z (parameter only present for 3d objects) the z source coordinate
// @tparam number force_x the x coordinate of the force vector applied through the impulse
// @tparam number force_y the y coordinate of the force vector
// @tparam number force_z (parameter only present for 3d objects) the z coordinate of the force vector
int luafuncs_impulse(lua_State* l) {
    struct blitwizardobject* obj = toblitwizardobject(l, 1, 0,
    "blitwizard.object:impulse");
    char funcname[] = "blitwizard.object.impulse";
    if (obj->deleted) {
        lua_pushstring(l, "Object was deleted");
        return lua_error(l);
    }
    if (!obj->physics || !obj->physics->object) {
        lua_pushstring(l, "Object has no shape");
        return lua_error(l);
    }
    if (!obj->physics->movable) {
        lua_pushstring(l, "Impulse can be only applied to movable objects");
        return lua_error(l);
    }
    if (lua_type(l, 2) != LUA_TNUMBER) {  // source x
        return haveluaerror(l, badargument1, 1, funcname, "number",
        lua_strtype(l, 2));
    }
    if (lua_type(l, 3) != LUA_TNUMBER) {  // source y
        return haveluaerror(l, badargument1, 2, funcname, "number",
        lua_strtype(l, 3));
    }
    if (obj->is3d) {
        if (lua_type(l, 4) != LUA_TNUMBER) {  // source z
            return haveluaerror(l, badargument1, 3, funcname,
            "number", lua_strtype(l, 4));
        }
    }
    if (lua_type(l, 4+obj->is3d) != LUA_TNUMBER) { // force x
        return haveluaerror(l, badargument1, 3+obj->is3d, funcname, "number",
        lua_strtype(l, 4+obj->is3d));
    }
    if (lua_type(l, 5+obj->is3d) != LUA_TNUMBER) { // force y
        return haveluaerror(l, badargument1, 4+obj->is3d, funcname, "number",
        lua_strtype(l, 5+obj->is3d));
    }
    if (obj->is3d) {
        if (lua_type(l, 7) != LUA_TNUMBER) { // force z
            return haveluaerror(l, badargument1, 6, funcname, "number",
            lua_strtype(l, 7));
        }
    }
    double sourcex,sourcey,sourcez;
    double forcex, forcey, forcez;
    sourcex = lua_tonumber(l, 2);
    sourcey = lua_tonumber(l, 3);
    sourcez = 0;
    if (obj->is3d) {
        sourcez = lua_tonumber(l, 4);
    }
    forcex = lua_tonumber(l, 4+obj->is3d);
    forcey = lua_tonumber(l, 5+obj->is3d);
    if (obj->is3d) {
        forcez = lua_tonumber(l, 7);
    }
    if (obj->is3d) {
        physics_Apply3dImpulse(obj->physics->object,
        forcex, forcey, forcez, sourcex, sourcey, sourcez);
    } else {
        physics_Apply2dImpulse(obj->physics->object,
        forcex, forcey, sourcex, sourcez);
    }
    return 0;
}
Пример #20
0
int luafuncs_enableCollision(lua_State* l, int movable) {
    struct blitwizardobject* obj = toblitwizardobject(l, 1, 1,
    "blitwizard.object:enableCollision");

    if (obj->deleted) {
        lua_pushstring(l, "Object was deleted");
        return lua_error(l);
    }

    // validate: parameters need to be a list of shape info tables
    int argcount = lua_gettop(l)-1;
    if (argcount <= 0) {
        return haveluaerror(l, badargument1, 2,
        "blitwizard.object:enableCollision", "table", "nil");
    } else {
        // check for args to be a table
        int i = 0;
        while (i < argcount) {
            if (lua_type(l, 2+i) != LUA_TTABLE &&
            lua_type(l, 2+i) != LUA_TNIL) {
                if (i == 0) {
                    return haveluaerror(l, badargument1, 2+i,
                    "blitwizard.object:enableCollision", "table",
                    lua_strtype(l, 2+i));
                } else {
                    return haveluaerror(l, badargument1, 2+i,
                    "blitwizard.object:enableCollision", "table or nil",
                    lua_strtype(l, 2+i));
                }
            }
            i++;
        }
    }

    // construct a shape list from the given shape tables:
    struct physicsobjectshape* shapes =
    physics_CreateEmptyShapes(argcount);
    int i = 0;
    while (i < argcount) {
        lua_pushstring(l, "type");
        lua_gettable(l, 2+i);
        if (lua_type(l, -1) != LUA_TSTRING) {
            physics_DestroyShapes(shapes, argcount);
            return haveluaerror(l, badargument2, 2+i,
            "blitwizard.object:enableCollision",
            "shape has invalid type: expected string");
        } else {
            // check the shape type being valid:
            const char* shapetype = lua_tostring(l, -1);
            if (obj->is3d) {
                // see if this is a usable 3d shape:
                int isok = 0;
                if (strcmp(shapetype, "decal") == 0) {
                    isok = 1;
                    // flat 3d decal with width and height
                    int width,height;
                    lua_pushstring(l, "width");
                    lua_gettable(l, 2+i);
                    if (lua_type(l, -1) != LUA_TNUMBER) {
                        physics_DestroyShapes(shapes, argcount);
                        return haveluaerror(l, badargument2, 2+i,
                        "blitwizard.object:enableCollision",
                        "shape \"decal\" needs \"width\" specified"
                        " as a number");
                    }
                    width = lua_tonumber(l, -1);
                    lua_pop(l, 1);
                    lua_pushstring(l, "height");
                    lua_gettable(l, 2+i);
                    if (lua_type(l, -1) != LUA_TNUMBER) {
                        physics_DestroyShapes(shapes, argcount);
                        return haveluaerror(l, badargument2, 2+i,
                        "blitwizard.object:enableCollision",
                        "shape \"decal\" needs \"height\" specified"
                        " as a number");
                    }
                    height = lua_tonumber(l, -1);
                    lua_pop(l, 1);
                    physics_Set3dShapeDecal(GET_SHAPE(shapes, i),
                    width, height);
                }
                if (strcmp(shapetype, "ball") == 0) {
                    isok = 1;
                    // 3d ball with diameter
                    int diameter;
                    lua_pushstring(l, "diameter");
                    lua_gettable(l, 2+i);
                    if (lua_type(l, -1) != LUA_TNUMBER) {
                        physics_DestroyShapes(shapes, argcount);
                        return haveluaerror(l, badargument2, 2+i,
                        "blitwizard.object:enableCollision",
                        "shape \"ball\" needs \"diameter\" specified"
                        " as a number");
                    }
                    diameter = lua_tonumber(l, -1);
                    lua_pop(l, 1);
                    physics_Set3dShapeBall(GET_SHAPE(shapes, i),
                    diameter);
                }
                if (strcmp(shapetype, "box") == 0 ||
                strcmp(shapetype, "elliptic ball") == 0) {
                    isok = 1;
                    // box or elliptic ball with x/y/z_size
                    int x_size,y_size,z_size;
                    lua_pushstring(l, "x_size");
                    lua_gettable(l, 2+i);
                    if (lua_type(l, -1) != LUA_TNUMBER) {
                        physics_DestroyShapes(shapes, argcount);
                        return haveluaerror(l, badargument2, 2+i,
                        "blitwizard.object:enableCollision",
                        "shape \"box\" or \"elliptic ball\" needs"
                        " \"x_size\" specified as a number");
                    }
                    x_size = lua_tonumber(l, -1);
                    lua_pop(l, 1);

                    lua_pushstring(l, "y_size");
                    lua_gettable(l, 2+i);
                    if (lua_type(l, -1) != LUA_TNUMBER) {
                        physics_DestroyShapes(shapes, argcount);
                        return haveluaerror(l, badargument2, 2+i,
                        "blitwizard.object:enableCollision",
                        "shape \"box\" or \"elliptic ball\" needs"
                        " \"y_size\" specified as a number");
                    }
                    y_size = lua_tonumber(l, -1);
                    lua_pop(l, 1);

                    lua_pushstring(l, "y_size");
                    lua_gettable(l, 2+i);
                    if (lua_type(l, -1) != LUA_TNUMBER) {
                        physics_DestroyShapes(shapes, argcount);
                        return haveluaerror(l, badargument2, 2+i,
                        "blitwizard.object:enableCollision",
                        "shape \"box\" or \"elliptic ball\" needs"
                        " \"y_size\" specified as a number");
                    }
                    z_size = lua_tonumber(l, -1);
                    lua_pop(l, 1);

                    if (strcmp(shapetype, "box") == 0) {
                        physics_Set3dShapeBox(GET_SHAPE(shapes, i),
                        x_size, y_size, z_size);
                    } else {
                        physics_Set3dShapeBox(GET_SHAPE(shapes, i),
                        x_size, y_size, z_size);
                    }
                }
                if (!isok) {
                    // not a valid shape for a 3d object
                    char invalidshape[50];
                    snprintf(invalidshape, sizeof(invalidshape),
                    "not a valid shape for a 3d object: \"%s\"", shapetype);
                    invalidshape[sizeof(invalidshape)-1] = 0;
                    physics_DestroyShapes(shapes, argcount);
                    return haveluaerror(l, badargument2, 2+i,
                    "blitwizard.object:enableCollision",
                    invalidshape);
                }
            } else {
                // see if this is a usable 2d shape:
                int isok = 0;
                if (strcmp(shapetype, "rectangle") == 0 ||
                strcmp(shapetype, "oval") == 0) {
                    isok = 1;
                    // rectangle or oval with width and height
                    int width,height;
                    lua_pushstring(l, "width");
                    lua_gettable(l, 2+i);
                    if (lua_type(l, -1) != LUA_TNUMBER) {
                        physics_DestroyShapes(shapes, argcount);
                        return haveluaerror(l, badargument2, 2+i,
                        "blitwizard.object:enableCollision",
                        "shape \"rectangle\" or \"oval\" needs"
                        " \"width\" specified as a number");
                    }
                    width = lua_tonumber(l, -1);
                    lua_pop(l, 1);

                    lua_pushstring(l, "height");
                    lua_gettable(l, 2+i);
                    if (lua_type(l, -1) != LUA_TNUMBER) {
                        physics_DestroyShapes(shapes, argcount);
                        return haveluaerror(l, badargument2, 2+i,
                        "blitwizard.object:enableCollision",
                        "shape \"rectangle\" or \"oval\" needs"
                        " \"height\" specified as a number");
                    }
                    height = lua_tonumber(l, -1);
                    lua_pop(l, 1);

                    if (strcmp(shapetype, "oval") == 0) {
                        physics_Set2dShapeOval(GET_SHAPE(shapes, i),
                        width, height);
                    } else {
                        physics_Set2dShapeRectangle(GET_SHAPE(shapes, i),
                        width, height);
                    }
                }
                if (strcmp(shapetype, "circle") == 0) {
                    isok = 1;
                    // rectangle or oval with width and height
                    int diameter;
                    lua_pushstring(l, "diameter");
                    lua_gettable(l, 2+i);
                    if (lua_type(l, -1) != LUA_TNUMBER) {
                        physics_DestroyShapes(shapes, argcount);
                        return haveluaerror(l, badargument2, 2+i,
                        "blitwizard.object:enableCollision",
                        "shape \"circle\" needs \"diameter\" specified"
                        " as a number");
                    }
                    diameter = lua_tonumber(l, -1);
                    lua_pop(l, 1);

                    physics_Set2dShapeCircle(GET_SHAPE(shapes, i),
                    diameter);
                }
                if (!isok) {
                    // not a valid shape for a 2d object
                    char invalidshape[50];
                    snprintf(invalidshape, sizeof(invalidshape),
                    "not a valid shape for a 2d object: \"%s\"", shapetype);
                    invalidshape[sizeof(invalidshape)-1] = 0;
                    physics_DestroyShapes(shapes, argcount);
                    return haveluaerror(l, badargument2, 2+i,
                    "blitwizard.object:enableCollision",
                    invalidshape);
                }
            }
            lua_pop(l, 1);  // pop shapetype string
        }
        i++;
    }

    // prepare physics data:
    if (!obj->physics) {
        obj->physics = malloc(sizeof(struct objectphysicsdata));
        memset(obj->physics, 0, sizeof(obj->physics));
    }

    // remember the old representation if any::
    struct physicsobject* old = obj->physics->object;

    // create a physics object from the shapes:
    obj->physics->object = physics_CreateObject(main_DefaultPhysics3dPtr(),
    obj, movable, shapes);
    physics_DestroyShapes(shapes, argcount);

    // destroy old representation after transferring settings:
    if (old) {
        transferbodysettings(old, obj->physics->object);
        physics_DestroyObject(old);
    }

    obj->physics->movable = 1;
    return 1;
}