Page MenuHomePhabricator (Chris)

No OneTemporary

Authored By
Unknown
Size
78 KB
Referenced Files
None
Subscribers
None
diff --git a/src/Block.cpp b/src/Block.cpp
index 22e90a6..b6e145d 100644
--- a/src/Block.cpp
+++ b/src/Block.cpp
@@ -1,1099 +1,1119 @@
/*
* Copyright (C) 2011-2013 Me and My Shadow
*
* This file is part of Me and My Shadow.
*
* Me and My Shadow is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Me And My Shadow is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
*/
#include "GameObjects.h"
#include "Game.h"
#include "Player.h"
#include "Block.h"
#include "Functions.h"
#include "Globals.h"
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
using namespace std;
Block::Block(Game* parent,int x,int y,int w,int h,int type):
GameObject(parent),
animation(0),
animationSave(0),
flags(0),
flagsSave(0),
temp(0),
tempSave(0),
dx(0),
dxSave(0),
- xSave(0),
dy(0),
dySave(0),
- ySave(0),
loop(true),
speed(0),
speedSave(0),
editorSpeed(0),
editorFlags(0),
enabled(true),
enabledSave(true)
{
//Make sure the type is set, if not init should be called somewhere else with this information.
if(type>=0 && type<TYPE_MAX)
init(x,y,w,h,type);
}
Block::~Block(){}
void Block::init(int x,int y,int w,int h,int type){
//First set the location and size of the box.
//The default size is 50x50.
- box.x=x;
- box.y=y;
- box.w=w;
- box.h=h;
-
- //Also store the starting location (and size).
- boxBase.x=x;
- boxBase.y=y;
- boxBase.w=w;
- boxBase.h=h;
-
+ box.x=boxBase.x=x;
+ box.y=boxBase.y=y;
+ box.w=boxBase.w=w;
+ box.h=boxBase.h=h;
+
+ //Set the save values.
+ boxSave.x=x;
+ boxSave.y=y;
+ boxSave.w=w;
+ boxSave.h=h;
+
//Set the type.
this->type=type;
//Some types need type specific code.
if(type==TYPE_START_PLAYER){
//This is the player start so set the player here.
//We center the player, the player is 23px wide.
parent->player.setLocation(box.x+(box.w-23)/2,box.y);
parent->player.fx=box.x+(box.w-23)/2;
parent->player.fy=box.y;
}else if(type==TYPE_START_SHADOW){
//This is the shadow start so set the shadow here.
//We center the shadow, the shadow is 23px wide.
parent->shadow.setLocation(box.x+(box.w-23)/2,box.y);
parent->shadow.fx=box.x+(box.w-23)/2;
parent->shadow.fy=box.y;
}
objCurrentStand=NULL;
inAir=inAirSave=true;
xVel=yVel=xVelBase=yVelBase=0;
xVelSave=yVelSave=xVelBaseSave=yVelBaseSave=0;
//And load the appearance.
objThemes.getBlock(type)->createInstance(&appearance);
}
void Block::show(){
//Make sure we are enabled.
if(!enabled)
return;
//Check if the block is visible.
if(checkCollision(camera,box)==true || (stateID==STATE_LEVEL_EDITOR && checkCollision(camera,boxBase)==true)){
SDL_Rect r={0,0,box.w,box.h};
//What we need to draw depends on the type of block.
switch(type){
case TYPE_CHECKPOINT:
//Check if the checkpoint is last used.
if(parent!=NULL && parent->objLastCheckPoint==this){
if(!temp) appearance.changeState("activated");
temp=1;
}else{
if(temp) appearance.changeState("default");
temp=0;
}
break;
case TYPE_CONVEYOR_BELT:
case TYPE_SHADOW_CONVEYOR_BELT:
if(animation){
r.x=box.w-animation;
r.w=animation;
appearance.draw(screen,box.x-camera.x-box.w+animation,box.y-camera.y,box.w,box.h,&r);
r.x=0;
r.w=box.w-animation;
appearance.draw(screen,box.x-camera.x+animation,box.y-camera.y,box.w,box.h,&r);
return;
}
break;
case TYPE_NOTIFICATION_BLOCK:
if(message.empty()==false){
appearance.draw(screen, box.x - camera.x, box.y - camera.y);
return;
}
break;
}
//Always draw the base.
appearance.drawState("base", screen, boxBase.x - camera.x, boxBase.y - camera.y, boxBase.w, boxBase.h);
//Now draw normal.
appearance.draw(screen, box.x - camera.x, box.y - camera.y, box.w, box.h);
//Some types need to draw something on top of the base/default.
switch(type){
case TYPE_BUTTON:
if(flags&4){
if(animation<5) animation++;
}else{
if(animation>0) animation--;
}
appearance.drawState("button",screen,box.x-camera.x,box.y-camera.y-5+animation);
break;
}
//Draw a stupid icon for scrpited blocks in edit mode.
if(stateID==STATE_LEVEL_EDITOR && !scripts.empty()){
static SDL_Surface *bmGUI=NULL;
if(bmGUI==NULL) bmGUI=loadImage(getDataPath()+"gfx/gui.png");
static SDL_Rect r={0,32,16,16};
applySurface(box.x - camera.x + 2, box.y - camera.y + 2, bmGUI, screen, &r);
}
}
}
SDL_Rect Block::getBox(int boxType){
SDL_Rect r={0,0,0,0};
switch(boxType){
case BoxType_Base:
return boxBase;
case BoxType_Previous:
r.x=box.x-dx;
r.y=box.y-dy;
r.w=box.w;
r.h=box.h;
return r;
case BoxType_Delta:
r.x=dx;
r.y=dy;
return r;
case BoxType_Velocity:
r.x=xVel;
r.y=yVel;
//NOTE: In case of the pushable block we sometimes need to substract one from the vertical velocity.
//The yVel is set to one when it's resting, but should be handled as zero in collision.
if(type==TYPE_PUSHABLE && !inAir)
r.y=0;
return r;
case BoxType_Current:
return box;
}
return r;
}
-void Block::setLocation(int x,int y){
+void Block::moveTo(int x,int y){
//The block has moved so calculate the delta.
//NOTE: Every delta is summed since they all happened within one frame and for collision/movement we need the resulting delta.
int delta=(x-box.x);
dx+=delta;
xVel+=delta;
delta=(y-box.y);
dy+=delta;
yVel+=delta;
//And set the new location.
box.x=x;
box.y=y;
}
+void Block::growTo(int w,int h){
+ //The block has changed size
+ //NOTE: Every delta is summed since they all happened within one frame and for collision/movement we need the resulting delta.
+ int delta=(w-box.w);
+ dx+=delta;
+ xVel+=delta;
+ delta=(h-box.h);
+ dy+=delta;
+ yVel+=delta;
+
+ //And set the new location.
+ box.w=w;
+ box.h=h;
+}
+
void Block::saveState(){
animationSave=animation;
flagsSave=flags;
tempSave=temp;
dxSave=dx;
dySave=dy;
- xSave=box.x-boxBase.x;
- ySave=box.y-boxBase.y;
+ boxSave.x=box.x-boxBase.x;
+ boxSave.y=box.y-boxBase.y;
+ boxSave.w=box.w-boxBase.w;
+ boxSave.h=box.h-boxBase.h;
xVelSave=xVel;
yVelSave=yVel;
enabledSave=enabled;
appearance.saveAnimation();
//In case of a certain blocks we need to save some more.
switch(type){
case TYPE_PUSHABLE:
xVelBaseSave=xVelBase;
yVelBaseSave=yVelBase;
inAirSave=inAir;
break;
case TYPE_CONVEYOR_BELT:
case TYPE_SHADOW_CONVEYOR_BELT:
speedSave=speed;
break;
}
}
void Block::loadState(){
//Restore the flags and animation var.
animation=animationSave;
flags=flagsSave;
temp=tempSave;
dx=dxSave;
dy=dySave;
//Restore the location.
- box.x=boxBase.x+xSave;
- box.y=boxBase.y+ySave;
+ box.x=boxBase.x+boxSave.x;
+ box.y=boxBase.y+boxSave.y;
+ box.w=boxBase.w+boxSave.w;
+ box.h=boxBase.h+boxSave.h;
//And the velocity.
xVel=xVelSave;
yVel=yVelSave;
//The enabled status.
enabled=enabledSave;
//Handle block type specific variables.
switch(type){
case TYPE_PUSHABLE:
xVelBase=xVelBaseSave;
yVelBase=yVelBaseSave;
inAir=inAirSave;
break;
case TYPE_CONVEYOR_BELT:
case TYPE_SHADOW_CONVEYOR_BELT:
speed=speedSave;
break;
}
//And load the animation.
appearance.loadAnimation();
}
void Block::reset(bool save){
//We need to reset so we clear the animation and saves.
if(save){
- animation=animationSave=xSave=ySave=0;
+ animation=animationSave=0;
+ boxSave.x=boxSave.y=boxSave.w=boxSave.h=0;
flags=flagsSave=editorFlags;
temp=tempSave=0;
dx=dxSave=0;
dy=dySave=0;
}else{
animation=0;
flags=editorFlags;
temp=0;
dx=0;
dy=0;
}
//Reset the block to its original location.
box.x=boxBase.x;
box.y=boxBase.y;
+ box.w=boxBase.w;
+ box.h=boxBase.h;
//Reset any velocity.
xVel=yVel=xVelBase=yVelBase=0;
if(save)
xVelSave=yVelSave=xVelBaseSave=yVelBaseSave=0;
//Reset the enabled status.
enabled=true;
if(save)
enabledSave=true;
//Also reset the appearance.
appearance.resetAnimation(save);
appearance.changeState("default");
//NOTE: We load the animation right after changing it to prevent a transition.
if(save)
appearance.loadAnimation();
//Some types of block requires type specific code.
switch(type){
case TYPE_FRAGILE:
{
const char* s=(flags==0)?"default":((flags==1)?"fragile1":((flags==2)?"fragile2":"fragile3"));
appearance.changeState(s);
}
break;
case TYPE_PUSHABLE:
inAir=false;
if(save)
inAirSave=false;
break;
case TYPE_CONVEYOR_BELT:
case TYPE_SHADOW_CONVEYOR_BELT:
if(save)
speed=speedSave=editorSpeed;
else
speed=editorSpeed;
break;
}
}
void Block::playAnimation(int flags){
switch(type){
case TYPE_SWAP:
appearance.changeState("activated");
break;
case TYPE_SWITCH:
temp^=1;
appearance.changeState(temp?"activated":"default");
break;
}
}
void Block::onEvent(int eventType){
//Make sure we are enabled, otherwise no events should be handled.
if(!enabled)
return;
//Iterator used to check if the map contains certain entries.
map<int,int>::iterator it;
//Check if there's a script for the event.
it=compiledScripts.find(eventType);
if(it!=compiledScripts.end()){
//There is a script so execute it and check return value.
int ret=getScriptExecutor()->executeScript(it->second,this);
//Return value 1 means do default event process.
//Other values are coming soon...
if(ret!=1) return;
}
//Event handling.
switch(eventType){
case GameObjectEvent_PlayerWalkOn:
switch(type){
case TYPE_FRAGILE:
flags++;
{
const char* s=(flags==0)?"default":((flags==1)?"fragile1":((flags==2)?"fragile2":"fragile3"));
appearance.changeState(s);
}
break;
}
break;
case GameObjectEvent_PlayerIsOn:
switch(type){
case TYPE_BUTTON:
temp=1;
break;
}
break;
case GameObjectEvent_OnToggle:
switch(type){
case TYPE_MOVING_BLOCK:
case TYPE_MOVING_SHADOW_BLOCK:
case TYPE_MOVING_SPIKES:
case TYPE_CONVEYOR_BELT:
case TYPE_SHADOW_CONVEYOR_BELT:
flags^=1;
break;
case TYPE_PORTAL:
appearance.changeState("activated");
break;
case TYPE_COLLECTABLE:
appearance.changeState("inactive");
flags=1;
break;
}
break;
case GameObjectEvent_OnSwitchOn:
switch(type){
case TYPE_MOVING_BLOCK:
case TYPE_MOVING_SHADOW_BLOCK:
case TYPE_MOVING_SPIKES:
case TYPE_CONVEYOR_BELT:
case TYPE_SHADOW_CONVEYOR_BELT:
flags&=~1;
break;
case TYPE_EXIT:
appearance.changeState("default");
break;
}
break;
case GameObjectEvent_OnSwitchOff:
switch(type){
case TYPE_MOVING_BLOCK:
case TYPE_MOVING_SHADOW_BLOCK:
case TYPE_MOVING_SPIKES:
case TYPE_CONVEYOR_BELT:
case TYPE_SHADOW_CONVEYOR_BELT:
flags|=1;
break;
case TYPE_EXIT:
appearance.changeState("closed");
break;
}
break;
}
}
int Block::queryProperties(int propertyType,Player* obj){
switch(propertyType){
case GameObjectProperty_PlayerCanWalkOn:
switch(type){
case TYPE_BLOCK:
case TYPE_MOVING_BLOCK:
case TYPE_CONVEYOR_BELT:
case TYPE_BUTTON:
case TYPE_PUSHABLE:
return 1;
case TYPE_SHADOW_BLOCK:
case TYPE_MOVING_SHADOW_BLOCK:
case TYPE_SHADOW_CONVEYOR_BELT:
if(obj!=NULL && obj->isShadow()) return 1;
break;
case TYPE_FRAGILE:
if(flags<3) return 1;
break;
}
break;
case GameObjectProperty_IsSpikes:
switch(type){
case TYPE_SPIKES:
case TYPE_MOVING_SPIKES:
return 1;
}
break;
case GameObjectProperty_Flags:
return flags;
break;
default:
break;
}
return 0;
}
void Block::getEditorData(std::vector<std::pair<std::string,std::string> >& obj){
//Every block has an id.
obj.push_back(pair<string,string>("id",id));
//Block specific properties.
switch(type){
case TYPE_MOVING_BLOCK:
case TYPE_MOVING_SHADOW_BLOCK:
case TYPE_MOVING_SPIKES:
{
char s[64],s0[64];
sprintf(s,"%d",(int)movingPos.size());
obj.push_back(pair<string,string>("MovingPosCount",s));
obj.push_back(pair<string,string>("activated",(editorFlags&0x1)?"0":"1"));
obj.push_back(pair<string,string>("loop",loop?"1":"0"));
for(unsigned int i=0;i<movingPos.size();i++){
sprintf(s0+1,"%u",i);
sprintf(s,"%d",movingPos[i].x);
s0[0]='x';
obj.push_back(pair<string,string>(s0,s));
sprintf(s,"%d",movingPos[i].y);
s0[0]='y';
obj.push_back(pair<string,string>(s0,s));
sprintf(s,"%d",movingPos[i].w);
s0[0]='t';
obj.push_back(pair<string,string>(s0,s));
}
}
break;
case TYPE_CONVEYOR_BELT:
case TYPE_SHADOW_CONVEYOR_BELT:
{
char s[64];
obj.push_back(pair<string,string>("activated",(editorFlags&0x1)?"0":"1"));
sprintf(s,"%d",editorSpeed);
obj.push_back(pair<string,string>("speed",s));
}
break;
case TYPE_PORTAL:
obj.push_back(pair<string,string>("automatic",(editorFlags&0x1)?"1":"0"));
obj.push_back(pair<string,string>("destination",destination));
break;
case TYPE_BUTTON:
case TYPE_SWITCH:
{
string s;
switch(editorFlags&0x3){
case 1:
s="on";
break;
case 2:
s="off";
break;
default:
s="toggle";
break;
}
obj.push_back(pair<string,string>("behaviour",s));
}
break;
case TYPE_NOTIFICATION_BLOCK:
{
string value=message;
//Change \n with the characters '\n'.
while(value.find('\n',0)!=string::npos){
size_t pos=value.find('\n',0);
value=value.replace(pos,1,"\\n");
}
obj.push_back(pair<string,string>("message",value));
}
break;
case TYPE_FRAGILE:
{
char s[64];
sprintf(s,"%d",editorFlags);
obj.push_back(pair<string,string>("state",s));
}
break;
}
}
void Block::setEditorData(std::map<std::string,std::string>& obj){
//Iterator used to check if the map contains certain entries.
map<string,string>::iterator it;
//Check if the data contains the id block.
it=obj.find("id");
if(it!=obj.end()){
//Set the id of the block.
id=obj["id"];
}
//Block specific properties.
switch(type){
case TYPE_MOVING_BLOCK:
case TYPE_MOVING_SHADOW_BLOCK:
case TYPE_MOVING_SPIKES:
{
//Make sure that the editor data contains MovingPosCount.
it=obj.find("MovingPosCount");
if(it!=obj.end()){
char s0[64];
int m=atoi(obj["MovingPosCount"].c_str());
movingPos.clear();
for(int i=0;i<m;i++){
SDL_Rect r={0,0,0,0};
sprintf(s0+1,"%d",i);
s0[0]='x';
r.x=atoi(obj[s0].c_str());
s0[0]='y';
r.y=atoi(obj[s0].c_str());
s0[0]='t';
r.w=atoi(obj[s0].c_str());
movingPos.push_back(r);
}
}
//Check if the activated or disabled key is in the data.
//NOTE: 'disabled' is obsolete in V0.5.
it=obj.find("activated");
if(it!=obj.end()){
string s=it->second;
editorFlags=0;
if(!(s=="true" || atoi(s.c_str()))) editorFlags|=0x1;
flags=flagsSave=editorFlags;
}else{
it=obj.find("disabled");
if(it!=obj.end()){
string s=it->second;
editorFlags=0;
if(s=="true" || atoi(s.c_str())) editorFlags|=0x1;
flags=flagsSave=editorFlags;
}
}
//Check if the loop key is in the data.
it=obj.find("loop");
if(it!=obj.end()){
string s=obj["loop"];
loop=false;
if(s=="true" || atoi(s.c_str()))
loop=true;
}
}
break;
case TYPE_CONVEYOR_BELT:
case TYPE_SHADOW_CONVEYOR_BELT:
{
//Check if there's a speed key in the editor data.
it=obj.find("speed");
if(it!=obj.end()){
editorSpeed=atoi(obj["speed"].c_str());
speed=speedSave=editorSpeed;
}
//Check if the activated or disabled key is in the data.
//NOTE: 'disabled' is obsolete in V0.5.
it=obj.find("activated");
if(it!=obj.end()){
string s=it->second;
editorFlags=0;
if(!(s=="true" || atoi(s.c_str()))) editorFlags|=0x1;
flags=flagsSave=editorFlags;
}else{
it=obj.find("disabled");
if(it!=obj.end()){
string s=it->second;
editorFlags=0;
if(s=="true" || atoi(s.c_str())) editorFlags|=0x1;
flags=flagsSave=editorFlags;
}
}
}
break;
case TYPE_PORTAL:
{
//Check if the automatic key is in the data.
it=obj.find("automatic");
if(it!=obj.end()){
string s=obj["automatic"];
editorFlags=0;
if(s=="true" || atoi(s.c_str())) editorFlags|=0x1;
flags=flagsSave=editorFlags;
}
//Check if the destination key is in the data.
it=obj.find("destination");
if(it!=obj.end()){
destination=obj["destination"];
}
}
break;
case TYPE_BUTTON:
case TYPE_SWITCH:
{
//Check if the behaviour key is in the data.
it=obj.find("behaviour");
if(it!=obj.end()){
string s=obj["behaviour"];
editorFlags=0;
if(s=="on" || s==_("On")) editorFlags|=1;
else if(s=="off" || s==_("Off")) editorFlags|=2;
flags=flagsSave=editorFlags;
}
}
break;
case TYPE_NOTIFICATION_BLOCK:
{
//Check if the message key is in the data.
it=obj.find("message");
if(it!=obj.end()){
message=obj["message"];
//Change the characters '\n' to a real \n
while(message.find("\\n")!=string::npos){
message=message.replace(message.find("\\n"),2,"\n");
}
}
}
break;
case TYPE_FRAGILE:
{
//Check if the status is in the data.
it=obj.find("state");
if(it!=obj.end()){
editorFlags=atoi(obj["state"].c_str());
flags=editorFlags;
{
const char* s=(flags==0)?"default":((flags==1)?"fragile1":((flags==2)?"fragile2":"fragile3"));
appearance.changeState(s);
}
}
}
}
}
std::string Block::getEditorProperty(std::string property){
//First get the complete editor data.
vector<pair<string,string> > objMap;
vector<pair<string,string> >::iterator it;
getEditorData(objMap);
//Loop through the entries.
for(it=objMap.begin();it!=objMap.end();++it){
if(it->first==property)
return it->second;
}
//Nothing found.
return "";
}
void Block::setEditorProperty(std::string property,std::string value){
//Create a map to hold the property.
std::map<std::string,std::string> editorData;
editorData[property]=value;
//And call the setEditorData method.
setEditorData(editorData);
}
bool Block::loadFromNode(TreeStorageNode* objNode){
//Make sure there are enough parameters.
if(objNode->value.size()<3)
return false;
//Load the type and location.
int type=Game::blockNameMap[objNode->value[0]];
int x=atoi(objNode->value[1].c_str());
int y=atoi(objNode->value[2].c_str());
int w=50;
int h=50;
if(objNode->value.size()>3)
w=atoi(objNode->value[3].c_str());
if(objNode->value.size()>4)
h=atoi(objNode->value[4].c_str());
//Call the init method.
init(x,y,w,h,type);
//Loop through the attributes as editorProperties.
map<string,string> obj;
for(map<string,vector<string> >::iterator i=objNode->attributes.begin();i!=objNode->attributes.end();++i){
if(i->second.size()>0) obj[i->first]=i->second[0];
}
setEditorData(obj);
//Loop through the subNodes.
for(unsigned int i=0;i<objNode->subNodes.size();i++){
//FIXME: Ugly variable naming.
TreeStorageNode* obj=objNode->subNodes[i];
if(obj==NULL) continue;
//Check for a script block.
if(obj->name=="script" && !obj->value.empty()){
map<string,int>::iterator it=Game::gameObjectEventNameMap.find(obj->value[0]);
if(it!=Game::gameObjectEventNameMap.end()){
int eventType=it->second;
const std::string& script=obj->attributes["script"][0];
if(!script.empty()) scripts[eventType]=script;
}
}
}
return true;
}
void Block::prepareFrame(){
//Reset the delta variables.
dx=dy=0;
//Also reset the velocity, these should be set in the move method.
if(type!=TYPE_PUSHABLE)
xVel=yVel=0;
}
/*//debug
int block_test_count=-1;
bool block_test_only=false;*/
void Block::move(){
//Make sure we are enabled, if not return.
if(!enabled)
return;
//First update the animation of the appearance.
appearance.updateAnimation();
//Block specific move code.
switch(type){
case TYPE_MOVING_BLOCK:
case TYPE_MOVING_SHADOW_BLOCK:
case TYPE_MOVING_SPIKES:
{
/*//debug
if(block_test_only || parent->time==416){
cout<<"Time:"<<(parent->time)<<" Recorded:"<<block_test_count<<" Coord:"<<box.x<<","<<box.y<<endl;
block_test_only=false;
}*/
//Make sure the block is enabled, if so increase the time.
if(!(flags&0x1)) temp++;
int t=temp;
SDL_Rect r0={0,0,0,0},r1;
dx=0;
dy=0;
//Loop through the moving positions.
for(unsigned int i=0;i<movingPos.size();i++){
r1.x=movingPos[i].x;
r1.y=movingPos[i].y;
r1.w=movingPos[i].w;
if(t==0&&r1.w==0){
r1.w=1;
flags|=0x1;
}
if(t>=0 && t<(int)r1.w){
int newX=boxBase.x+(int)(float(r0.x)+(float(r1.x)-float(r0.x))*float(t)/float(r1.w));
int newY=boxBase.y+(int)(float(r0.y)+(float(r1.y)-float(r0.y))*float(t)/float(r1.w));
//Calculate the delta and velocity.
xVel=dx=newX-box.x;
yVel=dy=newY-box.y;
//Set the new location of the moving block.
box.x=newX;
box.y=newY;
return;
}else if(t==(int)r1.w){
//If the time is the time of the movingPosition then set it equal to the location.
//We do this to prevent a slight edge between normal blocks and moving blocks.
int newX=boxBase.x+r1.x;
int newY=boxBase.y+r1.y;
xVel=dx=newX-box.x;
yVel=dy=newY-box.y;
box.x=newX;
box.y=newY;
return;
}
t-=r1.w;
r0.x=r1.x;
r0.y=r1.y;
}
//Only reset the stuff when we're looping.
if(loop){
//Set the time back to zero.
temp=0;
//Calculate the delta movement.
if(!movingPos.empty() && movingPos.back().x==0 && movingPos.back().y==0){
dx=boxBase.x-box.x;
dy=boxBase.y-box.y;
}
//Set the movingblock back to it's initial location.
box.x=boxBase.x;
box.y=boxBase.y;
}
}
break;
case TYPE_BUTTON:
{
//Check the third bit of flags to see if temp changed.
int new_flags=temp?4:0;
if((flags^new_flags)&4){
//The button has been pressed or unpressed so change the third bit on flags.
flags=(flags&~4)|new_flags;
if(parent && (new_flags || (flags&3)==0)){
//Make sure that id isn't empty.
if(!id.empty()){
parent->broadcastObjectEvent(0x10000|(flags&3),-1,id.c_str());
}else{
cerr<<"WARNING: invalid button id!"<<endl;
}
}
}
temp=0;
}
break;
case TYPE_CONVEYOR_BELT:
case TYPE_SHADOW_CONVEYOR_BELT:
//Increase the conveyor belt animation.
if((flags&1)==0){
animation=(animation+speed)%box.w;
if(animation<0) animation+=box.w;
//Set the velocity NOTE This isn't the actual velocity of the block, but the speed of the player/shadow standing on it.
xVel=speed;
}
break;
case TYPE_PUSHABLE:
{
//Update the vertical velocity, horizontal is set by the player.
if(inAir==true){
yVel+=1;
//Cap fall speed to 13.
if(yVel>13)
yVel=13;
}
if(objCurrentStand!=NULL){
//Now get the velocity of the object the player is standing on.
SDL_Rect v=objCurrentStand->getBox(BoxType_Velocity);
//Set the base velocity to the velocity of the object.
xVelBase=v.x;
//NOTE: Only copy the velocity of the block when moving down.
//Upwards is automatically resolved before the player is moved.
if(v.y>0)
yVelBase=v.y;
else
yVelBase=0;
}
//Set the object the player is currently standing to NULL.
objCurrentStand=NULL;
//Store the location of the player.
int lastX=box.x;
int lastY=box.y;
//An array that will hold all the GameObjects that are involved in the collision/movement.
vector<Block*> objects;
//All the blocks have moved so if there's collision with the player, the block moved into him.
for(unsigned int o=0;o<parent->levelObjects.size();o++){
//Make sure to only check enabled blocks.
if(!parent->levelObjects[o]->enabled)
continue;
//Make sure we aren't the block.
if(parent->levelObjects[o]==this)
continue;
//Make sure the object is solid for the player.
if(!parent->levelObjects[o]->queryProperties(GameObjectProperty_PlayerCanWalkOn,&parent->player))
continue;
//Check for collision.
if(checkCollision(box,parent->levelObjects[o]->getBox()))
objects.push_back(parent->levelObjects[o]);
}
//There was collision so try to resolve it.
if(!objects.empty()){
//FIXME: When multiple moving blocks are overlapping the player can be "bounced" off depending on the block order.
for(unsigned int o=0;o<objects.size();o++){
SDL_Rect r=objects[o]->getBox();
SDL_Rect delta=objects[o]->getBox(BoxType_Delta);
//Check on which side of the box the player is.
if(delta.x!=0){
if(delta.x>0){
if((r.x+r.w)-box.x<=delta.x)
box.x=r.x+r.w;
}else{
if((box.x+box.w)-r.x<=-delta.x)
box.x=r.x-box.w;
}
}
if(delta.y!=0){
if(delta.y>0){
if((r.y+r.h)-box.y<=delta.y)
box.y=r.y+r.h;
}else{
if((box.y+box.h)-r.y<=-delta.y)
box.y=r.y-box.h;
}
}
}
}
//Reuse the objects array, this time for blocks the block moves into.
objects.clear();
//Determine the collision frame.
SDL_Rect frame={box.x,box.y,box.w,box.h};
//Keep the horizontal movement of the block in mind.
if(xVel+xVelBase>=0){
frame.w+=(xVel+xVelBase);
}else{
frame.x+=(xVel+xVelBase);
frame.w-=(xVel+xVelBase);
}
//And the vertical movement.
if(yVel+yVelBase>=0){
frame.h+=(yVel+yVelBase);
}else{
frame.y+=(yVel+yVelBase);
frame.h-=(yVel+yVelBase);
}
//Loop through the game objects.
for(unsigned int o=0; o<parent->levelObjects.size(); o++){
//Make sure the object is enabled.
if(!parent->levelObjects[o]->enabled)
continue;
//Make sure we aren't the block.
if(parent->levelObjects[o]==this)
continue;
//Check if the player can collide with this game object.
if(!parent->levelObjects[o]->queryProperties(GameObjectProperty_PlayerCanWalkOn,&parent->player))
continue;
//Check if the block is inside the frame.
if(checkCollision(frame,parent->levelObjects[o]->getBox()))
objects.push_back(parent->levelObjects[o]);
}
//Horizontal pass.
if(xVel+xVelBase!=0){
box.x+=xVel+xVelBase;
for(unsigned int o=0;o<objects.size();o++){
SDL_Rect r=objects[o]->getBox();
if(!checkCollision(box,r))
continue;
if(xVel+xVelBase>0){
//We came from the left so the right edge of the player must be less or equal than xVel+xVelBase.
if((box.x+box.w)-r.x<=xVel+xVelBase)
box.x=r.x-box.w;
}else{
//We came from the left so the right edge of the player must be less or equal than xVel+xVelBase.
if(box.x-(r.x+r.w)<=-(xVel+xVelBase))
box.x=r.x+r.w;
}
}
}
//Some variables that are used in vertical movement.
Block* lastStand=NULL;
inAir=true;
//Vertical pass.
if(yVel+yVelBase!=0){
box.y+=yVel+yVelBase;
for(unsigned int o=0;o<objects.size();o++){
SDL_Rect r=objects[o]->getBox();
if(!checkCollision(box,r))
continue;
//Now check how we entered the block (vertically or horizontally).
if(yVel+yVelBase>0){
//We came from the top so the bottom edge of the player must be less or equal than yVel+yVelBase.
if((box.y+box.h)-r.y<=yVel+yVelBase){
//NOTE: lastStand is handled later since the player can stand on only one block at the time.
//Check if there's already a lastStand.
if(lastStand){
//There is one, so check 'how much' the player is on the blocks.
SDL_Rect r=objects[o]->getBox();
int w=0;
if(box.x+box.w>r.x+r.w)
w=(r.x+r.w)-box.x;
else
w=(box.x+box.w)-r.x;
//Do the same for the other box.
r=lastStand->getBox();
int w2=0;
if(box.x+box.w>r.x+r.w)
w2=(r.x+r.w)-box.x;
else
w2=(box.x+box.w)-r.x;
//NOTE: It doesn't matter which block the player is on if they are both stationary.
SDL_Rect v=objects[o]->getBox(BoxType_Velocity);
SDL_Rect v2=lastStand->getBox(BoxType_Velocity);
if(v.y==v2.y){
if(w>w2)
lastStand=objects[o];
}else if(v.y<v2.y){
lastStand=objects[o];
}
}else{
lastStand=objects[o];
}
}
}else{
//We came from the bottom so the upper edge of the player must be less or equal than yVel+yVelBase.
if(box.y-(r.y+r.h)<=-(yVel+yVelBase)){
box.y=r.y+r.h;
yVel=0;
}
}
}
}
if(lastStand){
inAir=false;
yVel=1;
SDL_Rect r=lastStand->getBox();
box.y=r.y-box.h;
}
dx=box.x-lastX;
dy=box.y-lastY;
xVel=0;
}
break;
}
}
diff --git a/src/Block.h b/src/Block.h
index 1397300..43d7734 100644
--- a/src/Block.h
+++ b/src/Block.h
@@ -1,195 +1,199 @@
/*
* Copyright (C) 2011-2012 Me and My Shadow
*
* This file is part of Me and My Shadow.
*
* Me and My Shadow is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Me and My Shadow is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef BLOCK_H
#define BLOCK_H
#include "GameObjects.h"
#include "Globals.h"
#include "ThemeManager.h"
#include "ScriptUserData.h"
#include "ScriptExecutor.h"
#include <vector>
#include <SDL/SDL.h>
class Block: public GameObject, public ScriptUserClass<'B','L','O','K',Block>{
private:
//Integer that a block can use for all animation or visual related things.
int animation;
//The save for animation when the state of the block is saved.
int animationSave;
//flags:
//moving object 0x1=disabled
//button bit0-1=behavior 0x4=pressed
//switch bit0-1=behavior
int flags;
//The save for flags when the state of the block is saved.
int flagsSave;
//Temp variables used to keep track of time/state.
int temp;
//The save for temp when the state of the block is saved.
int tempSave;
- //Save variables for the current location of the block.
- int xSave,ySave;
+ //Save variables for the current location and size of the block.
+ SDL_Rect boxSave;
//Delta variables, if the block moves these must be set to the delta movement.
int dx,dy;
int dxSave,dySave;
//Vector containing the poisitions of the moving block.
std::vector<SDL_Rect> movingPos;
//Boolean if the moving block loops his movement.
//Default value is true.
bool loop;
//Integer containing the speed for conveyorbelts.
int speed;
int speedSave;
int editorSpeed;
//Following is for the pushable block.
Block* objCurrentStand;
//Flags of the block for the editor.
//moving object 0x1=disabled
//portal 0x1=automatic
//fragile =state
int editorFlags;
public:
//The Appearance of the block.
ThemeBlockInstance appearance;
//Velocity variables for the block, if the block moves these must be set for collision/movement of the player.
int xVel,yVel;
//Save variables for the velocity.
int xVelSave,yVelSave;
//Follwing is for pushable block.
bool inAir;
int xVelBase,yVelBase;
//The save variables for each of the above.
bool inAirSave;
int xVelBaseSave,yVelBaseSave;
//The id of the block.
std::string id;
//String containing the id of the destination for portals.
std::string destination;
//String containing the message of the notification block.
std::string message;
//The map that holds a script for every event.
map<int,std::string> scripts;
//Compiled scripts. Use lua_rawgeti(L, LUA_REGISTRYINDEX, r) to get the function.
std::map<int,int> compiledScripts;
//Boolean if the block is enabled.
//If it's not enabled it will not collide with anything or execute any scripts.
bool enabled,enabledSave;
//Constructor.
//objParent: Pointer to the Game object.
//x: The x location of the block.
//y: The y location of the block.
//w: The width of the block.
//h: The height of the block.
//type: The block type.
Block(Game* objParent,int x=0,int y=0,int w=50,int h=50,int type=-1);
//Desturctor.
~Block();
//Method for initializing the block.
//x: The x location of the block.
//y: The y location of the block.
//w: The width of the block.
//h: The height of the block.
//type: The block type.
void init(int x,int y,int w,int h,int type);
//Method used to draw the block.
void show();
//Returns the box of a given type.
//boxType: The type of box that should be returned.
//See GameObjects.h for the types.
//Returns: The box.
virtual SDL_Rect getBox(int boxType=BoxType_Current);
- //Method used to set the location of the block.
- //NOTE: The new location isn't stored as base location.
+ //Method for setting the block to a given location as if it moved there.
//x: The new x location.
//y: The new y location.
- virtual void setLocation(int x,int y);
+ void moveTo(int x,int y);
+
+ //Method for setting a new size as if the block grew,
+ //w: The new width of the block.
+ //h: The new height of the block.
+ void growTo(int w,int h);
//Save the state of the block so we can load it later on.
virtual void saveState();
//Load the saved state of the block so.
virtual void loadState();
//Reset the block.
//save: Boolean if the saved state should also be deleted.
virtual void reset(bool save);
//Play an animation.
//flags: TODO???
virtual void playAnimation(int flags);
//Method called when there's an event.
//eventType: The type of event.
//See GameObjects.h for the eventtypes.
virtual void onEvent(int eventType);
//Method used to retrieve a property from the block.
//propertyType: The type of property requested.
//See GameObjects.h for the properties.
//obj: Pointer to the player.
//Returns: Integer containing the value of the property.
virtual int queryProperties(int propertyType,Player* obj);
//Get the editor data of the block.
//obj: The vector that will be filled with the editorData.
virtual void getEditorData(std::vector<std::pair<std::string,std::string> >& obj);
//Set the editor data of the block.
//obj: The new editor data.
virtual void setEditorData(std::map<std::string,std::string>& obj);
//Get a single property of the block.
//property: The property to return.
//Returns: The value for the requested property.
virtual std::string getEditorProperty(std::string property);
//Set a single property of the block.
//property: The property to set.
//value: The new value for the property.
virtual void setEditorProperty(std::string property,std::string value);
//Method for loading the Block from a node.
//objNode: Pointer to the storage node to load from.
//Returns: True if it succeeds without errors.
virtual bool loadFromNode(TreeStorageNode* objNode);
//Method used for resetting the dx/dy and xVel/yVel variables.
virtual void prepareFrame();
//Method used for updating moving blocks or elements of blocks.
virtual void move();
};
#endif
diff --git a/src/GameObjects.cpp b/src/GameObjects.cpp
index f319a62..ef2150d 100644
--- a/src/GameObjects.cpp
+++ b/src/GameObjects.cpp
@@ -1,72 +1,83 @@
/*
* Copyright (C) 2011-2012 Me and My Shadow
*
* This file is part of Me and My Shadow.
*
* Me and My Shadow is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Me and My Shadow is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
*/
#include "GameObjects.h"
#include "Functions.h"
#include "Globals.h"
GameObject::GameObject(Game* parent):type(0),parent(parent){}
GameObject::~GameObject(){}
SDL_Rect GameObject::getBox(int boxType){
//This is the default implementation of getBox(int) method.
switch(boxType){
case BoxType_Current:
case BoxType_Previous:
return box;
case BoxType_Base:
return boxBase;
}
//Return an empty SDL_Rect.
SDL_Rect tmp={0,0,0,0};
return tmp;
}
void GameObject::setLocation(int x,int y){
box.x=x;
box.y=y;
}
void GameObject::setBaseLocation(int x,int y){
box.x=x;
box.y=y;
boxBase.x=x;
boxBase.y=y;
}
+void GameObject::setSize(int w,int h){
+ box.w=w;
+ box.h=h;
+}
+void GameObject::setBaseSize(int w,int h){
+ box.w=w;
+ box.h=h;
+ boxBase.w=w;
+ boxBase.h=h;
+}
+
void GameObject::saveState(){}
void GameObject::loadState(){}
void GameObject::reset(bool save){}
void GameObject::playAnimation(int flags){}
void GameObject::onEvent(int eventType){}
int GameObject::queryProperties(int propertyType,Player* obj){
return 0;
}
void GameObject::getEditorData(std::vector<std::pair<std::string,std::string> >& obj){}
void GameObject::setEditorData(std::map<std::string,std::string>& obj){}
std::string GameObject::getEditorProperty(std::string property){return "";}
void GameObject::setEditorProperty(std::string property,std::string value){}
bool GameObject::loadFromNode(TreeStorageNode* objNode){return true;}
void GameObject::prepareFrame(){}
void GameObject::move(){}
diff --git a/src/GameObjects.h b/src/GameObjects.h
index 9d15dc6..ff18a1d 100644
--- a/src/GameObjects.h
+++ b/src/GameObjects.h
@@ -1,167 +1,175 @@
/*
* Copyright (C) 2011-2012 Me and My Shadow
*
* This file is part of Me and My Shadow.
*
* Me and My Shadow is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Me and My Shadow is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GAME_OBJECTS_H
#define GAME_OBJECTS_H
#include "Globals.h"
#include "TreeStorageNode.h"
#include "Player.h"
#include <SDL/SDL.h>
#include <string>
#include <vector>
#include <utility>
#include <map>
class Game;
class Player;
//The different gameObject events.
enum GameObjectEventType{
//Event called when the player walks on the gameObject.
GameObjectEvent_PlayerWalkOn=1,
//Event called when the player is on the gameObject.
GameObjectEvent_PlayerIsOn,
//Event called when the player leaves the gameObject.
GameObjectEvent_PlayerLeave,
//Event called when the gameObject is created.
//Only used for scripting purpose.
GameObjectEvent_OnCreate,
//Event called every frame.
//Only used for scripting purpose.
GameObjectEvent_OnEnterFrame,
//Event called when the player toggles it. (DOWN key)
GameObjectEvent_OnToggle=0x10000,
//Event called when the player switches it on. (DOWN key)
GameObjectEvent_OnSwitchOn=0x10001,
//Event called when the player switches it off. (DOWN key)
GameObjectEvent_OnSwitchOff=0x10002,
};
//The different gameObject properties.
enum GameObjectPropertyType{
//If the player can walk on the gameObject.
GameObjectProperty_PlayerCanWalkOn=1,
//If the object is spiked.
GameObjectProperty_IsSpikes,
//If the gameObject has some flags.
GameObjectProperty_Flags,
};
//The different box types that can be requested using the getBox(int boxType) method.
enum GameObjectBoxType{
//Box of the current position.
BoxType_Current=0,
//Box of the base/start position.
BoxType_Base,
//Box of the previous position.
BoxType_Previous,
//The movement of the block since last position.
BoxType_Delta,
//The velocity for when the player is standing on it.
BoxType_Velocity,
};
//The GameObject class.
class GameObject{
protected:
//The box of the gameObject.
//It's used for the current location of the gameObject and its size.
SDL_Rect box;
//The base location of the game object.
SDL_Rect boxBase;
public:
//The type of the GameObject.
int type;
//Pointer to the Game state.
Game* parent;
//Constructor.
//parent: Pointer to the Game state.
GameObject(Game* parent);
//Destructor.
~GameObject();
//Method used to retrieve a certain box from the GameObject.
//boxType: The type of box that is requested. (default=0)
//Returns: An SDL_Rect.
virtual SDL_Rect getBox(int boxType=0);
//This method is used to place the location on a given location.
//x: The x location to place the gameObject.
//y: The y location to place the gameObject.
virtual void setLocation(int x,int y);
//This method is used to set the base of an object to a given location.
//x: The x location to place the gameObject.
//y: The y location to place the gameObject.
virtual void setBaseLocation(int x,int y);
+ //This method sets the size of the object to a given size.
+ //w: The new width of the gameObject.
+ //h: The new height the gameObject.
+ virtual void setSize(int w,int h);
+ //This method sets the size of the base of the object to a given size.
+ //w: The new width of the gameObject.
+ //h: The new height of the gameObject.
+ virtual void setBaseSize(int w,int h);
//Method used to draw the GameObject.
virtual void show()=0;
//Save the state of the GameObject, used for moving blocks, etc.
virtual void saveState();
//Load the state of the GameObject, used for moving blocks, etc.
virtual void loadState();
//Reset the state of the GameObject, used for moving blocks, etc.
//save: Boolean if the saved state should also be reset.
virtual void reset(bool save);
//Play an animation.
//flags: TODO???
virtual void playAnimation(int flags);
//Invoke an event of the GameObject.
//eventType: The event type.
virtual void onEvent(int eventType);
//Method used to request certain properties of the GameObject.
//propertyType: The property that is requested.
//obj: Pointer to the player.
virtual int queryProperties(int propertyType,Player* obj);
//Method used to retrieve the additional editor data for the GameObject.
//Used for messages, moving positions, etc...
//obj: Vector containing the editorData pairs. (key, value)
virtual void getEditorData(std::vector<std::pair<std::string,std::string> >& obj);
//Set the editorData.
//obj: Map containing the key/value for the editor data.
virtual void setEditorData(std::map<std::string,std::string>& obj);
//Get a single property of the block.
//property: The property to return.
//Returns: The value for the requested property.
virtual std::string getEditorProperty(std::string property);
//Set a single property of the block.
//property: The property to set.
//value: The new value for the property.
virtual void setEditorProperty(std::string property,std::string value);
//Method for loading the GameObject from a node.
//objNode: Pointer to the storage node to load from.
//Returns: True if it succeeds without errors.
virtual bool loadFromNode(TreeStorageNode* objNode);
//Method that is called before the move method.
//It can be used to reset variables like delta movement and velocity.
virtual void prepareFrame();
//Update method for GameObjects, used for moving blocks.
virtual void move();
};
#endif
diff --git a/src/ScriptAPI.cpp b/src/ScriptAPI.cpp
index c1d8066..670bec0 100644
--- a/src/ScriptAPI.cpp
+++ b/src/ScriptAPI.cpp
@@ -1,953 +1,1079 @@
/*
* Copyright (C) 2012-2013 Me and My Shadow
*
* This file is part of Me and My Shadow.
*
* Me and My Shadow is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Me and My Shadow is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Me and My Shadow. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ScriptAPI.h"
#include "ScriptExecutor.h"
#include "Functions.h"
#include "Game.h"
#include <iostream>
using namespace std;
///////////////////////////BLOCK SPECIFIC///////////////////////////
int getBlockById(lua_State* state){
//Get the number of args, this MUST be one.
int args=lua_gettop(state);
if(args!=1){
lua_pushstring(state,"Incorrect number of arguments for getBlockById, expected 1.");
lua_error(state);
}
//Make sure the given argument is an id (string).
if(!lua_isstring(state,1)){
lua_pushstring(state,"Invalid type for argument 1 of getBlockById, should be string.");
lua_error(state);
}
//Check if the currentState is the game state.
Game* game=dynamic_cast<Game*>(currentState);
if(game==NULL) return 0;
//Get the actual game object.
string id=lua_tostring(state,1);
std::vector<Block*>& levelObjects=game->levelObjects;
Block* object=NULL;
for(unsigned int i=0;i<levelObjects.size();i++){
if(levelObjects[i]->getEditorProperty("id")==id){
object=levelObjects[i];
break;
}
}
if(object==NULL){
//Unable to find the requested object.
//Return nothing, will result in a nil in the script.
return 0;
}
//Create the userdatum.
object->createUserData(state,"block");
//We return one object, the userdatum.
return 1;
}
int getBlocksById(lua_State* state){
//Get the number of args, this MUST be one.
int args=lua_gettop(state);
if(args!=1){
lua_pushstring(state,"Incorrect number of arguments for getBlocksById, expected 1.");
lua_error(state);
}
//Make sure the given argument is an id (string).
if(!lua_isstring(state,1)){
lua_pushstring(state,"Invalid type for argument 1 of getBlocksById, should be string.");
lua_error(state);
}
//Check if the currentState is the game state.
Game* game=dynamic_cast<Game*>(currentState);
if(game==NULL) return 0;
//Get the actual game object.
string id=lua_tostring(state,1);
std::vector<Block*>& levelObjects=game->levelObjects;
std::vector<Block*> result;
for(unsigned int i=0;i<levelObjects.size();i++){
if(levelObjects[i]->getEditorProperty("id")==id){
result.push_back(levelObjects[i]);
}
}
//Create the table that will hold the result.
lua_createtable(state,result.size(),0);
//Loop through the results.
for(unsigned int i=0;i<result.size();i++){
//Create the userdatum.
result[i]->createUserData(state,"block");
//And set the table.
lua_rawseti(state,-2,i+1);
}
//We return one object, the userdatum.
return 1;
}
+int moveBlockTo(lua_State* state){
+ //Check the number of arguments.
+ int args=lua_gettop(state);
+
+ //Make sure the number of arguments is correct.
+ if(args!=3){
+ lua_pushstring(state,"Incorrect number of arguments for moveBlockTo, expected 3.");
+ lua_error(state);
+ }
+ //Check if the arguments are of the right type.
+ if(!lua_isuserdata(state,1)){
+ lua_pushstring(state,"Invalid type for argument 1 of moveBlockTo.");
+ lua_error(state);
+ }
+ if(!lua_isnumber(state,2)){
+ lua_pushstring(state,"Invalid type for argument 2 of moveBlockTo, should be integer.");
+ lua_error(state);
+ }
+ if(!lua_isnumber(state,3)){
+ lua_pushstring(state,"Invalid type for argument 3 of moveBlockTo, should be integer.");
+ lua_error(state);
+ }
+
+ //Now get the pointer to the object.
+ Block* object = Block::getObjectFromUserData(state,1);
+ if(object==NULL) return 0;
+
+ int x=lua_tonumber(state,2);
+ int y=lua_tonumber(state,3);
+ object->moveTo(x,y);
+
+ return 0;
+}
+
int getBlockLocation(lua_State* state){
//Make sure there's only one argument and that argument is an userdatum.
int args=lua_gettop(state);
if(args!=1){
lua_pushstring(state,"Incorrect number of arguments for getBlockLocation, expected 1.");
lua_error(state);
}
if(!lua_isuserdata(state,1)){
lua_pushstring(state,"Invalid type for argument 1 of getBlockLocation.");
lua_error(state);
}
Block* object = Block::getObjectFromUserData(state,1);
if(object==NULL) return 0;
//Get the object.
lua_pushnumber(state,object->getBox().x);
lua_pushnumber(state,object->getBox().y);
return 2;
}
int setBlockLocation(lua_State* state){
//Check the number of arguments.
int args=lua_gettop(state);
//Make sure the number of arguments is correct.
if(args!=3){
lua_pushstring(state,"Incorrect number of arguments for setBlockLocation, expected 3.");
lua_error(state);
}
//Check if the arguments are of the right type.
if(!lua_isuserdata(state,1)){
lua_pushstring(state,"Invalid type for argument 1 of setBlockLocation.");
lua_error(state);
}
if(!lua_isnumber(state,2)){
lua_pushstring(state,"Invalid type for argument 2 of setBlockLocation, should be integer.");
lua_error(state);
}
if(!lua_isnumber(state,3)){
lua_pushstring(state,"Invalid type for argument 3 of setBlockLocation, should be integer.");
lua_error(state);
}
//Now get the pointer to the object.
Block* object = Block::getObjectFromUserData(state,1);
if(object==NULL) return 0;
int x=lua_tonumber(state,2);
int y=lua_tonumber(state,3);
object->setLocation(x,y);
return 0;
}
+int growBlockTo(lua_State* state){
+ //Check the number of arguments.
+ int args=lua_gettop(state);
+
+ //Make sure the number of arguments is correct.
+ if(args!=3){
+ lua_pushstring(state,"Incorrect number of arguments for growBlockTo, expected 3.");
+ lua_error(state);
+ }
+ //Check if the arguments are of the right type.
+ if(!lua_isuserdata(state,1)){
+ lua_pushstring(state,"Invalid type for argument 1 of growBlockTo.");
+ lua_error(state);
+ }
+ if(!lua_isnumber(state,2)){
+ lua_pushstring(state,"Invalid type for argument 2 of growBlockTo, should be integer.");
+ lua_error(state);
+ }
+ if(!lua_isnumber(state,3)){
+ lua_pushstring(state,"Invalid type for argument 3 of growBlockTo, should be integer.");
+ lua_error(state);
+ }
+
+ //Now get the pointer to the object.
+ Block* object = Block::getObjectFromUserData(state,1);
+ if(object==NULL) return 0;
+
+ int w=lua_tonumber(state,2);
+ int h=lua_tonumber(state,3);
+ object->growTo(w,h);
+
+ return 0;
+}
+
+int getBlockSize(lua_State* state){
+ //Make sure there's only one argument and that argument is an userdatum.
+ int args=lua_gettop(state);
+ if(args!=1){
+ lua_pushstring(state,"Incorrect number of arguments for getBlockSize, expected 1.");
+ lua_error(state);
+ }
+ if(!lua_isuserdata(state,1)){
+ lua_pushstring(state,"Invalid type for argument 1 of getBlockSize.");
+ lua_error(state);
+ }
+ Block* object = Block::getObjectFromUserData(state,1);
+ if(object==NULL) return 0;
+
+ //Get the object.
+ lua_pushnumber(state,object->getBox().w);
+ lua_pushnumber(state,object->getBox().h);
+ return 2;
+}
+
+int setBlockSize(lua_State* state){
+ //Check the number of arguments.
+ int args=lua_gettop(state);
+
+ //Make sure the number of arguments is correct.
+ if(args!=3){
+ lua_pushstring(state,"Incorrect number of arguments for setBlockSize, expected 3.");
+ lua_error(state);
+ }
+ //Check if the arguments are of the right type.
+ if(!lua_isuserdata(state,1)){
+ lua_pushstring(state,"Invalid type for argument 1 of setBlockSize.");
+ lua_error(state);
+ }
+ if(!lua_isnumber(state,2)){
+ lua_pushstring(state,"Invalid type for argument 2 of setBlockSize, should be integer.");
+ lua_error(state);
+ }
+ if(!lua_isnumber(state,3)){
+ lua_pushstring(state,"Invalid type for argument 3 of setBlockSize, should be integer.");
+ lua_error(state);
+ }
+
+ //Now get the pointer to the object.
+ Block* object = Block::getObjectFromUserData(state,1);
+ if(object==NULL) return 0;
+
+ int w=lua_tonumber(state,2);
+ int h=lua_tonumber(state,3);
+ object->setSize(w,h);
+
+ return 0;
+}
+
int getBlockType(lua_State* state){
int args=lua_gettop(state);
if(args!=1){
lua_pushstring(state,"Incorrect number of arguments for getBlockType, expected 1.");
lua_error(state);
}
if(!lua_isuserdata(state,1)){
lua_pushstring(state,"Invalid type for argument 1 of getBlockType.");
lua_error(state);
}
Block* object = Block::getObjectFromUserData(state,1);
if(object==NULL || object->type<0 || object->type>=TYPE_MAX) return 0;
lua_pushstring(state,Game::blockName[object->type]);
return 1;
}
int changeBlockThemeState(lua_State* state){
int args=lua_gettop(state);
if(args!=2){
lua_pushstring(state,"Incorrect number of arguments for changeBlockThemeState, expected 2.");
lua_error(state);
}
if(!lua_isuserdata(state,1)){
lua_pushstring(state,"Invalid type for argument 1 of changeBlockThemeState.");
lua_error(state);
}
if(!lua_isstring(state,2)){
lua_pushstring(state,"Invalid type for argument 2 of changeBlockThemeState, should be string.");
lua_error(state);
}
Block* object = Block::getObjectFromUserData(state,1);
object->appearance.changeState(lua_tostring(state,2));
return 0;
}
int setBlockEnabled(lua_State* state){
int args=lua_gettop(state);
if(args!=2){
lua_pushstring(state,"Incorrect number of arguments for setBlockEnabled, expected 2.");
lua_error(state);
}
if(!lua_isuserdata(state,1)){
lua_pushstring(state,"Invalid type for argument 1 of setBlockEnabled.");
lua_error(state);
}
if(!lua_isboolean(state,2)){
lua_pushstring(state,"Invalid type for argument 2 of setBlockEnabled, should be boolean.");
lua_error(state);
}
Block* object = Block::getObjectFromUserData(state,1);
if(object==NULL)
return 0;
bool enabled=lua_toboolean(state,2);
object->enabled=enabled;
return 0;
}
int isBlockEnabled(lua_State* state){
int args=lua_gettop(state);
if(args!=1){
lua_pushstring(state,"Incorrect number of arguments for isBlockEnabled, expected 1.");
lua_error(state);
}
if(!lua_isuserdata(state,1)){
lua_pushstring(state,"Invalid type for argument 1 of isBlockEnabled.");
lua_error(state);
}
Block* object = Block::getObjectFromUserData(state,1);
if(object==NULL)
return 0;
lua_pushboolean(state,object->enabled);
return 1;
}
int getBlockEventHandler(lua_State* state){
int args=lua_gettop(state);
if(args!=2){
lua_pushstring(state,"Incorrect number of arguments for getBlockEventHandler, expected 2.");
lua_error(state);
}
if(!lua_isuserdata(state,1)){
lua_pushstring(state,"Invalid type for argument 1 of getBlockEventHandler.");
lua_error(state);
}
if(!lua_isstring(state,2)){
lua_pushstring(state,"Invalid type for argument 2 of getBlockEventHandler, should be string.");
lua_error(state);
}
Block* object = Block::getObjectFromUserData(state,1);
if(object==NULL) return 0;
//Check event type
string eventType=lua_tostring(state,2);
map<string,int>::iterator it=Game::gameObjectEventNameMap.find(eventType);
if(it==Game::gameObjectEventNameMap.end()) return 0;
//Check compiled script
map<int,int>::iterator script=object->compiledScripts.find(it->second);
if(script==object->compiledScripts.end()) return 0;
//Get event handler
lua_rawgeti(state,LUA_REGISTRYINDEX,script->second);
return 1;
}
//It will return old event handler.
int setBlockEventHandler(lua_State* state){
int args=lua_gettop(state);
if(args!=3){
lua_pushstring(state,"Incorrect number of arguments for setBlockEventHandler, expected 3.");
lua_error(state);
}
if(!lua_isuserdata(state,1)){
lua_pushstring(state,"Invalid type for argument 1 of setBlockEventHandler.");
lua_error(state);
}
if(!lua_isstring(state,2)){
lua_pushstring(state,"Invalid type for argument 2 of setBlockEventHandler, should be string.");
lua_error(state);
}
if(!lua_isfunction(state,3) && !lua_isnil(state,3)){
lua_pushstring(state,"Invalid type for argument 3 of setBlockEventHandler, should be function.");
lua_error(state);
}
Block* object = Block::getObjectFromUserData(state,1);
if(object==NULL) return 0;
//Check event type
string eventType=lua_tostring(state,2);
map<string,int>::const_iterator it=Game::gameObjectEventNameMap.find(eventType);
if(it==Game::gameObjectEventNameMap.end()){
lua_pushfstring(state,"Unknown block event type: '%s'.",eventType.c_str());
lua_error(state);
}
//Check compiled script
int scriptIndex=LUA_REFNIL;
{
map<int,int>::iterator script=object->compiledScripts.find(it->second);
if(script!=object->compiledScripts.end()) scriptIndex=script->second;
}
//Set new event handler
object->compiledScripts[it->second]=luaL_ref(state,LUA_REGISTRYINDEX);
//Get old event handler and unreference it
lua_rawgeti(state,LUA_REGISTRYINDEX,scriptIndex);
luaL_unref(state,LUA_REGISTRYINDEX,scriptIndex);
return 1;
}
//Array with the methods for the block library.
static const struct luaL_Reg blocklib_m[]={
{"getBlockById",getBlockById},
{"getBlocksById",getBlocksById},
+ {"moveTo",moveBlockTo},
{"getLocation",getBlockLocation},
{"setLocation",setBlockLocation},
+ {"growTo",growBlockTo},
+ {"getSize",getBlockSize},
+ {"setSize",setBlockSize},
{"getType",getBlockType},
{"changeThemeState",changeBlockThemeState},
{"setEnabled",setBlockEnabled},
{"isEnabled",isBlockEnabled},
{"getEventHandler",getBlockEventHandler},
{"setEventHandler",setBlockEventHandler},
{NULL,NULL}
};
int luaopen_block(lua_State* state){
luaL_newlib(state,blocklib_m);
//Create the metatable for the block userdata.
luaL_newmetatable(state,"block");
lua_pushstring(state,"__index");
lua_pushvalue(state,-2);
lua_settable(state,-3);
Block::registerMetatableFunctions(state,-3);
//Register the functions and methods.
luaL_setfuncs(state,blocklib_m,0);
return 1;
}
//////////////////////////PLAYER SPECIFIC///////////////////////////
struct PlayerUserDatum{
char sig1,sig2,sig3,sig4;
};
Player* getPlayerFromUserData(lua_State* state,int idx){
PlayerUserDatum* ud=(PlayerUserDatum*)lua_touserdata(state,1);
//Make sure the user datum isn't null.
if(!ud) return NULL;
//Get the game state.
Game* game=dynamic_cast<Game*>(currentState);
if(game==NULL) return NULL;
Player* player=NULL;
//Check the signature to see if it's the player or the shadow.
if(ud->sig1=='P' && ud->sig2=='L' && ud->sig3=='Y' && ud->sig4=='R')
player=&game->player;
else if(ud->sig1=='S' && ud->sig2=='H' && ud->sig3=='D' && ud->sig4=='W')
player=&game->shadow;
return player;
}
int getPlayerLocation(lua_State* state){
//Make sure there's only one argument and that argument is an userdatum.
int args=lua_gettop(state);
if(args!=1){
lua_pushstring(state,"Incorrect number of arguments for getPlayerLocation, expected 1.");
lua_error(state);
}
if(!lua_isuserdata(state,1)){
lua_pushstring(state,"Invalid type for argument 1 of getPlayerLocation.");
lua_error(state);
}
Player* player=getPlayerFromUserData(state,1);
if(player==NULL) return 0;
//Get the object.
lua_pushnumber(state,player->getBox().x);
lua_pushnumber(state,player->getBox().y);
return 2;
}
int setPlayerLocation(lua_State* state){
//Make sure there are three arguments, userdatum and two integers.
int args=lua_gettop(state);
if(args!=3){
lua_pushstring(state,"Incorrect number of arguments for setPlayerLocation, expected 3.");
lua_error(state);
}
//Check if the arguments are of the right type.
if(!lua_isuserdata(state,1)){
lua_pushstring(state,"Invalid type for argument 1 of setPlayerLocation.");
lua_error(state);
}
if(!lua_isnumber(state,2)){
lua_pushstring(state,"Invalid type for argument 2 of setPlayerLocation, should be integer.");
lua_error(state);
}
if(!lua_isnumber(state,3)){
lua_pushstring(state,"Invalid type for argument 3 of setPlayerLocation, should be integer.");
lua_error(state);
}
//Get the player.
Player* player=getPlayerFromUserData(state,1);
if(player==NULL) return 0;
//Get the new location.
int x=lua_tonumber(state,2);
int y=lua_tonumber(state,3);
player->setLocation(x,y);
return 0;
}
int setPlayerJump(lua_State* state){
//Make sure there are three arguments, userdatum and one integers.
int args=lua_gettop(state);
if(args!=1 && args!=2){
lua_pushstring(state,"Incorrect number of arguments for setPlayerJump, expected 1 or 2.");
lua_error(state);
}
//Check if the arguments are of the right type.
if(!lua_isuserdata(state,1)){
lua_pushstring(state,"Invalid type for argument 1 of setPlayerJump.");
lua_error(state);
}
if(args==2 && !lua_isnumber(state,2)){
lua_pushstring(state,"Invalid type for argument 2 of setPlayerJump, should be integer.");
lua_error(state);
}
//Get the player.
Player* player=getPlayerFromUserData(state,1);
if(player==NULL) return 0;
//Get the new location.
if(args==2){
int yVel=lua_tonumber(state,2);
player->jump(yVel);
}else{
//Use default jump strength.
player->jump();
}
return 0;
}
int isPlayerShadow(lua_State* state){
//Make sure there's only one argument and that argument is an userdatum.
int args=lua_gettop(state);
if(args!=1){
lua_pushstring(state,"Incorrect number of arguments for isPlayerShadow, expected 1.");
lua_error(state);
}
if(!lua_isuserdata(state,1)){
lua_pushstring(state,"Invalid type for argument 1 of isPlayerShadow.");
lua_error(state);
}
Player* player=getPlayerFromUserData(state,1);
if(player==NULL) return 0;
lua_pushboolean(state,player->isShadow());
return 1;
}
int getPlayerCurrentStand(lua_State* state){
//Get the number of args, this MUST be one.
int args=lua_gettop(state);
if(args!=1){
lua_pushstring(state,"Incorrect number of arguments for getPlayerCurrentStand, expected 1.");
lua_error(state);
}
//Make sure the given argument is a player userdatum.
if(!lua_isuserdata(state,1)){
lua_pushstring(state,"Invalid type for argument 1 of getPlayerCurrentStand.");
lua_error(state);
}
Player* player=getPlayerFromUserData(state,1);
if(player==NULL) return 0;
//Get the actual game object.
Block* object=player->getObjCurrentStand();
if(object==NULL){
return 0;
}
//Create the userdatum.
object->createUserData(state,"block");
//We return one object, the userdatum.
return 1;
}
//Array with the methods for the player and shadow library.
static const struct luaL_Reg playerlib_m[]={
{"getLocation",getPlayerLocation},
{"setLocation",setPlayerLocation},
{"jump",setPlayerJump},
{"isShadow",isPlayerShadow},
{"getCurrentStand",getPlayerCurrentStand},
{NULL,NULL}
};
int luaopen_player(lua_State* state){
luaL_newlib(state,playerlib_m);
//Create the metatable for the player userdata.
luaL_newmetatable(state,"player");
lua_pushstring(state,"__index");
lua_pushvalue(state,-2);
lua_settable(state,-3);
//Now create two default player user data, one for the player and one for the shadow.
PlayerUserDatum* ud=(PlayerUserDatum*)lua_newuserdata(state,sizeof(PlayerUserDatum));
ud->sig1='P';ud->sig2='L';ud->sig3='Y';ud->sig4='R';
luaL_getmetatable(state,"player");
lua_setmetatable(state,-2);
lua_setglobal(state,"player");
ud=(PlayerUserDatum*)lua_newuserdata(state,sizeof(PlayerUserDatum));
ud->sig1='S';ud->sig2='H';ud->sig3='D';ud->sig4='W';
luaL_getmetatable(state,"player");
lua_setmetatable(state,-2);
lua_setglobal(state,"shadow");
//Register the functions and methods.
luaL_setfuncs(state,playerlib_m,0);
return 1;
}
//////////////////////////LEVEL SPECIFIC///////////////////////////
int getLevelSize(lua_State* state){
//NOTE: this function accepts 0 arguments, but we ignore the argument count.
//Returns level size.
lua_pushinteger(state,LEVEL_WIDTH);
lua_pushinteger(state,LEVEL_HEIGHT);
return 2;
}
int getLevelWidth(lua_State* state){
//NOTE: this function accepts 0 arguments, but we ignore the argument count.
//Returns level size.
lua_pushinteger(state,LEVEL_WIDTH);
return 1;
}
int getLevelHeight(lua_State* state){
//NOTE: this function accepts 0 arguments, but we ignore the argument count.
//Returns level size.
lua_pushinteger(state,LEVEL_HEIGHT);
return 1;
}
int getLevelName(lua_State* state){
//NOTE: this function accepts 0 arguments, but we ignore the argument count.
//Check if the currentState is the game state.
Game* game=dynamic_cast<Game*>(currentState);
if(game==NULL) return 0;
//Returns level name.
lua_pushstring(state,game->getLevelName().c_str());
return 1;
}
int getLevelEventHandler(lua_State* state){
int args=lua_gettop(state);
if(args!=1){
lua_pushstring(state,"Incorrect number of arguments for getLevelEventHandler, expected 1.");
lua_error(state);
}
if(!lua_isstring(state,1)){
lua_pushstring(state,"Invalid type for argument 1 of getLevelEventHandler, should be string.");
lua_error(state);
}
//Check if the currentState is the game state.
Game* game=dynamic_cast<Game*>(currentState);
if(game==NULL) return 0;
//Check event type
string eventType=lua_tostring(state,1);
map<string,int>::iterator it=Game::levelEventNameMap.find(eventType);
if(it==Game::levelEventNameMap.end()) return 0;
//Check compiled script
map<int,int>::iterator script=game->compiledScripts.find(it->second);
if(script==game->compiledScripts.end()) return 0;
//Get event handler
lua_rawgeti(state,LUA_REGISTRYINDEX,script->second);
return 1;
}
//It will return old event handler.
int setLevelEventHandler(lua_State* state){
int args=lua_gettop(state);
if(args!=2){
lua_pushstring(state,"Incorrect number of arguments for setLevelEventHandler, expected 2.");
lua_error(state);
}
if(!lua_isstring(state,1)){
lua_pushstring(state,"Invalid type for argument 1 of setLevelEventHandler, should be string.");
lua_error(state);
}
if(!lua_isfunction(state,2) && !lua_isnil(state,2)){
lua_pushstring(state,"Invalid type for argument 2 of setLevelEventHandler, should be function.");
lua_error(state);
}
//Check if the currentState is the game state.
Game* game=dynamic_cast<Game*>(currentState);
if(game==NULL) return 0;
//Check event type
string eventType=lua_tostring(state,1);
map<string,int>::const_iterator it=Game::levelEventNameMap.find(eventType);
if(it==Game::levelEventNameMap.end()){
lua_pushfstring(state,"Unknown level event type: '%s'.",eventType.c_str());
lua_error(state);
}
//Check compiled script
int scriptIndex=LUA_REFNIL;
{
map<int,int>::iterator script=game->compiledScripts.find(it->second);
if(script!=game->compiledScripts.end()) scriptIndex=script->second;
}
//Set new event handler
game->compiledScripts[it->second]=luaL_ref(state,LUA_REGISTRYINDEX);
//Get old event handler and unreference it
lua_rawgeti(state,LUA_REGISTRYINDEX,scriptIndex);
luaL_unref(state,LUA_REGISTRYINDEX,scriptIndex);
return 1;
}
int winGame(lua_State* state){
//NOTE: this function accepts 0 arguments, but we ignore the argument count.
//Check if the currentState is the game state.
if(stateID==STATE_LEVEL_EDITOR)
return 0;
Game* game=dynamic_cast<Game*>(currentState);
if(game==NULL) return 0;
game->won=true;
return 0;
}
int getGameTime(lua_State* state){
//NOTE: this function accepts 0 arguments, but we ignore the argument count.
//Check if the currentState is the game state.
Game* game=dynamic_cast<Game*>(currentState);
if(game==NULL) return 0;
//Returns level size.
lua_pushinteger(state,game->time);
return 1;
}
int getGameRecordings(lua_State* state){
//NOTE: this function accepts 0 arguments, but we ignore the argument count.
//Check if the currentState is the game state.
Game* game=dynamic_cast<Game*>(currentState);
if(game==NULL) return 0;
//Returns level size.
lua_pushinteger(state,game->recordings);
return 1;
}
//Array with the methods for the level library.
static const struct luaL_Reg levellib_m[]={
{"getSize",getLevelSize},
{"getWidth",getLevelWidth},
{"getHeight",getLevelHeight},
{"getName",getLevelName},
{"getEventHandler",getLevelEventHandler},
{"setEventHandler",setLevelEventHandler},
{"win",winGame},
{"getTime",getGameTime},
{"getRecordings",getGameRecordings},
{NULL,NULL}
};
int luaopen_level(lua_State* state){
luaL_newlib(state,levellib_m);
//Register the functions and methods.
luaL_setfuncs(state,levellib_m,0);
return 1;
}
/////////////////////////CAMERA SPECIFIC///////////////////////////
int setCameraMode(lua_State* state){
//Get the number of args, this MUST be one.
int args=lua_gettop(state);
if(args!=1){
lua_pushstring(state,"Incorrect number of arguments for setCameraMode, expected 1.");
lua_error(state);
}
//Make sure the given argument is a string.
if(!lua_isstring(state,1)){
lua_pushstring(state,"Invalid type for argument 1 of setCameraMode, should be string.");
lua_error(state);
}
string mode=lua_tostring(state,1);
//Get the game for setting the camera.
Game* game=dynamic_cast<Game*>(currentState);
if(game==NULL) return 0;
//Check which mode.
if(mode=="player"){
game->cameraMode=Game::CAMERA_PLAYER;
}else if(mode=="shadow"){
game->cameraMode=Game::CAMERA_SHADOW;
}else{
//Unkown OR invalid camera mode.
lua_pushfstring(state,"Unkown or invalid camera mode for setCameraMode: '%s'.",mode.c_str());
lua_error(state);
}
//Returns nothing.
return 0;
}
int cameraLookAt(lua_State* state){
//Get the number of args, this MUST be two (x and y).
int args=lua_gettop(state);
if(args!=2){
lua_pushstring(state,"Incorrect number of arguments for cameraLookAt, expected 2.");
lua_error(state);
}
//Make sure the given arguments are integers.
if(!lua_isnumber(state,1)){
lua_pushstring(state,"Invalid type for argument 1 of cameraLookAt, should be integer.");
lua_error(state);
}
if(!lua_isnumber(state,2)){
lua_pushstring(state,"Invalid type for argument 2 of cameraLookAt, should be integer.");
lua_error(state);
}
//Get the point.
int x=lua_tonumber(state,1);
int y=lua_tonumber(state,2);
//Get the game for setting the camera.
Game* game=dynamic_cast<Game*>(currentState);
if(game==NULL) return 0;
game->cameraMode=Game::CAMERA_CUSTOM;
game->cameraTarget.x=x;
game->cameraTarget.y=y;
return 0;
}
//Array with the methods for the camera library.
static const struct luaL_Reg cameralib_m[]={
{"setMode",setCameraMode},
{"lookAt",cameraLookAt},
{NULL,NULL}
};
int luaopen_camera(lua_State* state){
luaL_newlib(state,cameralib_m);
//Register the functions and methods.
luaL_setfuncs(state,cameralib_m,0);
return 1;
}
/////////////////////////AUDIO SPECIFIC///////////////////////////
int playSound(lua_State* state){
//Get the number of args, this can be anything from one to three.
int args=lua_gettop(state);
if(args<1 || args>3){
lua_pushstring(state,"Incorrect number of arguments for playSound, expected 1-3.");
lua_error(state);
}
//Make sure the first argument is a string.
if(!lua_isstring(state,1)){
lua_pushstring(state,"Invalid type for argument 1 of playSound, should be string.");
lua_error(state);
}
//Default values for concurrent and force.
//See SoundManager.h
int concurrent=1;
bool force=false;
//If there's a second one it should be an integer.
if(args>1){
if(!lua_isnumber(state,2)){
lua_pushstring(state,"Invalid type for argument 2 of playSound, should be integer.");
lua_error(state);
}else{
concurrent=lua_tonumber(state,2);
}
}
//If there's a third one it should be a boolean.
if(args>2){
if(!lua_isboolean(state,3)){
lua_pushstring(state,"Invalid type for argument 3 of playSound, should be boolean.");
lua_error(state);
}else{
force=lua_toboolean(state,3);
}
}
//Get the name of the sound.
string sound=lua_tostring(state,1);
//Try to play the sound.
getSoundManager()->playSound(sound,concurrent,force);
//Returns nothing.
return 0;
}
int playMusic(lua_State* state){
//Get the number of args, this can be either one or two.
int args=lua_gettop(state);
if(args<1 || args>2){
lua_pushstring(state,"Incorrect number of arguments for playMusic, expected 1 or 2.");
lua_error(state);
}
//Make sure the first argument is a string.
if(!lua_isstring(state,1)){
lua_pushstring(state,"Invalid type for argument 1 of playMusic, should be string.");
lua_error(state);
}
//Default value of fade for playMusic.
//See MusicManager.h.
bool fade=true;
//If there's a second one it should be a boolean.
if(args>1){
if(!lua_isboolean(state,2)){
lua_pushstring(state,"Invalid type for argument 2 of playMusic, should be boolean.");
lua_error(state);
}else{
fade=lua_toboolean(state,2);
}
}
//Get the name of the music.
string music=lua_tostring(state,1);
//Try to switch to the new music.
getMusicManager()->playMusic(music,fade);
//Returns nothing.
return 0;
}
int pickMusic(lua_State* state){
//NOTE: this function accepts 0 arguments, but we ignore the argument count.
//Let the music manager pick a song from the current music list.
getMusicManager()->pickMusic();
return 0;
}
int setMusicList(lua_State* state){
//Get the number of args, this MUST be one.
int args=lua_gettop(state);
if(args!=1){
lua_pushstring(state,"Incorrect number of arguments for setMusicList, expected 1.");
lua_error(state);
}
//Make sure the given argument is a string.
if(!lua_isstring(state,1)){
lua_pushstring(state,"Invalid type for argument 1 of setMusicList, should be string.");
lua_error(state);
}
//And set the music list in the music manager.
string list=lua_tostring(state,1);
getMusicManager()->setMusicList(list);
return 0;
}
int getMusicList(lua_State* state){
//NOTE: this function accepts 0 arguments, but we ignore the argument count.
//Return the name of the song (contains list prefix).
lua_pushstring(state,getMusicManager()->getCurrentMusicList().c_str());
return 1;
}
int currentMusicPlaying(lua_State* state){
//NOTE: this function accepts 0 arguments, but we ignore the argument count.
//Return the name of the song (contains list prefix).
lua_pushstring(state,getMusicManager()->getCurrentMusic().c_str());
return 1;
}
//Array with the methods for the audio library.
static const struct luaL_Reg audiolib_m[]={
{"playSound",playSound},
{"playMusic",playMusic},
{"pickMusic",pickMusic},
{"setMusicList",setMusicList},
{"getMusicList",getMusicList},
{"currentMusic",currentMusicPlaying},
{NULL,NULL}
};
int luaopen_audio(lua_State* state){
luaL_newlib(state,audiolib_m);
//Register the functions and methods.
luaL_setfuncs(state,audiolib_m,0);
return 1;
}

File Metadata

Mime Type
text/x-diff
Expires
Sat, May 16, 8:26 PM (1 d, 15 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
63482
Default Alt Text
(78 KB)

Event Timeline