root/trunk/src/mugen/stage.cpp @ 6767

Revision 6767, 73.6 KB (checked in by kazzmir, 2 years ago)

[mugen] handle own animations for super pauses. convert MugenAnimation?* to reference counts

Line 
1#include <fstream>
2#include <iostream>
3#include <algorithm>
4#include <cctype>
5#include <string>
6#include <cstring>
7#include <vector>
8#include <list>
9#include <ostream>
10#include <sstream>
11#include <iostream>
12
13#include "stage.h"
14
15#include "util/init.h"
16#include "state.h"
17
18#include "util/events.h"
19#include "util/funcs.h"
20#include "util/file-system.h"
21#include "util/bitmap.h"
22#include "util/stretch-bitmap.h"
23#include "util/trans-bitmap.h"
24// #include "util/console.h"
25/*
26#include "object/animation.h"
27#include "object/object.h"
28// #include "object/character.h"
29#include "object/object_attack.h"
30// #include "object/player.h"
31*/
32#include "globals.h"
33#include "util/debug.h"
34#include "factory/font_render.h"
35#include "ast/all.h"
36#include "util/timedifference.h"
37#include "character.h"
38#include "helper.h"
39
40#include "parse-cache.h"
41#include "parser/all.h"
42
43#include "animation.h"
44#include "background.h"
45#include "config.h"
46#include "item.h"
47#include "item-content.h"
48#include "section.h"
49#include "projectile.h"
50#include "sound.h"
51#include "reader.h"
52#include "sprite.h"
53#include "util.h"
54#include "characterhud.h"
55
56#include "font.h"
57
58using namespace std;
59
60namespace PaintownUtil = ::Util;
61
62// Some static variables
63static const int CONTROLLER_VALUE_NOT_SET = -999999;
64static const int DEFAULT_BACKGROUND_ID = -9999;
65static const int DEFAULT_OBJECT_OFFSET = 160;
66static const int DEFAULT_WIDTH = 320;
67static const int DEFAULT_HEIGHT = 240;
68static const double DEFAULT_JUMP_VELOCITY = 7.2;
69// static const int CONSOLE_SIZE = 95;
70static const double DEFAULT_X_JUMP_VELOCITY = 2.2;
71
72namespace Mugen{
73
74Effect::Effect(const Character * owner, PaintownUtil::ReferenceCount<MugenAnimation> animation, int id, int x, int y):
75owner(owner),
76/* Copy the animation here so that it can start from frame 0 and not accidentally
77 * be shared with another Effect
78 */
79animation(PaintownUtil::ReferenceCount<MugenAnimation>(new MugenAnimation(*animation))),
80id(id),
81x(x),
82y(y){
83}
84   
85void Effect::draw(const Graphics::Bitmap & work, int cameraX, int cameraY){
86    animation->render((int)(x - cameraX), (int)(y - cameraY), work);
87}
88
89void Effect::logic(){
90    animation->logic();
91}
92
93bool Effect::isDead(){
94    return animation->hasLooped();
95}
96
97Effect::~Effect(){
98}
99
100class Spark: public Effect {
101public:
102    Spark(int x, int y, PaintownUtil::ReferenceCount<MugenAnimation> animation);
103    virtual ~Spark();
104};
105
106Spark::Spark(int x, int y, PaintownUtil::ReferenceCount<MugenAnimation> animation):
107Effect(NULL, animation, -1, x, y){
108}
109
110Spark::~Spark(){
111}
112
113}
114
115static bool centerCollision( Mugen::Object *p1, Mugen::Object *p2 ){
116    //p1->getCurrentMovement()->getCurrentFrame();
117    /* FIXME! */
118    /*
119    const int p1width = p1->getCurrentMovement()->getCurrentFrame()->getWidth(), p1height = p1->getCurrentMovement()->getCurrentFrame()->getHeight();
120    const int p2width = p2->getCurrentMovement()->getCurrentFrame()->getWidth(), p2height = p2->getCurrentMovement()->getCurrentFrame()->getHeight();
121   
122    const double x1 = p1->getX() + ((p1width/2)/2), y1 = 0, x2 = p1->getX() + p1width - ((p1width/2)/2), y2 = p1height,
123              x3 = p2->getX() + ((p2width/2)/2), y3 = 0, x4 = p2->getX() + p2width - ((p2width/2)/2), y4 = p2height;
124   
125    if ( x1 < x3 && x1 < x4 &&
126            x2 < x3 && x2 < x4 ) return false;
127    if ( x1 > x3 && x1 > x4 &&
128            x2 > x3 && x2 > x4 ) return false;
129    if ( y1 < y3 && y1 < y4 &&
130            y2 < y3 && y2 < y4 ) return false;
131    if ( y1 > y3 && y1 > y4 &&
132            y2 > y3 && y2 > y4 ) return false;
133            */
134   
135    return true;
136}
137
138Mugen::Stage::Stage(const Filesystem::AbsolutePath & location):
139location(location),
140baseDir(""),
141name(""),
142startx(0),
143starty(0),
144boundleft(-150),
145boundright(150),
146boundhigh(-25),
147boundlow(0),
148verticalfollow(.2),
149floortension(0),
150tension(60),
151p1startx(-70),
152p1starty(0),
153p1startz(0),
154p1facing(1),
155p2startx(70),
156p2starty(0),
157p2startz(0),
158p2facing(-1),
159leftbound(-1000),
160rightbound(1000),
161topbound(-25),
162botbound(0),
163/*topz(0),
164botz(50),
165topscale(1),
166botscale(1.2),*/
167screenleft(15),
168screenright(15),
169zoffset(200),
170zoffsetlink(DEFAULT_BACKGROUND_ID),
171autoturn(true),
172resetBG(true),
173shadowIntensity(128),
174reflect(false),
175shadowColor(Graphics::makeColor(0,0,0)),
176shadowYscale(0.4),
177shadowFadeRangeHigh(0),
178shadowFadeRangeMid(0),
179reflectionIntensity(0),
180musicVolume(0),
181//sffFile(""),
182//debugbg(false),
183// board(0),
184xaxis(0),
185yaxis(0),
186camerax(0),
187cameray(0),
188stageStart(false),
189ticker(0),
190totalRounds(3),
191round(1),
192totalTime(99),
193time(99),
194p1points(0),
195p2points(0),
196// console(new Console::Console(CONSOLE_SIZE)),
197debugMode(false),
198inleft(0),
199inright(0),
200onLeftSide(0),
201onRightSide(0),
202inabove(0),
203loaded(false),
204gameHUD(NULL),
205gameOver(false),
206gameRate(1),
207cycles(0),
208quake_time(0){
209}
210
211#if 0
212Mugen::Stage::Mugen::Stage( const char * location ):
213World(),
214location( std::string(location) ),
215baseDir(""),
216name(""),
217startx(0),
218starty(0),
219boundleft(-150),
220boundright(150),
221boundhigh(-25),
222boundlow(0),
223verticalfollow(.2),
224floortension(0),
225tension(60),
226p1startx(-70),
227p1starty(0),
228p1startz(0),
229p1facing(1),
230p2startx(70),
231p2starty(0),
232p2startz(0),
233p2facing(-1),
234leftbound(-1000),
235rightbound(1000),
236topbound(-25),
237botbound(0),
238/*topz(0),
239botz(50),
240topscale(1),
241botscale(1.2),*/
242screenleft(15),
243screenright(15),
244zoffset(200),
245zoffsetlink(DEFAULT_BACKGROUND_ID),
246autoturn(true),
247resetBG(true),
248shadowIntensity(128),
249reflect(false),
250shadowColor(Bitmap::makeColor(0,0,0)),
251shadowYscale(0.4),
252shadowFadeRangeHigh(0),
253shadowFadeRangeMid(0),
254reflectionIntensity(0),
255musicVolume(0),
256//sffFile(""),
257//debugbg(false),
258background(0),
259board(0),
260xaxis(0),
261yaxis(0),
262camerax(0),
263cameray(0),
264stageStart(false),
265ticker(0),
266totalRounds(3),
267round(1),
268totalTime(99),
269time(99),
270p1points(0),
271p2points(0),
272console(new Console::Console(CONSOLE_SIZE)),
273debugMode(false),
274inleft(0),
275inright(0),
276onLeftSide(0),
277onRightSide(0),
278inabove(0),
279loaded(false),
280gameHUD(NULL),
281gameOver(false),
282gameRate(1),
283cycles(0){
284}
285#endif
286
287Mugen::Stage::~Stage(){
288    cleanup();
289    if (gameHUD){
290        delete gameHUD;
291    }
292}
293
294/* fix */
295void Mugen::Stage::loadSectionCamera(Ast::Section * section){
296    for (list<Ast::Attribute*>::const_iterator attribute_it = section->getAttributes().begin(); attribute_it != section->getAttributes().end(); attribute_it++){
297        Ast::Attribute * attribute = *attribute_it;
298        if (attribute->getKind() == Ast::Attribute::Simple){
299            Ast::AttributeSimple * simple = (Ast::AttributeSimple*) attribute;
300            if (*simple == "startx"){
301                (*simple).view() >> startx;
302            } else if (*simple == "starty"){
303                simple->view() >> starty;
304            } else if (*simple == "boundleft"){
305                simple->view() >> boundleft;
306            } else if (*simple == "boundright"){
307                simple->view() >> boundright;
308            } else if (*simple == "boundhigh"){
309                simple->view() >> boundhigh;
310            } else if (*simple == "boundlow"){
311                // This is always 0 so don't grab it
312                // *content->getNext() >> boundlow;
313            } else if (*simple == "verticalfollow"){
314                simple->view() >> verticalfollow;
315                if (verticalfollow > 1){
316                    verticalfollow = 1;
317                } else if (verticalfollow < 0){
318                    verticalfollow = 0;
319                }
320            } else if (*simple == "floortension"){
321                simple->view() >> floortension;
322            } else if (*simple == "tension"){
323                simple->view() >> tension;
324            } else {
325                throw MugenException( "Unhandled option in Camera Section: " + simple->toString());
326            }
327        }
328    }
329}
330
331void Mugen::Stage::loadSectionInfo(Ast::Section * section){
332    for (list<Ast::Attribute*>::const_iterator attribute_it = section->getAttributes().begin(); attribute_it != section->getAttributes().end(); attribute_it++){
333        Ast::Attribute * attribute = *attribute_it;
334        if (attribute->getKind() == Ast::Attribute::Simple){
335            Ast::AttributeSimple * simple = (Ast::AttributeSimple*) attribute;
336            if (*simple == "name"){
337                /* use setName() here */
338                simple->view() >> name;
339                Global::debug(1) << "Read name '" << name << "'" << endl;
340            } else if (*simple == "author"){
341                // Seems to be that some people think that author belongs in background defs
342                std::string temp;
343                simple->view() >> temp;
344                Global::debug(1) << "Made by this guy: '" << temp << "'" << endl;
345            } else {
346                throw MugenException( "Unhandled option in Info Section: " + simple->toString());
347            }
348        }
349    }
350}
351
352void Mugen::Stage::loadSectionPlayerInfo(Ast::Section * section){
353    for (list<Ast::Attribute*>::const_iterator attribute_it = section->getAttributes().begin(); attribute_it != section->getAttributes().end(); attribute_it++){
354        Ast::Attribute * attribute = *attribute_it;
355        if (attribute->getKind() == Ast::Attribute::Simple){
356            Ast::AttributeSimple * simple = (Ast::AttributeSimple*) attribute;
357            if (*simple == "p1startx"){
358                simple->view() >> p1startx;
359            } else if (*simple == "p1starty"){
360                simple->view() >> p1starty;
361            } else if (*simple == "p1startz"){
362                simple->view() >> p1startz;
363            } else if (*simple == "p1facing"){
364                simple->view() >> p1facing;
365            } else if (*simple == "p2startx"){
366                simple->view() >> p2startx;
367            } else if (*simple == "p2starty"){
368                simple->view() >> p2starty;
369            } else if (*simple == "p2startz"){
370                simple->view() >> p2startz;
371            } else if (*simple == "p2facing"){
372                simple->view() >> p2facing;
373            } else if (*simple == "leftbound"){
374                simple->view() >> leftbound;
375            } else if (*simple == "rightbound"){
376                simple->view() >> rightbound;
377            } else if (*simple == "topbound"){
378                simple->view() >> topbound;
379            } else if (*simple == "botbound"){
380                simple->view() >> botbound;
381            } else {
382                throw MugenException("Unhandled option in PlayerInfo Section: " + simple->toString());
383            }
384        }
385    }
386}
387
388void Mugen::Stage::loadSectionBound(Ast::Section * section){
389    for (list<Ast::Attribute*>::const_iterator attribute_it = section->getAttributes().begin(); attribute_it != section->getAttributes().end(); attribute_it++){
390        Ast::Attribute * attribute = *attribute_it;
391        if (attribute->getKind() == Ast::Attribute::Simple){
392            Ast::AttributeSimple * simple = (Ast::AttributeSimple*) attribute;
393            if (*simple == "screenleft"){
394                simple->view() >> screenleft;
395            } else if (*simple == "screenright"){
396                simple->view() >> screenright;
397            } else {
398                throw MugenException("Unhandled option in Bound Section: " + simple->toString());
399            }
400        }
401    }
402}
403
404void Mugen::Stage::loadSectionStageInfo(Ast::Section * section){
405    for (list<Ast::Attribute*>::const_iterator attribute_it = section->getAttributes().begin(); attribute_it != section->getAttributes().end(); attribute_it++){
406        Ast::Attribute * attribute = *attribute_it;
407        if (attribute->getKind() == Ast::Attribute::Simple){
408            Ast::AttributeSimple * simple = (Ast::AttributeSimple*) attribute;
409            if (*simple == "zoffset" ){
410                simple->view() >> zoffset;
411            } else if (*simple == "zoffsetlink" ){
412                simple->view() >> zoffsetlink;
413            } else if (*simple == "autoturn"){
414                simple->view() >> autoturn;
415            } else if (*simple == "resetbg"){
416                simple->view() >> resetBG;
417            } else {
418                throw MugenException("Unhandled option in StageInfo Section: " + simple->toString());
419            }
420        }
421    }
422}
423
424void Mugen::Stage::loadSectionShadow(Ast::Section * section, cymk_holder & shadow){
425    for (list<Ast::Attribute*>::const_iterator attribute_it = section->getAttributes().begin(); attribute_it != section->getAttributes().end(); attribute_it++){
426        Ast::Attribute * attribute = *attribute_it;
427        if (attribute->getKind() == Ast::Attribute::Simple){
428            Ast::AttributeSimple * simple = (Ast::AttributeSimple*) attribute;
429            if (*simple == "intensity"){
430                simple->view() >> shadow.k;
431            // *content->getNext() >> shadowIntensity;
432            // shadow.k = shadowIntensity;
433            } else if (*simple == "reflect"){
434                simple->view() >> reflect;
435            } else if (*simple == "color"){
436                try{
437                    Ast::View view = simple->view();
438                    view >> shadow.c;
439                    view >> shadow.y;
440                    view >> shadow.m;
441                } catch (const Ast::Exception & fail){
442                }
443            } else if (*simple == "yscale"){
444                simple->view() >> shadowYscale;
445            } else if (*simple == "fade.range"){
446                simple->view() >> shadowFadeRangeHigh >> shadowFadeRangeMid;
447            } else {
448                throw MugenException("Unhandled option in Shadow Section: " + simple->toString());
449            }
450        }
451    }
452}
453
454void Mugen::Stage::loadSectionReflection(Ast::Section * section){
455    for (list<Ast::Attribute*>::const_iterator attribute_it = section->getAttributes().begin(); attribute_it != section->getAttributes().end(); attribute_it++){
456        Ast::Attribute * attribute = *attribute_it;
457        if (attribute->getKind() == Ast::Attribute::Simple){
458            Ast::AttributeSimple * simple = (Ast::AttributeSimple*) attribute;
459            if (*simple == "intensity"){
460                simple->view() >> reflectionIntensity;
461            } else {
462                throw MugenException("Unhandled option in Reflection Section: " + simple->toString());
463            }
464        }
465    }
466}
467
468void Mugen::Stage::loadSectionMusic(Ast::Section * section){
469    for (list<Ast::Attribute*>::const_iterator attribute_it = section->getAttributes().begin(); attribute_it != section->getAttributes().end(); attribute_it++){
470        Ast::Attribute * attribute = *attribute_it;
471        if (attribute->getKind() == Ast::Attribute::Simple){
472            Ast::AttributeSimple * simple = (Ast::AttributeSimple*) attribute;
473            if (*simple == "bgmusic"){
474                try {
475                    simple->view() >> music;
476                } catch (const MugenException &ex){
477                }
478            } else if (*simple == "bgvolume"){
479                try {
480                    simple->view() >> musicVolume;
481                } catch (const MugenException &ex){
482                }
483            } else {
484                throw MugenException("Unhandled option in Music Section: " + simple->toString());
485            }
486        }
487    }
488}
489
490int Mugen::Stage::getFloor() const {
491    return currentZOffset();
492}
493
494int Mugen::Stage::currentZOffset() const {
495    if (zoffsetlink != DEFAULT_BACKGROUND_ID){
496        // Link zoffset to id
497        vector<Mugen::BackgroundElement *> elements = background->getIDList(zoffsetlink);
498        if (elements.size() != 0){
499            Mugen::BackgroundElement * element = elements[0];
500            return (int) element->getCurrentY();
501        }
502    }
503
504    return zoffset;
505}
506
507static bool matchRegex(const string & str, const string & regex){
508    return Util::matchRegex(str, regex);
509}
510
511static string regexResult(const string & str, const string & regex){
512    return "";
513}
514
515static Filesystem::AbsolutePath getMotifFile(const string & path){
516    return Mugen::Data::getInstance().getFileFromMotif(Filesystem::RelativePath(path));
517}
518
519void Mugen::Stage::load(){
520    if (loaded){
521        return;
522    }
523#if 0
524    // Lets look for our def since some people think that all file systems are case insensitive
525    baseDir = Filesystem::find("mugen/stages/");
526    Global::debug(1) << baseDir << endl;
527    if (location.find(".def")==std::string::npos){
528        location+=".def";
529    }
530    // Get correct directory
531    baseDir = Mugen::Util::getFileDir(baseDir + location);
532    location = Mugen::Util::stripDir(location);
533    const std::string ourDefFile = Mugen::Util::getCorrectFileLocation(baseDir, location);//Mugen::Util::fixFileName( baseDir, std::string(location) );
534   
535    if (ourDefFile.empty()){
536        throw MugenException( "Cannot locate stage definition file for: " + location );
537    }
538#endif
539    baseDir = location.getDirectory();
540    const Filesystem::AbsolutePath ourDefFile = location;
541   
542    std::string filesdir = "";
543   
544    /* will this screw up on windows??
545     * FIXME: redo this code to work with Path objects instead of their strings
546     */
547    size_t strloc = location.path().find_last_of("/");
548    if (strloc != std::string::npos){
549        filesdir = location.path().substr(0, strloc);
550        filesdir += "/";
551    }
552   
553    Global::debug(1) << "Got subdir: " << filesdir << endl;
554
555    TimeDifference diff;
556    diff.startTime();
557    AstRef parsed(Mugen::Util::parseDef(ourDefFile.path()));
558    diff.endTime();
559    Global::debug(1) << "Parsed mugen file " + ourDefFile.path() + " in" + diff.printTime("") << endl;
560    // list<Ast::Section*> * sections = (list<Ast::Section*>*) Mugen::Def::main(ourDefFile);
561
562    struct cymk_holder shadow;
563   
564    /* Extract info for our first section of our stage */
565    for (Ast::AstParse::section_iterator section_it = parsed->getSections()->begin(); section_it != parsed->getSections()->end(); section_it++){
566        Ast::Section * section = *section_it;
567        std::string head = section->getName();
568        head = Mugen::Util::fixCase(head);
569        if (head == "info"){
570            loadSectionInfo(section);
571        } else if (head == "camera"){
572            loadSectionCamera(section);
573        } else if (head == "playerinfo"){
574            loadSectionPlayerInfo(section);
575        } else if (head == "scaling"){
576            /* not used anymore.. print a warning? */
577        } else if (head == "bound"){
578            loadSectionBound(section);
579        } else if (head == "stageinfo"){
580            loadSectionStageInfo(section);
581        } else if (head == "shadow"){
582            loadSectionShadow(section, shadow);
583        } else if (head == "reflection"){
584            loadSectionReflection(section);
585        /* search for bgdef instead of just assuming its there */
586        /*
587        } else if (matchRegex(head, ".*bgdef.*")){
588            // Background management
589            vector<Ast::Section*> backgroundStuff = Mugen::Util::collectBackgroundStuff(section_it, parsed.getSections()->end());
590            MugenBackgroundManager *manager = new MugenBackgroundManager(baseDir, backgroundStuff, ticker, 0);
591            background = manager;
592            Global::debug(1) << "Got background: '" << manager->getName() << "'" << endl;
593        }*/
594        } else if (head == "music" ){
595           loadSectionMusic(section);
596        } else {
597            // throw MugenException( "Unhandled Section in '" + ourDefFile + "': " + head );
598        }
599    }
600
601    /* backgrounds should always use `BG' as their name */
602    /* FIXME: pass in the parsed data instead of making the background reparse it */
603    background = new Mugen::Background(ourDefFile, "BG");
604   
605    // Setup board our worksurface to the proper size of the entire stage 320x240 :P
606    // Global::debug(1) << "Creating level size of Width: " << abs(boundleft) + boundright << " and Height: " << abs(boundhigh) + boundlow << endl;
607    //board = new Bitmap( DEFAULT_WIDTH, DEFAULT_HEIGHT );
608    // Nope we need it to be the size of the entire board... we then pan the blit so our characters will stay put without fiddling with their x coordinates
609    // board = new Bitmap( abs(boundleft) + boundright + DEFAULT_WIDTH, abs(boundhigh) + boundlow + DEFAULT_HEIGHT);
610    // board = new Graphics::Bitmap(DEFAULT_WIDTH, DEFAULT_HEIGHT);
611    camerax = startx;
612    cameray = starty;
613    // xaxis = (abs(boundleft) + boundright + DEFAULT_WIDTH)/2;//abs(boundleft);
614    // yaxis = abs(boundhigh);
615    /* FIXME: do we need xaxis and yaxis anymore? I don't think so */
616    xaxis = DEFAULT_WIDTH / 2;
617    yaxis = 0;
618   
619    // Preload background
620    // background->preload( startx, starty );
621   
622    // zoffsetlink
623    /*
624    if (zoffsetlink != DEFAULT_BACKGROUND_ID){
625        // Link zoffset to id
626        vector<Mugen::BackgroundElement *> elements = background->getIDList(zoffsetlink);
627        if (elements.size() != 0){
628            Mugen::BackgroundElement * element = elements[0];
629            zoffset = element->getCurrentY();
630        }
631    }
632    */
633
634    int r, g, b;
635    Graphics::Bitmap::cymkToRGB(shadow.c, shadow.y, shadow.m, shadow.k, &r, &g, &b);
636    Global::debug(1) << "Shadow c/y/m/k " << shadow.c << " " << shadow.y << " " << shadow.m << " " << shadow.k << " r/g/b " << r << " " << g << " " << b << endl;
637    shadowColor = Graphics::makeColor(r, g, b);
638
639    /* shadowIntensity is used as the alpha value. its some combination of the
640     * cymk components but I'm not sure what it is. This is relatively close
641     * but its definately not 100% accurate.
642     */
643    shadowIntensity = PaintownUtil::min((shadow.c + shadow.y + shadow.m + shadow.k * 2) / 3, 255);
644    Global::debug(1) << "Shadow intensity " << shadowIntensity << endl;
645
646    // Mugen::Util::readSprites(Mugen::Data::getInstance().getFileFromMotif(Filesystem::RelativePath("fightfx.sff")), Filesystem::AbsolutePath(), effects);
647    Mugen::Util::readSprites(getMotifFile("fightfx.sff"), Filesystem::AbsolutePath(), effects, true);
648    destroyRaw(effects);
649    // sparks = Mugen::Util::loadAnimations(Mugen::Data::getInstance().getFileFromMotif(Filesystem::RelativePath("fightfx.air")), effects);
650    sparks = Mugen::Util::loadAnimations(getMotifFile("fightfx.air"), effects, true);
651
652    // Mugen::Util::readSounds(Mugen::Data::getInstance().getFileFromMotif(Filesystem::RelativePath("common.snd")), sounds);
653    Mugen::Util::readSounds(getMotifFile("common.snd"), sounds);
654
655    /*
656    for (Mugen::SpriteMap::iterator it = effects.begin(); it != effects.end(); it++){
657        Global::debug(-1) << "Effect group " << (*it).first << endl;
658    }
659
660    spark = new MugenAnimation();
661    for (Mugen::GroupMap::iterator it = effects[0].begin(); it != effects[0].end(); it++){
662        MugenFrame * frame = new MugenFrame();
663        frame->sprite = (*it).second;
664        frame->xoffset = 0;
665        frame->yoffset = 0;
666        frame->time = 2;
667        frame->effects.trans = Mugen::ADD;
668        spark->addFrame(frame);
669    }
670    */
671   
672    /*
673    // Console stuff
674    console->setTextHeight(10);
675    console->setTextWidth(10);
676    */
677   
678    // *FIXME Use current motif instead of direct file access
679    try{
680        gameHUD = new Mugen::GameInfo(Mugen::Data::getInstance().getFileFromMotif(Filesystem::RelativePath("fight.def")));
681    } catch (const MugenException &e){
682        Global::debug(0) << "Problem loading HUD. Reason: " << e.getReason() << endl;
683        /* FIXME: throw an exception here?? */
684    }
685
686    // Stage is loaded
687    loaded = true;
688}
689
690void Mugen::Stage::destroyRaw(const map< unsigned int, std::map< unsigned int, MugenSprite * > > & sprites){
691    for (map< unsigned int, std::map< unsigned int, MugenSprite * > >::const_iterator i = sprites.begin() ; i != sprites.end() ; ++i ){
692        for(map< unsigned int, MugenSprite * >::const_iterator j = i->second.begin() ; j != i->second.end() ; ++j ){
693            MugenSprite * sprite = j->second;
694            sprite->unloadRaw();
695        }
696    }
697}
698
699void Mugen::Stage::setCamera( const double x, const double y ){ 
700    camerax = x;
701    cameray = y; 
702    // Camera boundaries
703    if( camerax < boundleft ) camerax = boundleft;
704    else if( camerax > boundright )camerax = boundright;
705    if( cameray < boundhigh ) cameray = boundhigh;
706    else if( cameray > boundlow )cameray = boundlow;
707}
708void Mugen::Stage::moveCamera( const double x, const double y ){ 
709    camerax += x; cameray += y; 
710    // Camera boundaries
711    if( camerax < boundleft ) camerax = boundleft;
712    else if( camerax > boundright )camerax = boundright;
713    if( cameray < boundhigh ) cameray = boundhigh;
714    else if( cameray > boundlow )cameray = boundlow;
715}
716
717static bool anyCollisions(const vector<MugenArea> & boxes1, int x1, int y1, const vector<MugenArea> & boxes2, int x2, int y2){
718
719    for (vector<MugenArea>::const_iterator attack_i = boxes1.begin(); attack_i != boxes1.end(); attack_i++){
720        for (vector<MugenArea>::const_iterator defense_i = boxes2.begin(); defense_i != boxes2.end(); defense_i++){
721            const MugenArea & attack = *attack_i;
722            const MugenArea & defense = *defense_i;
723            if (attack.collision(x1, y1, defense, x2, y2)){
724                return true;
725            }
726        }
727    }
728
729    return false;
730
731}
732
733static bool anyBlocking(const vector<MugenArea> & boxes1, int x1, int y1, int attackDist, const vector<MugenArea> & boxes2, int x2, int y2){
734    for (vector<MugenArea>::const_iterator attack_i = boxes1.begin(); attack_i != boxes1.end(); attack_i++){
735        for (vector<MugenArea>::const_iterator defense_i = boxes2.begin(); defense_i != boxes2.end(); defense_i++){
736            const MugenArea & attack = *attack_i;
737            MugenArea defense = *defense_i;
738            defense.x1 -= attackDist;
739            defense.x2 += attackDist;
740            if (attack.collision(x1, y1, defense, x2, y2)){
741                return true;
742            }
743        }
744    }
745
746    return false;
747}
748
749bool Mugen::Stage::doBlockingDetection(Mugen::Object * obj1, Mugen::Object * obj2){
750    return anyBlocking(obj1->getAttackBoxes(), (int) obj1->getX(), (int) obj1->getY(), obj1->getAttackDistance(), obj2->getDefenseBoxes(), (int) obj2->getX(), (int) obj2->getY());
751}
752
753bool Mugen::Stage::doCollisionDetection(Mugen::Object * obj1, Mugen::Object * obj2){
754    return anyCollisions(obj1->getAttackBoxes(), (int) obj1->getX(), (int) obj1->getY(), obj2->getDefenseBoxes(), (int) obj2->getX(), (int) obj2->getY());
755}
756
757PaintownUtil::ReferenceCount<MugenAnimation> Mugen::Stage::getFightAnimation(int id){
758    if (sparks[id] == 0){
759        ostringstream out;
760        out << "No fightfx animation for " << id;
761        throw MugenException(out.str());
762    }
763
764    return sparks[id];
765}
766
767void Mugen::Stage::addSpark(int x, int y, int sparkNumber){
768    if (sparks[sparkNumber] == 0){
769        /*
770        ostringstream out;
771        out << "No spark animation for " << sparkNumber;
772        throw MugenException(out.str());
773        */
774        Global::debug(0) << "No spark animation for " << sparkNumber << endl;
775        return;
776    }
777    Mugen::Spark * spark = new Mugen::Spark(x, y, PaintownUtil::ReferenceCount<MugenAnimation>(sparks[sparkNumber]));
778    showSparks.push_back(spark);
779}
780
781void Mugen::Stage::addSpark(int x, int y, const PaintownUtil::ReferenceCount<MugenAnimation> & animation){
782    if (animation != NULL){
783        Mugen::Spark * spark = new Mugen::Spark(x, y, animation);
784        showSparks.push_back(spark);
785    }
786}
787
788void Mugen::Stage::playSound(int group, int item, bool own){
789    /* FIXME: handle own */
790    MugenSound * sound = sounds[group][item];
791    if (sound != 0){
792        sound->play();
793    }
794}
795
796/* for helpers and players */
797void Mugen::Stage::physics(Object * mugen){
798    /* ignore physics while the player is paused */
799    if (mugen->isPaused()){
800        return;
801    }
802
803    mugen->doMovement(objects, *this);
804
805    if (mugen->getCurrentPhysics() == Mugen::Physics::Stand ||
806        mugen->getCurrentPhysics() == Mugen::Physics::Crouch){
807        /* friction */
808        if (mugen->getY() == 0){
809            mugen->setXVelocity(mugen->getXVelocity() * mugen->getGroundFriction());
810            if (mugen->getMoveType() == Mugen::Move::Hit && 
811                mugen->getXVelocity() < 0 &&
812                ticker % 5 == 0){
813                /* 120 is small dust */
814                addSpark((int)mugen->getX(), (int)(mugen->getRY()), 120);
815            }
816        }
817    }
818
819    if (mugen->getMoveType() == Mugen::Move::Attack && mugen->getHit().isEnabled()){
820
821        for (vector<Mugen::Object*>::iterator enem = objects.begin(); enem != objects.end(); ++enem){
822            Mugen::Character * enemy = (Mugen::Character*) *enem;
823            if (enemy->getAlliance() != mugen->getAlliance() && enemy->canBeHit(mugen)){
824                // Check attack distance to make sure we begin block at the correct distance
825                /*
826                if (doBlockingDetection(mugen, enemy) && enemy->isBlocking(*mugen->getHit())){
827                    enemy->guarded(mugen);
828                }
829                */
830
831                bool collision = doCollisionDetection(mugen, enemy);
832                /* blocking collision extends a little further than a a normal collision */
833                bool blockingCollision = doBlockingDetection(mugen, enemy);
834
835                /* guarding */
836                if ((collision || blockingCollision) && enemy->isBlocking(mugen->getHit())){
837                    if (collision){
838                        /* add guard spark and play guard sound */
839                        int spark = mugen->getHit().guardSpark;
840                        if (spark == -1){
841                            spark = mugen->getDefaultGuardSpark();
842                        }
843                        addSpark((int)(mugen->getHit().sparkPosition.x + enemy->getX()), (int)(mugen->getHit().sparkPosition.y + mugen->getRY()), spark);
844                        playSound(mugen->getHit().guardHitSound.group, mugen->getHit().guardHitSound.item, mugen->getHit().guardHitSound.own);
845                    }
846                    mugen->didHitGuarded(enemy, *this);
847                    enemy->guarded(mugen, mugen->getHit());
848                    /*
849                       vector<string> empty;
850                       enemy->changeState(*this, Mugen::StartGuardStand, empty);
851                       */
852                } else if (collision){
853                    /* do hitdef stuff */
854                    // Global::debug(0) << "Collision!" << endl;
855                    /* the hit state */
856                    int spark = mugen->getHit().spark;
857                    if (spark == -1){
858                        spark = mugen->getDefaultSpark();
859                    }
860                    addSpark((int)(mugen->getHit().sparkPosition.x + enemy->getX()), (int)(mugen->getHit().sparkPosition.y + mugen->getRY()), spark);
861                    playSound(mugen->getHit().hitSound.group, mugen->getHit().hitSound.item, mugen->getHit().hitSound.own);
862
863                    /* order matters here, the guy attacking needs to know that
864                     * he hit enemy so the guy can update his combo stuff.
865                     */
866                    mugen->didHit(enemy, *this);
867                    enemy->wasHit(*this, mugen, mugen->getHit());
868                    // enemy->changeState(5000);
869                }
870            }
871        }
872    }
873
874    // Check collisions
875    for (vector<Mugen::Object*>::iterator enem = objects.begin(); enem != objects.end(); ++enem){
876        Mugen::Object *enemy = *enem;
877        if (mugen->getAlliance() != enemy->getAlliance()){
878            // Do stuff for players
879            if (isaPlayer(enemy)){
880                // He collides with another push him away
881                // if ( player->collision( (ObjectAttack*)enemy ) && centerCollision( ((Mugen::Character *)player), ((Mugen::Character *)enemy) ) ){
882                Mugen::Object * mplayer = (Mugen::Object *) mugen;
883                Mugen::Object * menemy = (Mugen::Object *) enemy;
884                // if (anyCollisions(mplayer->getDefenseBoxes(), mplayer->getX(), mplayer->getY(), menemy->getDefenseBoxes(), menemy->getX(), menemy->getY()) && centerCollision( ((Mugen::Character *)player), ((Mugen::Character *)enemy) ) ){
885                /* TODO: make this cleaner */
886                while (anyCollisions(mplayer->getDefenseBoxes(), (int) mplayer->getX(), (int) mplayer->getY(), menemy->getDefenseBoxes(), (int) menemy->getX(), (int) menemy->getY()) && centerCollision(mplayer, menemy) && enemy->getY() == 0 && mplayer->getY() < enemy->getHeight() && menemy->getMoveType() == Mugen::Move::Idle){
887
888                    /* use move*Force to override pos freeze */
889
890                    if (enemy->getX() < mugen->getX()){
891                        if (enemy->getX() <= maximumLeft()){
892                            /* FIXME */
893                            mugen->moveRightForce(0.5);
894                        } else {
895                            /* FIXME! */
896                            enemy->moveLeftForce(0.5);
897                        }
898                        // enemy->moveLeft( ((Mugen::Character *)player)->getSpeed() );
899                    } else if (enemy->getX() > mugen->getX()){
900                        if (enemy->getX() >= maximumRight()){
901                            /* FIXME */
902                            mugen->moveLeftForce(0.5);
903                        } else {
904                            /* FIXME! */
905                            enemy->moveRightForce(0.5);
906                        }
907                        // enemy->moveRight( ((Mugen::Character *)player)->getSpeed() );
908                    } else if (enemy->getX() == mugen->getX()){
909                        if (enemy->getX() >= maximumRight()){
910                            mugen->moveLeftForce(0.5);
911                        } else {
912                            mugen->moveRightForce(0.5);
913                        }
914                    }
915                }
916                // autoturn need to do turning actions
917                if (autoturn){
918                    if (isaPlayer(mugen)){
919                        /* FIXME! */
920                        /*
921                           if (enemy->getX() > player->getX() && enemy->getFacing() != Object::FACING_LEFT && ((Mugen::Character *)enemy)->getStatus() == Status_Ground){
922                           enemy->setFacing(Object::FACING_LEFT);
923                           }
924
925                           if (enemy->getX() < player->getX() && enemy->getFacing() != Object::FACING_RIGHT && ((Mugen::Character *)enemy)->getStatus() == Status_Ground){
926                           enemy->setFacing(Object::FACING_RIGHT);
927                           }
928                           */
929                    }
930                }
931            }
932            }
933    }
934}
935
936vector<Mugen::Object*> Mugen::Stage::getOpponents(Mugen::Object * who){
937    vector<Mugen::Object*> out;
938    for (vector<Mugen::Object*>::iterator it = objects.begin(); it != objects.end(); ++it){
939        Mugen::Object * player = *it;
940        if (isaPlayer(player) && player->getAlliance() != who->getAlliance()){
941            out.push_back(player);
942        }
943    }
944
945    return out;
946}
947
948void Mugen::Stage::unbind(Mugen::Object * what){
949    for (vector<Mugen::Object*>::iterator it = objects.begin(); it != objects.end(); ++it){
950        Mugen::Object * guy = *it;
951        guy->unbind(what);
952    }
953}
954
955void Mugen::Stage::logic(){
956    // Console::ConsoleEnd & cend = Console::Console::endl;
957
958    /* cycles slow the stage down, like after ko */
959    cycles += 1;
960    if (cycles >= 1 / gameRate){
961        cycles = 0;
962
963        if (paletteEffects.time > 0){
964            paletteEffects.time = 0;
965            paletteEffects.counter += 1;
966        }
967
968        // camera crap
969        if (quake_time > 0){
970            quake_time--;
971        }
972
973        for (vector<Mugen::Effect*>::iterator it = showSparks.begin(); it != showSparks.end(); /**/){ 
974            Mugen::Effect * spark = *it;
975            spark->logic();
976
977            /* if the spark looped then kill it */
978            if (spark->isDead()){
979                delete spark;
980                it = showSparks.erase(it);
981            } else {
982                it++;
983            }
984        }
985
986        // implement some stuff before we actually begin the round then start the round
987        if (!stageStart){
988            stageStart = true;
989        }
990
991        // Run our ticker on and on like energizer bunnies (tm)
992        ticker++;
993
994        const double diffx = startx - camerax;
995        const double diffy = starty - cameray;
996
997        if (superPause.time > 0){
998            superPause.time -= 1;
999        } else {
1000            background->act();
1001
1002            // Players go in here
1003            std::vector<Mugen::Object *> add;
1004            addedObjects.clear();
1005            for (vector<Mugen::Object*>::iterator it = objects.begin(); it != objects.end(); /**/ ){
1006                bool next = true;
1007                /* use local variables more often, iterators can be easily confused */
1008                Mugen::Object * player = *it;
1009                player->act(&objects, this, &add);
1010                physics(player);
1011
1012                /* Debug crap put it on console */
1013                // *console << "Object: " << player << " x: " << player->getX() << " y: " << player->getY() << cend;
1014
1015                if (isaPlayer(player)){
1016                    // Lets check their boundaries and camera whateva
1017                    updatePlayer(player);
1018
1019                    // Update old position
1020                    playerInfo[player].oldx = player->getX();
1021                    playerInfo[player].oldy = player->getY();
1022
1023                    // Non players, objects, projectiles misc
1024                } else if (!isaPlayer(player) && player->getHealth() <= 0){
1025                    unbind(player);
1026                    delete player;
1027                    it = objects.erase(it);
1028                    next = false;
1029                }
1030
1031                if (next){
1032                    it++;
1033                }
1034            }
1035
1036            objects.insert(objects.end(), add.begin(), add.end());
1037            objects.insert(objects.end(), addedObjects.begin(), addedObjects.end());
1038        }
1039    }
1040   
1041    // Correct camera
1042    if ((verticalfollow > 0) && !inabove && (getCameraY() < 0)){
1043        moveCamera(0, verticalfollow * 3.2);
1044    }
1045   
1046    // Player HUD Need to make this more ellegant than casting and passing from array
1047    gameHUD->act(*this, *((Mugen::Character *)players[0]),*((Mugen::Character *)players[1]));
1048#if 0
1049    if (!gameOver){
1050        for (vector<Object*>::iterator it = objects.begin(); it != objects.end(); ++it){
1051            /* use local variables more often, iterators can be easily confused */
1052            Object * player = *it;
1053
1054            if (isaPlayer(player)){
1055                if (player->getHealth() <= 0){
1056                    gameOver = true;
1057                    vector<Object*> others = getOpponents(player);
1058                    for (vector<Object*>::iterator it2 = others.begin(); it2 != others.end(); it2++){
1059                        Mugen::Character * character = (Mugen::Character*) *it2;
1060                        vector<string> inputs;
1061                        character->changeState(*this, 180, inputs);
1062                    }
1063                }
1064            }
1065        }
1066    }
1067#endif
1068}
1069
1070class PaletteShader: public Graphics::Bitmap::Filter {
1071public:
1072    PaletteShader(int time, int addRed, int addGreen, int addBlue, int multiplyRed, int multiplyGreen, int multiplyBlue, int sinRed, int sinGreen, int sinBlue, int period, int invert, int color):
1073        time(time),
1074        addRed(addRed),
1075        addGreen(addGreen),
1076        addBlue(addBlue),
1077        multiplyRed(multiplyRed),
1078        multiplyGreen(multiplyGreen),
1079        multiplyBlue(multiplyBlue),
1080        sinRed(sinRed),
1081        sinGreen(sinGreen),
1082        sinBlue(sinBlue),
1083        period(period),
1084        invert(invert),
1085        color(color){
1086        }
1087
1088    int time;
1089    int addRed;
1090    int addGreen;
1091    int addBlue;
1092    int multiplyRed;
1093    int multiplyGreen;
1094    int multiplyBlue;
1095    int sinRed;
1096    int sinGreen;
1097    int sinBlue;
1098    int period;
1099    int invert;
1100    int color;
1101
1102    mutable map<Graphics::Color, Graphics::Color> cache;
1103
1104    Graphics::Color doFilter(int red, int green, int blue) const {
1105        int newRed = red;
1106        int newGreen = green;
1107        int newBlue = blue;
1108
1109        if (color < 255){
1110            double greyRed = (1 - 0.299) * color / 255 + 0.299;
1111            double greyGreen = (1 - 0.587) * color / 255 + 0.587;
1112            double greyBlue = (1 - 0.114) * color / 255 + 0.114;
1113            red = (int)(red * greyRed + 0.5 + 16);
1114            green = (int)(green * greyGreen + 0.5 + 16);
1115            blue = (int)(blue * greyBlue + 0.5 + 16);
1116        }
1117
1118        if (invert){
1119            red = 255 - red;
1120            green = 255 - green;
1121            blue = 255 - blue;
1122        }
1123
1124        if (period > 0){
1125            newRed = (red + addRed + sinRed * sin(2 * PaintownUtil::pi * time / period)) * multiplyRed / 256;
1126            newGreen = (green + addGreen + sinGreen * sin(2 * PaintownUtil::pi * time / period)) * multiplyGreen / 256;
1127            newBlue = (blue + addBlue + sinBlue * sin(2 * PaintownUtil::pi * time / period)) * multiplyBlue / 256;
1128        } else {
1129            newRed = (red + addRed) * multiplyRed / 256;
1130            newGreen = (green + addGreen) * multiplyGreen / 256;
1131            newBlue = (blue + addBlue) * multiplyBlue / 256;
1132        }
1133
1134        if (newRed > 255){
1135            newRed = 255;
1136        }
1137
1138        if (newRed < 0){
1139            newRed = 0;
1140        }
1141
1142        if (newGreen > 255){
1143            newGreen = 255;
1144        }
1145
1146        if (newGreen < 0){
1147            newGreen = 0;
1148        }
1149
1150        if (newBlue > 255){
1151            newBlue = 255;
1152        }
1153
1154        if (newBlue < 0){
1155            newBlue = 0;
1156        }
1157
1158        return Graphics::makeColor(newRed, newGreen, newBlue);
1159    }
1160
1161    Graphics::Color filter(Graphics::Color pixel) const {
1162
1163        if (cache.find(pixel) != cache.end()){
1164            return cache[pixel];
1165        }
1166
1167        int red = Graphics::getRed(pixel);
1168        int green = Graphics::getGreen(pixel);
1169        int blue = Graphics::getBlue(pixel);
1170        Graphics::Color out = doFilter(red, green, blue);
1171        cache[pixel] = out;
1172        return out;
1173    }
1174};
1175
1176void Mugen::Stage::drawBackgroundWithEffectsSide(int x, int y, const Graphics::Bitmap & board, void (Mugen::Background::*render) (int, int, const Graphics::Bitmap &, Graphics::Bitmap::Filter *)){
1177    PaletteShader effects(paletteEffects.counter, paletteEffects.addRed,
1178                    paletteEffects.addGreen, paletteEffects.addBlue,
1179                    paletteEffects.multiplyRed, paletteEffects.multiplyGreen,
1180                    paletteEffects.multiplyBlue, paletteEffects.sinRed,
1181                    paletteEffects.sinGreen, paletteEffects.sinBlue,
1182                    paletteEffects.period, paletteEffects.invert,
1183                    paletteEffects.color);
1184
1185    (background->*render)(x, y, board, &effects);
1186}
1187       
1188void Mugen::Stage::drawBackgroundWithEffects(int x, int y, const Graphics::Bitmap & board){
1189    drawBackgroundWithEffectsSide(x, y, board, &Background::renderBackground);
1190}
1191
1192void Mugen::Stage::drawForegroundWithEffects(int x, int y, const Graphics::Bitmap & board){
1193    drawBackgroundWithEffectsSide(x, y, board, &Background::renderForeground);
1194}
1195
1196void Mugen::Stage::render(Graphics::Bitmap *work){
1197
1198    // Background
1199    // background->renderBack( (xaxis + camerax) - DEFAULT_OBJECT_OFFSET, yaxis + cameray, (DEFAULT_WIDTH + (abs(boundleft) + boundright)), DEFAULT_HEIGHT + abs(boundhigh) + boundlow, board );
1200    // background->renderBackground(camerax, cameray, xaxis, yaxis, board);
1201    if (paletteEffects.time > 0){
1202        drawBackgroundWithEffects((int) camerax, (int) cameray, *work);
1203    } else {
1204        background->renderBackground((int) camerax, (int) cameray, *work);
1205    }
1206
1207    /* darken the background */
1208    if (superPause.time > 0){
1209        /* FIXME: this should be faded I think */
1210        Graphics::Bitmap::transBlender(0, 0, 0, 128);
1211        work->translucent().rectangleFill(0, 0, work->getWidth(), work->getHeight(), Graphics::makeColor(0, 0, 0));
1212    }
1213
1214    //! Render layer 0 HUD
1215    gameHUD->render(Mugen::Element::Background, *work);
1216
1217    // Players go in here
1218    for (vector<Mugen::Object*>::iterator it = objects.begin(); it != objects.end(); it++){
1219        Mugen::Object *obj = *it;
1220        /* Reflection */
1221        /* FIXME: reflection and shade need camerax/y */
1222        if (reflectionIntensity > 0){
1223            obj->drawReflection(work, (int)(camerax - DEFAULT_WIDTH / 2), (int) cameray, reflectionIntensity);
1224        }
1225
1226        /* Shadow */
1227        obj->drawMugenShade(work, (int)(camerax - DEFAULT_WIDTH / 2), shadowIntensity, shadowColor, shadowYscale, shadowFadeRangeMid, shadowFadeRangeHigh);
1228       
1229        /* draw the player */
1230        obj->draw(work, (int)(camerax - DEFAULT_WIDTH / 2), (int) cameray);
1231    }
1232
1233    for (vector<Mugen::Effect*>::iterator it = showSparks.begin(); it != showSparks.end(); it++){
1234        Mugen::Effect * spark = *it;
1235        spark->draw(*work, (int) (camerax - DEFAULT_WIDTH / 2), (int) cameray);
1236    }
1237
1238    //! Render layer 1 HUD
1239    gameHUD->render(Mugen::Element::Foreground, *work);
1240
1241    // Foreground
1242    // background->renderForeground( (xaxis + camerax) - DEFAULT_OBJECT_OFFSET, yaxis + cameray, (DEFAULT_WIDTH + (abs(boundleft) + boundright)), DEFAULT_HEIGHT + abs(boundhigh) + boundlow, board );
1243    if (paletteEffects.time > 0){
1244        drawForegroundWithEffects((int) camerax, (int) cameray, *work);
1245    } else {
1246        background->renderForeground((int) camerax, (int) cameray, *work);
1247    }
1248   
1249    //! Render layer 2 HUD
1250    gameHUD->render(Mugen::Element::Top, *work);
1251
1252    // Player debug
1253    for (vector<Mugen::Object*>::iterator it = objects.begin(); it != objects.end(); it++){
1254        if (isaPlayer(*it)){
1255            Mugen::Character *character = (Mugen::Character*)*it;
1256            // Player debug crap
1257            if (debugMode){
1258                // Players x positioning
1259                work->vLine( 150, (int)character->getX(), (int)character->getZ(), Graphics::makeColor( 255, 0, 0));
1260            }
1261        }
1262    }
1263   
1264    // Debug crap for board coordinates
1265    if (debugMode){
1266        work->hLine( 0, abs(boundhigh) + currentZOffset(), work->getWidth(), Graphics::makeColor( 0,255,0 ));
1267        work->vLine( 0, xaxis, work->getHeight(), Graphics::makeColor(255,0,0));
1268    }
1269   
1270    // board->Blit( (int)(abs(boundleft) + camerax) + ( quake_time > 0 ? Util::rnd( 9 ) - 4 : 0 ), (int)(yaxis + cameray) + ( quake_time > 0 ? Util::rnd( 9 ) - 4 : 0 ), DEFAULT_WIDTH, DEFAULT_HEIGHT, 0,0, *work);
1271
1272    /* FIXME: add quake back in */
1273    // board->Blit((int)(quake_time > 0 ? PaintownUtil::rnd( 9 ) - 4 : 0), (int)(quake_time > 0 ? PaintownUtil::rnd( 9 ) - 4 : 0), *work);
1274   
1275    // Debug crap for screen coordinates
1276    if (debugMode){
1277        work->vLine( 0, tension, 240, Graphics::makeColor( 0,255,0 ));
1278        work->vLine( 0, 320 - tension, 240, Graphics::makeColor( 0,255,0 ));
1279    }
1280   
1281    // Life bars, will eventually be changed out with mugens interface
1282    for (vector<Mugen::Object*>::iterator it = objects.begin(); it != objects.end(); it++){
1283        int p1Side = 5;
1284        int p2Side = 5;
1285        if (isaPlayer(*it)){
1286            Mugen::Character *character = (Mugen::Character*)*it;
1287            if ( character->getAlliance() == Player1Side ){
1288                /* FIXME! */
1289                // character->drawLifeBar( 5, p1Side, work );
1290                p1Side += 10;
1291            } else if ( character->getAlliance() == Player2Side ){
1292                /* FIXME! */
1293                // character->drawLifeBar( 215, p2Side, work );
1294                p2Side += 10;
1295            }
1296        }
1297    }
1298   
1299    // Render console
1300    // console->draw(*work);
1301}
1302
1303void Mugen::Stage::reset(){
1304    camerax = startx;
1305    cameray = starty;
1306    gameOver = false;
1307    /*for( std::vector< MugenBackground * >::iterator i = backgrounds.begin(); i != backgrounds.end(); ++i ){
1308        // reset just reloads it to default
1309        MugenBackground *background = *i;
1310        if (resetBG){
1311            background->preload( startx, starty );
1312        }
1313    }
1314    for( std::vector< MugenBackground * >::iterator i = foregrounds.begin(); i != foregrounds.end(); ++i ){
1315        // reset
1316        MugenBackground *background = *i;
1317        if (resetBG){
1318            background->preload( startx, starty );
1319        }
1320    }*/
1321
1322    /* FIXME: implement this again */
1323    // background->reset(startx, starty, resetBG);
1324   
1325    // Reset player positions
1326    for (vector<Mugen::Object*>::iterator it = objects.begin(); it != objects.end();){
1327        Mugen::Object *player = *it;
1328
1329        /* remove any non-player objects, like projectiles or helpers */
1330        if (!isaPlayer(player)){
1331            unbind(player);
1332            delete player;
1333            it = objects.erase(it);
1334        } else {
1335            Mugen::Character * character = (Mugen::Character*) player;
1336            vector<string> inputs;
1337            //character->changeState(*this, Mugen::Intro, inputs);
1338            character->setHealth(character->getMaxHealth());
1339            if (player->getAlliance() == Player1Side){
1340                //((Player *)player)->deathReset();
1341                player->setX(p1startx);
1342                player->setY(p1starty);
1343                player->setZ(currentZOffset());
1344                player->setFacing(FacingRight);
1345                playerInfo[player].oldx = player->getX();
1346                playerInfo[player].oldy = player->getY();
1347                playerInfo[player].leftTension = false;
1348                playerInfo[player].rightTension = false;
1349                playerInfo[player].leftSide = false;
1350                playerInfo[player].rightSide = false;
1351                playerInfo[player].jumped = false;
1352            } else if (player->getAlliance() == Player2Side){
1353                //((Player *)player)->deathReset();
1354                player->setX(p2startx);
1355                player->setY(p2starty);
1356                player->setZ(currentZOffset());
1357                player->setFacing(FacingLeft);
1358                playerInfo[player].oldx = player->getX();
1359                playerInfo[player].oldy = player->getY();
1360                playerInfo[player].leftTension = false;
1361                playerInfo[player].rightTension = false;
1362                playerInfo[player].leftSide = false;
1363                playerInfo[player].rightSide = false;
1364                playerInfo[player].jumped = false;
1365            }
1366            it++;
1367        }
1368    }
1369   
1370    inleft = inright = onLeftSide = onRightSide = 0;
1371    if (players.size() < 2){
1372        throw MugenException("Need at least 2 players");
1373    }
1374
1375    if (gameHUD == NULL){
1376        throw MugenException("Internal error: Stage not loaded, call load()");
1377    }
1378
1379    gameHUD->reset(*this, *((Mugen::Character *)players[0]),*((Mugen::Character *)players[1]));
1380}
1381
1382std::vector<Mugen::Object *> Mugen::Stage::getPlayers() const {
1383    return players;
1384}
1385
1386// Add player1 people
1387void Mugen::Stage::addPlayer1( Mugen::Object * o ){
1388    o->setAlliance(Player1Side);
1389    o->setX(p1startx);
1390    o->setY(p1starty);
1391    o->setZ(currentZOffset());
1392    o->setFacing(FacingRight);
1393    objects.push_back(o);
1394    players.push_back(o);
1395
1396    playerInfo[o].oldx = o->getX();
1397    playerInfo[o].oldy = o->getY();
1398    playerInfo[o].leftTension = false;
1399    playerInfo[o].rightTension = false;
1400    playerInfo[o].leftSide = false;
1401    playerInfo[o].rightSide = false;
1402    playerInfo[o].jumped = false;
1403
1404    ((Mugen::Character *) o)->setCommonSounds(&sounds);
1405}
1406
1407// Add player2 people
1408void Mugen::Stage::addPlayer2(Mugen::Object * o ){
1409    o->setAlliance(Player2Side);
1410    o->setX(p2startx);
1411    o->setY(p2starty);
1412    o->setZ(currentZOffset());
1413    o->setFacing(FacingLeft);
1414    objects.push_back(o);
1415    players.push_back(o);
1416   
1417    playerInfo[o].oldx = o->getX();
1418    playerInfo[o].oldy = o->getY();
1419    playerInfo[o].leftTension = false;
1420    playerInfo[o].rightTension = false;
1421    playerInfo[o].leftSide = false;
1422    playerInfo[o].rightSide = false;
1423    playerInfo[o].jumped = false;
1424
1425    ((Mugen::Character *) o)->setCommonSounds(&sounds);
1426}
1427
1428void Mugen::Stage::setPlayerHealth(int health){
1429    for ( vector<Mugen::Object * >::iterator it = players.begin(); it != players.end(); it++ ){
1430        Mugen::Character *player = (Mugen::Character *)(*it);
1431        player->setHealth(health);
1432    }
1433}
1434
1435/*
1436// Console
1437void Mugen::Stage::toggleConsole(){
1438    console->toggle();
1439}
1440*/
1441
1442void Mugen::Stage::toggleDebug(int choose){
1443    debugMode = !debugMode;
1444    int count = 0;
1445    for (vector<Mugen::Object *>::iterator it = players.begin(); it != players.end(); it++, count++){
1446        Mugen::Character *player = (Mugen::Character *)(*it);
1447        if (choose == count){
1448            player->enableDebug();
1449        } else {
1450            player->disableDebug();
1451        }
1452    }
1453}
1454
1455void Mugen::Stage::act(){
1456    logic();
1457}
1458
1459void Mugen::Stage::draw( Graphics::Bitmap * work ){
1460    render(work);
1461}
1462
1463void Mugen::Stage::addObject(Mugen::Object * o){
1464    addedObjects.push_back(o);
1465}
1466
1467bool Mugen::Stage::finished() const { return false; }
1468void Mugen::Stage::reloadLevel() throw( LoadException ){ 
1469    cleanup();
1470    loaded = false;
1471    load(); 
1472}
1473/* upper left hand corner of the screen */
1474int Mugen::Stage::getX(){
1475    return (int)getCameraX();
1476}
1477
1478int Mugen::Stage::getY(){
1479    return (int)getCameraY();
1480}
1481
1482/* bleh.. */
1483Mugen::Object * Mugen::Stage::findObject(int id){ 
1484    for (vector<Mugen::Object*>::iterator it = objects.begin(); it != objects.end(); it++){
1485        Mugen::Object * object = *it;
1486        if (object->getObjectId() == id){
1487            return object;
1488        }
1489    }
1490    return NULL;
1491}
1492
1493// These should be the same, but we'll see, mugen has some funny parameters
1494int Mugen::Stage::getMaximumZ(){ return zoffset; }
1495int Mugen::Stage::getMinimumZ(){ return zoffset; }
1496
1497void Mugen::Stage::begin(){
1498}
1499
1500const std::string Mugen::Stage::getStageName(const std::string &filename) throw (MugenException){
1501    // Lets look for our def since some people think that all file systems are case insensitive
1502    Filesystem::AbsolutePath dir = Storage::instance().find(Filesystem::RelativePath("mugen/stages/"));
1503    Global::debug(1) << dir.path() << endl;
1504    string fullname = filename;
1505    if ( fullname.find(".def") == std::string::npos){
1506        fullname += ".def";
1507    }
1508    const Filesystem::AbsolutePath defFile = Mugen::Util::fixFileName( dir, std::string(fullname) );
1509   
1510    if (defFile.isEmpty()){
1511        throw MugenException( "Cannot locate stage definition file for: " + fullname );
1512    }
1513   
1514    std::string filesdir = "";
1515   
1516    size_t strloc = fullname.find_last_of("/");
1517    if (strloc != std::string::npos){
1518        filesdir = fullname.substr(0, strloc);
1519        filesdir += "/";
1520    }
1521   
1522    Global::debug(1) << "Got subdir: " << filesdir << endl;
1523   
1524    AstRef parsed(Mugen::Util::parseDef(defFile.path()));
1525    return parsed->findSection("info")->findAttribute("name")->valueAsString();
1526       
1527    throw MugenException( "Cannot locate stage definition file for: " + fullname );
1528    return "";
1529}
1530
1531void Mugen::Stage::cleanup(){
1532    if (loaded){
1533        if (background){
1534            delete background;
1535            background = 0;
1536        }
1537       
1538        /*
1539        if (board){
1540            delete board;
1541            board = 0;
1542        }
1543        */
1544       
1545        /*
1546        if (console){
1547            delete console;
1548            console = 0;
1549        }
1550        */
1551
1552        for (Mugen::SpriteMap::iterator it1 = effects.begin(); it1 != effects.end(); it1++){
1553            for (Mugen::GroupMap::iterator it2 = (*it1).second.begin(); it2 != (*it1).second.end(); it2++){
1554                MugenSprite * sprite = (*it2).second;
1555                delete sprite;
1556            }
1557        }
1558        effects.clear();
1559
1560        sparks.clear();
1561
1562        for (vector<Mugen::Effect*>::iterator it = showSparks.begin(); it != showSparks.end(); it++){
1563            delete *it;
1564        }
1565        showSparks.clear();
1566
1567        for (map<unsigned int, map<unsigned int, MugenSound*> >::iterator it1 = sounds.begin(); it1 != sounds.end(); it1++){
1568            map<unsigned int, MugenSound*> & group = (*it1).second;
1569            for (map<unsigned int, MugenSound*>::iterator it2 = group.begin(); it2 != group.end(); it2++){
1570                delete (*it2).second;
1571            }
1572        }
1573        sounds.clear();
1574
1575        for (vector<Mugen::Projectile*>::iterator it = projectiles.begin(); it != projectiles.end(); it++){
1576            delete *it;
1577        }
1578        projectiles.clear();
1579
1580        for (vector<Mugen::Object*>::iterator it = objects.begin(); it != objects.end(); /**/){
1581            Mugen::Object * object = *it;
1582
1583            /* remove any non-player objects, like projectiles or helpers */
1584            if (!isaPlayer(object)){
1585                unbind(object);
1586                delete object;
1587                it = objects.erase(it);
1588            } else {
1589                it++;
1590            }
1591        }
1592    }
1593}
1594
1595bool Mugen::Stage::isaPlayer(Mugen::Object * o) const {
1596    for (vector<Mugen::Object *>::const_iterator it = players.begin(); it != players.end(); it++ ){
1597        if ( (*it) == o ){
1598            return true;
1599        }
1600    }
1601    return false;
1602}
1603
1604int Mugen::Stage::maximumRight() const {
1605    return (int)(camerax + DEFAULT_WIDTH / 2);
1606}
1607
1608int Mugen::Stage::maximumLeft() const {
1609    return (int)(camerax - DEFAULT_WIDTH / 2);
1610}
1611   
1612int Mugen::Stage::maximumUp() const {
1613    return cameray + DEFAULT_HEIGHT;
1614}
1615
1616int Mugen::Stage::maximumDown() const {
1617    return cameray;
1618}
1619   
1620void Mugen::Stage::addProjectile(Projectile * projectile){
1621    projectiles.push_back(projectile);
1622}
1623
1624void Mugen::Stage::updatePlayer(Mugen::Object * player){
1625    // Z/Y offset
1626    player->setZ(currentZOffset());
1627
1628    // Move X and Camera
1629    const double px = player->getX();
1630    const double py = player->getY();
1631    const double pdiffx = px - playerInfo[player].oldx;
1632    /*
1633       const double screenLeft = camerax - DEFAULT_WIDTH / 2;
1634       const double screenRight = camerax + DEFAULT_WIDTH / 2;
1635       */
1636    const double screenLeft = maximumLeft();
1637    const double screenRight = maximumRight();
1638
1639    /*
1640       const double screenLeft = abs(boundleft) + camerax;
1641       const double screenRight = abs(boundleft) + camerax + DEFAULT_WIDTH;
1642       */
1643    const double leftTension = screenLeft + tension;
1644    const double rightTension = screenRight - tension;
1645    // Check leftbound rightbound
1646    if (px < leftbound){
1647        player->setX(leftbound);
1648    } else if (px > rightbound){
1649        player->setX(rightbound);
1650    }
1651    /*
1652       if (px <= (abs(boundleft) + boundleft)){
1653       o->setX(abs(boundleft) + boundleft );
1654       playerInfo[o].oldx = px;
1655       } else if (px >= (DEFAULT_WIDTH + abs(boundleft) + boundright)){
1656       o->setX(DEFAULT_WIDTH + abs(boundleft) + boundright );
1657       playerInfo[o].oldx = px;
1658       }
1659       */
1660
1661    // Check if in tension
1662    if (px <= leftTension){
1663        if (!playerInfo[player].leftTension){
1664            playerInfo[player].leftTension = true;
1665            inleft++;
1666        }
1667    } else if (px >= rightTension){
1668        if (!playerInfo[player].rightTension){
1669            playerInfo[player].rightTension = true;
1670            inright++;
1671        }
1672    } 
1673
1674    // Release tension
1675    if (px > leftTension){
1676        if (playerInfo[player].leftTension){
1677            playerInfo[player].leftTension = false;
1678            inleft--;
1679        }
1680    }
1681    // Release tension
1682    if (px < rightTension){
1683        if (playerInfo[player].rightTension){
1684            playerInfo[player].rightTension = false;
1685            inright--;
1686        }
1687    }
1688
1689    // Check Screen sides
1690    if (px <= screenLeft){
1691        player->setX(screenLeft);
1692        playerInfo[player].oldx = px;
1693        if (!playerInfo[player].leftSide){
1694            playerInfo[player].leftSide = true;
1695            onLeftSide++;
1696        }
1697    } else if (px >= screenRight){
1698        player->setX(screenRight);
1699        playerInfo[player].oldx = px;
1700        if (!playerInfo[player].rightSide){
1701            playerInfo[player].rightSide = true;
1702            onRightSide++;
1703        }
1704    } 
1705    // Release side
1706    if (px > screenLeft){
1707        if (playerInfo[player].leftSide){
1708            playerInfo[player].leftSide = false;
1709            onLeftSide--;
1710        }
1711    }
1712    // Release side
1713    if (px < screenRight){
1714        if (playerInfo[player].rightSide){
1715            playerInfo[player].rightSide = false;
1716            onRightSide--;
1717        }
1718    }
1719
1720    //Global::debug(0) << "Left Tension: " << inleft << " | Right Tension: "<< inright << endl;
1721    //Global::debug(0) << "Left Screen Edge: " << onLeftSide << " | Right Screen Edge: "<< onRightSide << endl;
1722
1723    if (playerInfo[player].leftTension){
1724        if (pdiffx < 0){
1725            if (!onRightSide){
1726                moveCamera(pdiffx,0);
1727            }
1728        } else if (pdiffx > 0){
1729            if (inright){
1730                moveCamera(pdiffx,0);
1731            }
1732        }
1733    } else if (playerInfo[player].rightTension){
1734        if (pdiffx > 0){
1735            if(!onLeftSide){
1736                moveCamera(pdiffx,0);
1737            }
1738        } else if (pdiffx < 0){
1739            if(inleft){
1740                moveCamera(pdiffx,0);
1741            }
1742        }
1743    }
1744
1745    // Vertical movement of camera
1746    if (playerInfo[player].oldy != py){
1747        if (verticalfollow > 0){
1748            const double pdiffy = playerInfo[player].oldy - py;
1749            if (py > floortension){
1750                if (!playerInfo[player].above){
1751                    playerInfo[player].above = true;
1752                    inabove++;
1753                }
1754            } else if ( playerInfo[player].above){
1755                playerInfo[player].above = false;
1756                inabove--;
1757            }
1758            if (playerInfo[player].above && pdiffy < 0){
1759                moveCamera( 0, verticalfollow * -3.2 );
1760            } else if (playerInfo[player].above && pdiffy > 0){
1761                moveCamera( 0, verticalfollow * 3.2 );
1762            }
1763        }
1764    }
1765    //Global::debug(1) << "Our players Y: " << py << " | Above: "<< playerInfo[o].above << " | total inabove: " << inabove << endl;
1766}
1767
1768void Mugen::Stage::initializeName(){
1769    try{
1770#if 0
1771        Filesystem::AbsolutePath str = this->location;
1772        // Lets look for our def since some people think that all file systems are case insensitive
1773        baseDir = Filesystem::find(Filesystem::RelativePath("mugen/stages/"));
1774        Global::debug(1) << baseDir.path() << endl;
1775
1776        /* FIXME: this is ugly */
1777        if (str.path().find(".def") == std::string::npos){
1778            str = Filesystem::AbsolutePath(str.path() + ".def");
1779        }
1780
1781        // Get correct directory
1782        baseDir = baseDir.join(str).getDirectory();
1783        // str = str.getFilename();
1784        const Filesystem::AbsolutePath ourDefFile = Mugen::Util::getCorrectFileLocation(baseDir, Filesystem::RelativePath(str.getFilename()).path());
1785#endif
1786        // Set name of map
1787        name = Mugen::Util::probeDef(location, "info", "name");
1788    } catch (const MugenException &ex){
1789        Global::debug(1) << "Couldn't find the name of the map!" << endl;
1790        Global::debug(1) << "Error was: " << ex.getReason() << endl;
1791    }
1792}
1793       
1794void Mugen::Stage::setGameRate(double rate){
1795    gameRate = rate;
1796    if (rate <= 0){
1797        gameRate = 0.1;
1798    }
1799}
1800
1801//! Do continue screen return true to continue playing, false to end
1802bool Mugen::Stage::doContinue(const Mugen::PlayerType & type, InputMap<Mugen::Keys> & input){
1803    Filesystem::AbsolutePath systemFile = Mugen::Data::getInstance().getFileFromMotif(Mugen::Data::getInstance().getMotif());
1804   
1805    // Check if we have the continue screen enabled
1806    std::string enabled = Mugen::Util::probeDef(systemFile, "Continue Screen", "enabled");
1807    // If so we can render it otherwise it's not enabled, so no continue
1808    if (enabled != "1"){
1809        return false;
1810    }
1811
1812    // Lets look for our def since some people think that all file systems are case insensitive
1813    Filesystem::AbsolutePath baseDir = systemFile.getDirectory();
1814
1815    // Uses system font3 by default
1816    std::string fontFile = Mugen::Util::probeDef(systemFile, "Files", "font3");
1817
1818    MugenFont font(Mugen::Util::findFile(Filesystem::RelativePath(fontFile)));
1819   
1820    Mugen::Character * character = NULL;
1821
1822    switch (type){
1823        case Mugen::Player1:
1824            character = ((Mugen::Character *)players[0]);
1825            character->setFacing(FacingRight);
1826            break;
1827        case Mugen::Player2:
1828            character = ((Mugen::Character *)players[1]);
1829            character->setFacing(FacingLeft);
1830            break;
1831        default:
1832            break;
1833    }
1834   
1835
1836    double gameSpeed = 1.0;
1837    double runCounter = 0;
1838
1839    // Put character in continue state
1840    std::vector<std::string> empty;
1841    character->changeState(*this, Mugen::Continue, empty);
1842
1843    class Logic: public PaintownUtil::Logic {
1844    public:
1845        Logic(InputMap<Mugen::Keys> & input, Mugen::Character * character, Mugen::Stage * stage):
1846        is_done(false),
1847        answer(false),
1848        selector(true),
1849        input(input),
1850        character(character),
1851        stage(stage){
1852        }
1853
1854        bool is_done;
1855        bool answer;
1856        bool selector;
1857        InputMap<Mugen::Keys> & input;
1858        Mugen::Character * character;
1859        Mugen::Stage * stage;
1860
1861        bool getAnswer() const {
1862            return answer;
1863        }
1864
1865        bool done(){
1866            return is_done;
1867        }
1868
1869        bool selectedYes() const {
1870            return selector;
1871        }
1872
1873        void run(){
1874            vector<InputMap<Mugen::Keys>::InputEvent> out = InputManager::getEvents(input, InputSource());
1875            for (vector<InputMap<Mugen::Keys>::InputEvent>::iterator it = out.begin(); it != out.end(); it++){
1876                const InputMap<Mugen::Keys>::InputEvent & event = *it;
1877                if (!event.enabled){
1878                    continue;
1879                }
1880
1881                if (event[Mugen::Left] || event[Mugen::Right]){
1882                    selector = !selector;
1883                }
1884
1885                if (event[Mugen::A] || event[Mugen::B] || event[Mugen::C] ||
1886                    event[Mugen::X] || event[Mugen::Y] || event[Mugen::Z]){
1887                    if (selector){
1888                        is_done = true;
1889                        answer = true;
1890                    } else {
1891                        is_done = true;
1892                        answer = false;
1893                    }
1894                }
1895                // If enter return true
1896                if (event[Mugen::Esc]){
1897                    is_done = true;
1898                    answer = false;
1899                }
1900            }
1901            std::vector<Mugen::Object *> add;
1902            character->act(&add, stage, &add);
1903        }
1904
1905        double ticks(double system){
1906            return Util::gameTicks(system);
1907        }
1908    };
1909
1910    class Draw: public PaintownUtil::Draw {
1911    public:
1912        Draw(Mugen::Background * background, int reflectionIntensity, Mugen::Character * character, double cameray, int shadowIntensity, Graphics::Color shadowColor, double shadowYscale, int shadowFadeRangeHigh, int shadowFadeRangeMid, MugenFont & font, const Logic & logic):
1913        background(background),
1914        reflectionIntensity(reflectionIntensity),
1915        character(character),
1916        cameray(cameray),
1917        shadowIntensity(shadowIntensity),
1918        shadowColor(shadowColor),
1919        shadowYscale(shadowYscale),
1920        shadowFadeRangeHigh(shadowFadeRangeHigh),
1921        shadowFadeRangeMid(shadowFadeRangeMid),
1922        font(font),
1923        logic(logic){
1924        }
1925
1926        Mugen::Background * background;
1927        int reflectionIntensity;
1928        Mugen::Character * character;
1929        double cameray;
1930
1931        int shadowIntensity;
1932        Graphics::Color shadowColor;
1933        double shadowYscale;
1934        int shadowFadeRangeHigh;
1935        int shadowFadeRangeMid;
1936   
1937        MugenFont & font;
1938        const Logic & logic;
1939
1940        void draw(const Graphics::Bitmap & screen){
1941            Graphics::StretchedBitmap board(320, 240, screen);
1942            board.start();
1943            // Render background
1944            background->renderBackground(0, 0, board);
1945       
1946            // do darkened background
1947            // Bitmap::drawingMode(Bitmap::MODE_TRANS);
1948            Graphics::Bitmap::transBlender(0,0,0,150);
1949            board.translucent().rectangleFill(0, 0, board.getWidth(), board.getHeight(), Graphics::makeColor(0,0,0));
1950            // Bitmap::drawingMode(Bitmap::MODE_SOLID);
1951           
1952            // Render character
1953            if (reflectionIntensity > 0){
1954                character->drawReflection(&board, -(DEFAULT_WIDTH / 2), (int) cameray, reflectionIntensity);
1955            }
1956
1957            /* Shadow */
1958            character->drawMugenShade(&board, -(DEFAULT_WIDTH / 2), shadowIntensity, shadowColor, shadowYscale, shadowFadeRangeMid, shadowFadeRangeHigh);
1959       
1960            character->draw(&board, -(DEFAULT_WIDTH / 2), (int) cameray); 
1961           
1962            // Render continue text
1963            font.render(DEFAULT_WIDTH/2, 40, 0, 0, board, "Continue?" );
1964
1965            // Render yes and no
1966            if (logic.selectedYes()){
1967                font.render(DEFAULT_WIDTH/2 - 20, 50, 0, 4, board, "Yes");
1968                font.render(DEFAULT_WIDTH/2 + 20, 50, 0, 0, board, "No");
1969            } else {
1970                font.render(DEFAULT_WIDTH/2 - 20, 50, 0, 0, board, "Yes");
1971                font.render(DEFAULT_WIDTH/2 + 20, 50, 0, 4, board, "No");
1972            }
1973       
1974            // Foreground
1975            background->renderForeground(0, 0, board);
1976
1977            board.finish();
1978            // board->Stretch(buffer);
1979            screen.BlitToScreen();
1980        }
1981    };
1982
1983    Logic logic(input, character, this);
1984    Draw draw(background, reflectionIntensity, character, cameray, shadowIntensity, shadowColor, shadowYscale, shadowFadeRangeHigh, shadowFadeRangeMid, font, logic);
1985
1986    PaintownUtil::standardLoop(logic, draw);
1987
1988    return logic.getAnswer();
1989}
1990   
1991Mugen::Character * Mugen::Stage::getEnemy(const Mugen::Character * who) const {
1992    for (vector<Mugen::Object*>::const_iterator enem = objects.begin(); enem != objects.end(); ++enem){
1993        Mugen::Object * enemy = *enem;
1994        if (who->getAlliance() != enemy->getAlliance() && isaPlayer(enemy)){
1995            return (Mugen::Character*) enemy;
1996        }
1997    }
1998
1999    return NULL;
2000}
2001
2002int Mugen::Stage::getGameTime() const {
2003    if (gameHUD){
2004        return gameHUD->getGameTime();
2005    }
2006    return 0;
2007}
2008   
2009void Mugen::Stage::doSuperPause(int time, Character & guy, int animation, bool ownAnimation, int positionX, int positionY){
2010    superPause.time = time;
2011    if (animation != -1){
2012        if (ownAnimation){
2013            PaintownUtil::ReferenceCount<MugenAnimation> use = guy.getAnimation(animation);
2014            if (use != NULL){
2015                addSpark(positionX, positionY, use);
2016            }
2017        } else {
2018            addSpark(positionX, positionY, animation);
2019        }
2020    }
2021}
2022   
2023void Mugen::Stage::doPause(int time, int buffer, int moveAllowed, bool pauseBackground){
2024    /* TODO */
2025}
2026   
2027void Mugen::Stage::createDust(int x, int y){
2028    addSpark(x, y, 120);
2029}
2030       
2031void Mugen::Stage::addEffect(Mugen::Effect * effect){
2032    showSparks.push_back(effect);
2033}
2034                   
2035int Mugen::Stage::countMyEffects(const Mugen::Character * owner) const {
2036    int total = 0;
2037    for (vector<Mugen::Effect*>::const_iterator it = showSparks.begin(); it != showSparks.end(); it++){ 
2038        Mugen::Effect * effect = *it;
2039        if (effect->getOwner() == owner){
2040            total += 1;
2041        }
2042    }
2043    return total;
2044}
2045   
2046int Mugen::Stage::countMyHelpers(const Mugen::Character * owner) const {
2047    int count = 0;
2048    for (vector<Mugen::Object*>::const_iterator it = objects.begin(); it != objects.end(); it++){
2049        /* FIXME! dont assume its a character */
2050        Mugen::Character * who = (Mugen::Character*) *it;
2051        if (who->isHelper()){
2052            Mugen::Helper * helper = (Mugen::Helper*) who;
2053            if (helper->getParent() == owner){
2054                count += 1;
2055            }
2056        }
2057    }
2058    return count;
2059}
2060
2061vector<Mugen::Character *> Mugen::Stage::getTargets(int id, const Mugen::Character * from) const {
2062    vector<Mugen::Character *> targets;
2063    if (id == -1){
2064        /* TODO: match all enemies */
2065    } else {
2066        Mugen::Object * target = from->getTargetId(id);
2067        if (target != NULL){
2068            /* FIXME: dont assume its a character */
2069            targets.push_back((Mugen::Character*) target);
2070        }
2071    }
2072    return targets;
2073}
2074   
2075/* Set the background to a solid color for some length of time */
2076void Mugen::Stage::setEnvironmentColor(Graphics::Color color, int time, bool under){
2077    /* TODO */
2078}
2079   
2080void Mugen::Stage::removeHelper(Mugen::Character * who){
2081    /* The character will ultimately be removed in the logic loop */
2082    who->setHealth(-1);
2083    vector<Mugen::Helper*> children = findHelpers(who);
2084    for (vector<Mugen::Helper*>::iterator it = children.begin(); it != children.end(); it++){
2085        Mugen::Helper * helper = *it;
2086        /* lose parent association, still has root though */
2087        helper->reParent(NULL);
2088    }
2089}
2090   
2091void Mugen::Stage::removeEffects(const Mugen::Character * owner, int id){
2092    for (vector<Mugen::Effect*>::iterator it = showSparks.begin(); it != showSparks.end(); /**/ ){ 
2093        Mugen::Effect * effect = *it;
2094        if (effect->getOwner() == owner && (id == -1 || id == effect->getId())){
2095            delete effect;
2096            it = showSparks.erase(it);
2097        } else {
2098            it++;
2099        }
2100    }
2101}
2102
2103vector<Mugen::Helper*> Mugen::Stage::findHelpers(const Mugen::Character * owner, int id) const {
2104    vector<Mugen::Helper*> out;
2105    for (vector<Mugen::Object*>::const_iterator it = objects.begin(); it != objects.end(); it++){
2106        /* FIXME! dont assume its a character */
2107        Mugen::Character * who = (Mugen::Character*) *it;
2108        if (who->isHelper()){
2109            Mugen::Helper * helper = (Mugen::Helper*) who;
2110            if (helper->getHelperId() == id && helper->getParent() == owner){
2111                out.push_back(helper);
2112            }
2113        }
2114    }
2115    return out;
2116}
2117
2118vector<Mugen::Helper*> Mugen::Stage::findHelpers(const Mugen::Character * owner) const {
2119    vector<Mugen::Helper*> out;
2120    for (vector<Mugen::Object*>::const_iterator it = objects.begin(); it != objects.end(); it++){
2121        /* FIXME! dont assume its a character */
2122        Mugen::Character * who = (Mugen::Character*) *it;
2123        if (who->isHelper()){
2124            Mugen::Helper * helper = (Mugen::Helper*) who;
2125            if (helper->getParent() == owner){
2126                out.push_back(helper);
2127            }
2128        }
2129    }
2130    return out;
2131}
2132   
2133Mugen::Effect * Mugen::Stage::findEffect(const Mugen::Character * owner, int id){
2134    for (vector<Mugen::Effect*>::iterator it = showSparks.begin(); it != showSparks.end(); it++){ 
2135        Mugen::Effect * effect = *it;
2136        if (effect->getOwner() == owner && id == effect->getId()){
2137            return effect;
2138        }
2139    }
2140
2141    return NULL;
2142}
2143
2144vector<Mugen::Effect *> Mugen::Stage::findEffects(const Mugen::Character * owner, int id){
2145    vector<Mugen::Effect*> effects;
2146    for (vector<Mugen::Effect*>::iterator it = showSparks.begin(); it != showSparks.end(); it++){ 
2147        Mugen::Effect * effect = *it;
2148        if (effect->getOwner() == owner && (id == effect->getId() || id == -1)){
2149            effects.push_back(effect);
2150        }
2151    }
2152
2153    return effects;
2154}
2155
2156void Mugen::Stage::setPaletteEffects(int time, int addRed, int addGreen, int addBlue, int multiplyRed, int multiplyGreen, int multiplyBlue, int sinRed, int sinGreen, int sinBlue, int period, int invert, int color){
2157    paletteEffects.time = time;
2158    paletteEffects.addRed = addRed;
2159    paletteEffects.addGreen = addGreen;
2160    paletteEffects.addBlue = addBlue;
2161    paletteEffects.multiplyRed = multiplyRed;
2162    paletteEffects.multiplyGreen = multiplyGreen;
2163    paletteEffects.multiplyBlue = multiplyBlue;
2164    paletteEffects.sinRed = sinRed;
2165    paletteEffects.sinGreen = sinGreen;
2166    paletteEffects.sinBlue = sinBlue;
2167    paletteEffects.period = period;
2168    paletteEffects.invert = invert;
2169    paletteEffects.color = color;
2170    paletteEffects.counter = 0;
2171}
2172
2173void Mugen::Stage::Quake(int q){
2174    quake_time += q;
2175}
Note: See TracBrowser for help on using the browser.