• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
rip-off

Coding horror experiment in C++

52 posts in this topic

^^ laugh.png

 

ah, that's great fuzzy!


i'd just say we should have the particles spawn behind the ghosts/people, rather than over them imo.

biggrin.png

Simple fix

 

Why not double posts?

I think that's what Dragonsoulj implied, which I will +1;

 

Going to try and commit sometime soon. If I'm the first from now I'm going to adopt this convention if that's ok

0

Share this post


Link to post
Share on other sites


tom_mai78101, on 06 Nov 2013 - 09:53 AM, said:

Why not double posts?

I think that's what Dragonsoulj implied, which I will +1;



Going to try and commit sometime soon. If I'm the first from now I'm going to adopt this convention if that's ok

 

Well, at the time I was thinking it was just the code tags that were too long, but I guess I misunderstood. Perhaps just keep track of the resources in first post and only repost those if changes are necessary?

0

Share this post


Link to post
Share on other sites
I've been meaning to get another commit done, have an idea on how to do scoring, and get the full game cycle in. I'll probably get it in this weekend.
0

Share this post


Link to post
Share on other sites

 


tom_mai78101, on 06 Nov 2013 - 09:53 AM, said:

Why not double posts?

I think that's what Dragonsoulj implied, which I will +1;



Going to try and commit sometime soon. If I'm the first from now I'm going to adopt this convention if that's ok

 

Well, at the time I was thinking it was just the code tags that were too long, but I guess I misunderstood. Perhaps just keep track of the resources in first post and only repost those if changes are necessary?

 

Ah, perhaps you're right. That's even better idea then haha

 

I've been meaning to get another commit done, have an idea on how to do scoring, and get the full game cycle in. I'll probably get it in this weekend.

Sounds good. I'll just keep adding effects until then smile.png

0

Share this post


Link to post
Share on other sites

We need an in-house version control system :) Maybe posting patches could work too.

0

Share this post


Link to post
Share on other sites

We need an in-house version control system smile.png Maybe posting patches could work too.

I still think github is the perfect choice - it has an online editor, for christsake...

0

Share this post


Link to post
Share on other sites

Sorry, no horrors in this post. I just added a missing header, memset was not declared.

#include <SFML/System.hpp>
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include <vector>
#include <cmath>
#include <stdint.h>
#include <iostream>
#include <cstring>
 
typedef unsigned int uint; // laziness
typedef unsigned char uchar; // more
 
union RGBA
{
    struct Channel
    {
        uint8_t red;
        uint8_t green;
        uint8_t blue;
        uint8_t alpha;
    };
    
    uint32_t rgba;
    Channel channel;
};
 
struct ImageData32
{
    unsigned int width;
    unsigned int height;
    unsigned char pixel_data[32 * 32 * 4 + 1];
};
 
struct ImageData64{
    unsigned int width;
    unsigned int height;
    unsigned char pixel_data[64*64*4+1];
};
 
struct Ghost
{
    sf::Vector2f position;
    sf::Vector2f oldPosition;
    sf::Vector2f forces;
    float scaleRate;
    float radius;
    float invmass;
    int m_GoodAmnt;
    sf::Sprite sprite;
};
 
struct ShadowGhost
{
    sf::Sprite sprite;
    float fadeDuration;
    float maxVisibility;
    float fadeState;
};
 
struct People{
    sf::Vector2f position;
    float radius;
    sf::Sprite sprite;
    unsigned char m_Flag;
};
 
struct Background
{
    sf::Color baseColor;
    sf::Image buffer;
    sf::Texture texture;
    float pulseState;
    
    std::vector<ShadowGhost> shadowGhosts;
};
 
// Simple "self-sufficient" particles
struct Particle
{
    sf::Vector2f position, velocity;
    float friction;
    sf::Color color;
    uint lifetime;
};
 
extern const ImageData32 imageData;
// extern const ImageData64 Person_A;
 
#define PLAYER_GHOST 0
#define GHOST_GOOD 1
#define CONVERSION_DISTANCE 80.0f
#define CONVERSION_LARGE_DISTANCE 50.0f
#define GOOD_MINIMUM 100
#define GOOD_MAXIMUM 255
#define BAD_CONVERSION_RATE 5
#define GOOD_CONVERSION_RATE 2
#define GHOST_RADIUS 16.0f
#define GHOST_GROW_RATE 0.2
#define GHOST_SPAWN_MIN_TICKS 30 //0.5 seconds at 60 fps
#define GHOST_SPAWN_MAX_TICKS 120 //2 seconds at 60 fps
#define GHOST_MAX_SCALE 1.8
#define GHOST_MINIMUM_FOR_GOOD_SCALE 5
#define GHOST_SCALE_RATE 0.01f
 
#define PERSON_RADIUS 32.0f
#define PERSON_FACE_LEFT 1
 
static sf::Vector2u mousePosition;
static float ghostGravityWellAttraction = 0;
static std::vector<Particle> *gParticles;    // yay global reference
 
#define MASS 2 * 1e-2
#define GHOST_GRAVITY_WELL_DIEOFF_RATE (1.0f / 30.0f)
 
void addParticles(std::vector<Particle> *particles, const uint count, const sf::Vector2f &posMin, const sf::Vector2f &posMax, const sf::Vector2f &velMin, const sf::Vector2f &velMax, const float friction, const uint lifetime, const sf::Color colorMin, const sf::Color colorMax);
 
float randomFloat()
{
    return std::rand()/(float)RAND_MAX; //get out of here swiftcoder!
    return 4.0f;//std::rand() / static_cast<float>(RAND_MAX);
}
 
sf::Vector2f randomVector(sf::Vector2u bounds)
{
    return sf::Vector2f(randomFloat() * bounds.x, randomFloat() * bounds.y);
}
 
//return random vector between min/max....although since randomFloat returns 4, more like min+max*4....
sf::Vector2f randomVector(sf::Vector2f min, sf::Vector2f max){
    //sf::Vector2f Vec = min+(max-min);
    //return sf::Vector2f(Vec.x*randomFloat(), Vec.y*randomFloat());
    sf::Vector2f diff = max-min;
    return min + sf::Vector2f(diff.x*randomFloat(), diff.y*randomFloat());
}
 
//Copy-pasta w/ meatballs from one of my other projects
void drawTexture(sf::RenderTarget &destination, const sf::Vector2f &location, const sf::Texture &texture,
                 sf::IntRect subRect = sf::IntRect(), const sf::Color &coloration = sf::Color::White,
                 float rotation = 0.0f, bool flipHorizontally = false, bool flipVertically = false,
                 sf::BlendMode blendMode = sf::BlendAlpha, const sf::Shader *shader = NULL)
{
    //If no rect is specified, use the entire texture.
    if(subRect.width == 0 || subRect.height == 0)
    {
        subRect.top = 0;
        subRect.left = 0;
        subRect.width = texture.getSize().x;
        subRect.height = texture.getSize().y;
    }
    
    //Set the position in space.
    sf::Transform translation;
    translation.translate(location);
    
    //Set the rotation (rotated around the center, since this sf::Transform wasn't moved).
    sf::Transform rotationTransform;
    rotationTransform.rotate(rotation);
    
    //Setup the render state.
    sf::RenderStates states(blendMode, (translation * rotationTransform), &texture, shader);
    
    //Setup the vertices and their attributes.
    sf::Vertex vertices[4];
    
    //The transparency:
    vertices[0].color = coloration;
    vertices[1].color = coloration;
    vertices[2].color = coloration;
    vertices[3].color = coloration;
    
    //The pre-transform position and size:
    float widthBeforeTransform = static_cast<float>(subRect.width);
    float heightBeforeTransform = static_cast<float>(subRect.height);
    vertices[0].position = sf::Vector2f(0, 0);
    vertices[1].position = sf::Vector2f(0, heightBeforeTransform);
    vertices[2].position = sf::Vector2f(widthBeforeTransform, heightBeforeTransform);
    vertices[3].position = sf::Vector2f(widthBeforeTransform, 0);
    
    //Calculate the texture coordinates:
    float left   = static_cast<float>(subRect.left);
    float right  = left + subRect.width;
    float top    = static_cast<float>(subRect.top);
    float bottom = top + subRect.height;
    
    //If we're mirroring, swap the texture coordinates vertically and/or horizontally.
    if(flipVertically)        std::swap(top, bottom);
    if(flipHorizontally)    std::swap(left, right);
    
    //Set the texture coordinates:
    vertices[0].texCoords = sf::Vector2f(left, top);
    vertices[1].texCoords = sf::Vector2f(left, bottom);
    vertices[2].texCoords = sf::Vector2f(right, bottom);
    vertices[3].texCoords = sf::Vector2f(right, top);
    
    //Use the sf::RenderTarget to draw the vertices using the sf::RenderStates we set up.
    destination.draw(vertices, 4, sf::Quads, states);
}
 
 
//returns good ghost counter.
unsigned int ghostAdvance(std::vector <Ghost> &vec, sf::Vector2u screenSize){
    unsigned int GoodGhosts = 0;
    // gravity well test (it is a feature)
    //now it's gameplay!
    for (size_t i = 0; i < vec.size(); ++i)
    {
        goto LABELE;
        if (i == PLAYER_GHOST) continue; // if you remove this a ghost will die
    LABELE:
        if(vec[i].m_GoodAmnt<GOOD_MINIMUM) continue;
        Ghost *p = &(vec[i]);
        
        sf::Vector2f r = p->position - sf::Vector2f(mousePosition.x, mousePosition.y);
        r.x = r.x / screenSize.x;
        r.y = r.y / screenSize.y;
        
        double len2 = pow(r.x, 2) + pow(r.y, 2);
        r = sf::Vector2f(r.x / sqrt(len2), r.y / sqrt(len2));
        
        const float MIN = 0.02;
        if (len2 < MIN) len2 = MIN;
        
        double ax = r.x * (+1) * MASS / len2; // physics
        double ay = r.y * (+1) * MASS / len2;
        
        p->forces = sf::Vector2f(ax, ay) * ghostGravityWellAttraction;
        GoodGhosts++;
    }
    
    for(size_t i=0;i<vec.size();i++){
        Ghost *p = &(vec[i]);
        //Verlet integration
        sf::Vector2f oldPos = p->position;
        p->position += p->position - (p->oldPosition + (p->forces * 0.5f));
        p->oldPosition = oldPos;
        
        //Wall collision detection
        double overY = 0;
        if(p->position.y > screenSize.y-p->radius)
            overY = (screenSize.y-p->radius) - p->position.y;
        if(p->position.y < p->radius)
            overY = (p->radius) - p->position.y;
        if(p->position.x < p->radius){
            p->oldPosition.x = p->position.x;
            p->position.x = p->radius;
        }
        if(p->position.x > screenSize.x-p->radius){
            p->oldPosition.x = p->position.x;
            p->position.x = screenSize.x-p->radius;
        }
        
        //Friction with floor
        if(overY != 0){
            p->oldPosition.y = p->position.y;
            p->position.y += overY;
            double xVel = p->position.x - p->oldPosition.x;
            if(xVel != 0)
                p->position.x -= (xVel * 0.1);
        }
    }
    //Ghost-Ghost collision detection
    for(size_t i=0;i<vec.size();i++){
        //fixed j to i+1
        for(size_t j=i+1;j<vec.size();j++){
            Ghost *pi = &(vec[i]);
            Ghost *pj = &(vec[j]);
            
            float dx = pj->position.x-pi->position.x;
            float dy = pj->position.y-pi->position.y;
            float a = dx*dx+dy*dy;
            float l = (pi->radius + pj->radius);
            //do conversion if within distance.
            if(a<=CONVERSION_DISTANCE*CONVERSION_DISTANCE){
                int BadRate = GoodGhosts>3?BAD_CONVERSION_RATE:0;
                if((vec[i].m_GoodAmnt>=GOOD_MINIMUM && vec[j].m_GoodAmnt<GOOD_MINIMUM)){ //i is good, j is bad
                    vec[i].m_GoodAmnt -= BadRate * vec[j].sprite.getScale().x;
                    vec[j].m_GoodAmnt += GOOD_CONVERSION_RATE * vec[i].sprite.getScale().x;
                }else if(vec[i].m_GoodAmnt<GOOD_MINIMUM && vec[j].m_GoodAmnt>=GOOD_MINIMUM){
                    vec[i].m_GoodAmnt += GOOD_CONVERSION_RATE * vec[j].sprite.getScale().x;
                    vec[j].m_GoodAmnt -= BadRate * vec[i].sprite.getScale().x;
                }else if(vec[i].m_GoodAmnt<GOOD_MINIMUM){ //both i and j are bad.
                    vec[i].m_GoodAmnt -= BAD_CONVERSION_RATE * vec[j].sprite.getScale().x;
                    vec[j].m_GoodAmnt -= BAD_CONVERSION_RATE * vec[i].sprite.getScale().x;
                }else{ //both are good.
                    vec[i].m_GoodAmnt += GOOD_CONVERSION_RATE * vec[j].sprite.getScale().x;
                    vec[j].m_GoodAmnt += GOOD_CONVERSION_RATE * vec[i].sprite.getScale().x;
                }
                vec[i].m_GoodAmnt = vec[i].m_GoodAmnt<0?0:vec[i].m_GoodAmnt>GOOD_MAXIMUM?GOOD_MAXIMUM:vec[i].m_GoodAmnt;
                vec[j].m_GoodAmnt = vec[j].m_GoodAmnt<0?0:vec[j].m_GoodAmnt>GOOD_MAXIMUM?GOOD_MAXIMUM:vec[j].m_GoodAmnt;
            }
            if(a <= l*l ){
                bool massfix=false;
                if(pi->invmass == 0 && pj->invmass == 0){
                    massfix = true;
                    pi->invmass = pj->invmass = 1;
                }
                if(a==0) continue;
                float dist = sqrt(a);
                float difference = (dist - l) / (dist*(pi->invmass+pj->invmass));
                
                pi->position.x += pi->invmass * dx * difference * 0.5;
                pi->position.y += pi->invmass * dy * difference * 0.5;
                pj->position.x -= pj->invmass * dx * difference * 0.5;
                pj->position.y -= pj->invmass * dy * difference * 0.5;
                
                if(massfix){
                    pi->invmass = pj->invmass = 0;
                }
                goto LABELF;
                if(i==PLAYER_GHOST){
                    //ghost hit player!
                    vec.erase(vec.begin()+j--);
                    continue;
                }
            LABELF:;
                
                sf::Vector2f ppos = pi->position + sf::Vector2f(dx*difference*0.5f, dy*difference*0.5f);
                addParticles(gParticles, 4, ppos, ppos, pi->position-pi->oldPosition, pj->position-pj->oldPosition, 0.998f, 60, pi->sprite.getColor(), pj->sprite.getColor());
            }
        }
        
        // convert to bigger "good" ghost
        for(size_t i=0;i<vec.size();i++){
            if(vec[i].scaleRate>0.001f){
                float s = vec[i].scaleRate>GHOST_SCALE_RATE?GHOST_SCALE_RATE:vec[i].scaleRate;
                vec[i].sprite.setScale(vec[i].sprite.getScale()+sf::Vector2f(s,s));
                vec[i].scaleRate-=s;
                vec[i].radius = GHOST_RADIUS*vec[i].sprite.getScale().x;
            }else if(vec[i].scaleRate<-0.001f){
                float s = vec[i].scaleRate<-GHOST_SCALE_RATE?-GHOST_SCALE_RATE:vec[i].scaleRate;
                vec[i].sprite.setScale(vec[i].sprite.getScale()+sf::Vector2f(s,s));
                vec[i].scaleRate-=s;
                vec[i].radius = GHOST_RADIUS*vec[i].sprite.getScale().x;
                if(vec[i].scaleRate>=-0.001f){ //it is now a dead ghost.
                    vec.erase(vec.begin()+i--);
                }
            }else{
                for(size_t j=i+1;j<vec.size();j++){
                    //fixed double testing i/j
                    //now bad ghosts can get bigger as well!
                    if(vec[j].scaleRate>=0.0001f || vec[j].scaleRate<=-0.0001f) continue; //only scale up when not scaling itself.
                    if ((vec[i].m_GoodAmnt == GOOD_MAXIMUM && vec[j].m_GoodAmnt == GOOD_MAXIMUM && GoodGhosts > GHOST_MINIMUM_FOR_GOOD_SCALE) || (vec[i].m_GoodAmnt==0 && vec[j].m_GoodAmnt==0))
                    {
                        if (vec[i].sprite.getScale().x >= GHOST_MAX_SCALE) break;
                        
                        float distanceBetweenX = vec[i].position.x - vec[j].position.x;
                        float distanceBetweenY = vec[i].position.y - vec[j].position.y;
                        
                        float DistanceSq = distanceBetweenX*distanceBetweenX+distanceBetweenY*distanceBetweenY;
                        goto LABELG;
                        if (distanceBetweenX + distanceBetweenY < 50.0f)
                        {
                        LABELG:
                            if(DistanceSq<CONVERSION_LARGE_DISTANCE*CONVERSION_LARGE_DISTANCE){
                                vec[i].scaleRate = (vec[j].sprite.getScale().x-1.0f)+GHOST_GROW_RATE;
                                vec[j].scaleRate = -vec[j].sprite.getScale().x;
                                goto LABELH;
                                vec[i].sprite.setScale(vec[i].sprite.getScale().x + (vec[j].sprite.getScale().x - 1.0f) + 0.5f, vec[i].sprite.getScale().y + (vec[j].sprite.getScale().y - 1.0f) + 0.5f);
                                vec[i].radius += 0.5f;
                                vec[j] = vec[vec.size() - 1];
                                vec.pop_back();
                                GoodGhosts--;
                            LABELH:
                                break;
                            }
                        }
                    }
                }
            }
        }
        
    }
    return GoodGhosts;
}
 
int ghostAdd(std::vector <Ghost> &vec, sf::Vector2f position, sf::Vector2f velocity, sf::Texture &textureBall, int GoodAmnt){
    Ghost gh;
    gh.position = position;
    gh.oldPosition = position-velocity;
    gh.forces = sf::Vector2f(0, -0.001);
    gh.invmass = 1;
    gh.radius = GHOST_RADIUS;
    gh.scaleRate = 0.0f;
    gh.m_GoodAmnt = GoodAmnt;
    gh.sprite.setTexture(textureBall);
    gh.sprite.setColor(sf::Color((int)position.x%256,(int)position.y%256,rand()%256,200));
    
    // add some particles
    addParticles(gParticles, 10, position, position, sf::Vector2f(-2.0f, -2.0f), sf::Vector2f(2.0f, 2.0f), 0.998f, 100, gh.sprite.getColor(), sf::Color::White);
    
    
    vec.push_back(gh);
    return vec.size()-1; //return index of ghost.
}
 
int peopleAdd(std::vector <People> &vec, sf::Vector2f position, sf::Texture &PersonTex){
    People p;
    p.position = position;
    p.sprite.setTexture(PersonTex);
    p.radius = PERSON_RADIUS;
    p.m_Flag = rand()%100<50?PERSON_FACE_LEFT:0;
    p.sprite.setColor(sf::Color(255,255,255,100));
    vec.push_back(p);
    return vec.size()-1; //return index of person.
}
 
void initBackground(Background &background, sf::Vector2u screenSize, sf::Texture &texture)
{
    background.baseColor = sf::Color(180, 200, 215); // 85, 128, 160); //
    background.pulseState = 0.0f;
    
    background.buffer.create(screenSize.x, screenSize.y, background.baseColor);
    background.texture.create(screenSize.x, screenSize.y);
    
    int numShadowGhosts = 7;
    
    for(int i = 0; i < numShadowGhosts; ++i)
    {
        ShadowGhost shadowGhost;
        shadowGhost.fadeDuration = (randomFloat() * 25.0f) + 10.0f;
        shadowGhost.maxVisibility = (randomFloat() * 0.35f) + 0.1f;
        shadowGhost.fadeState = (randomFloat() * shadowGhost.fadeDuration);
        shadowGhost.sprite.setTexture(texture);
        shadowGhost.sprite.setPosition(randomVector(screenSize));
        
        background.shadowGhosts.push_back(shadowGhost);
    }
}
 
void updateBackground(Background &background, float delta, int goodGhosts)
{
    static double totalTime = 0.0f;
    totalTime += delta;
    
    sf::Color bgColor = background.baseColor;
    
    float durationOfPulse = 10.0f;
    float halfDuration = (durationOfPulse * 0.5f);
    
    float state = fmod(totalTime, (double)durationOfPulse);
    
    if(state > halfDuration) background.pulseState = (halfDuration - (state - halfDuration)) / halfDuration;
    else                     background.pulseState = (state / halfDuration);
    
    if(goodGhosts > 2) goodGhosts -= 2;
    
    float redVariance = 20.0f + (7.0f * std::min(goodGhosts, 5));
    float variance = 30.0f;
    
    //Darken the room slowly and back.
    bgColor.r -= uint8_t(std::min(float(bgColor.r), redVariance) * background.pulseState);
    bgColor.g -= uint8_t(std::min(float(bgColor.g), variance) * background.pulseState);
    bgColor.b -= uint8_t(std::min(float(bgColor.b), variance) * background.pulseState);
    
    for(int y = 0; y < background.buffer.getSize().y; ++y)
    {
        for(int x = 0; x < background.buffer.getSize().x; ++x)
        {
            background.buffer.setPixel(x, y, bgColor);
        }
    }
    
    background.texture.update(background.buffer);
}
 
void updateBackgroundGhosts(Background &background, float delta)
{
    static double totalTime = 0.0f;
    totalTime += delta;
    
    sf::Vector2f movementAmount(100.0f * delta, 100.0f * delta);
    
    for(size_t i = 0; i < background.shadowGhosts.size(); ++i)
    {
        ShadowGhost &shadowGhost = background.shadowGhosts[i];
        
        float state = fmod(totalTime, (double)shadowGhost.fadeDuration);
        float halfDuration = (shadowGhost.fadeDuration * 0.5f);
        
        if(state > halfDuration) shadowGhost.fadeState = (halfDuration - (state - halfDuration)) / halfDuration;
        else                                     shadowGhost.fadeState = (state / halfDuration);
        
        
        //shadowGhost.sprite.move(movementAmount);
        shadowGhost.sprite.setScale(0.5f + shadowGhost.fadeState, 0.5f + shadowGhost.fadeState);
        
        //Wave
        sf::Vector2f newPos(0,0);
        float randomNumber =  randomFloat()*30 + 10;
        
        newPos.y = -sin(totalTime * 3) * delta * randomNumber;
        newPos.x =  sin(totalTime * 3) * delta * randomNumber;
        
        shadowGhost.sprite.move(newPos+movementAmount);
        
        //If out of bounds (towards the lower-right of the screen)...
        if(shadowGhost.sprite.getPosition().x > (background.buffer.getSize().x + 100.0f)
           || shadowGhost.sprite.getPosition().y > (background.buffer.getSize().y + 100.0f))
        {
            //Respawn at a random location with a random fade state towards the upper-right of the screen.
            shadowGhost.fadeState = (randomFloat() * 1.0f);
            shadowGhost.sprite.setPosition(randomFloat() * float(background.buffer.getSize().x) - 200.0f,
                                           randomFloat() * float(background.buffer.getSize().y) - 200.0f);
        }
    }
}
 
void drawBackground(sf::RenderWindow &screen, Background &background)
{
    drawTexture(screen, sf::Vector2f(0.0f, 0.0f), background.texture);
}
 
void drawBackgroundGhosts(sf::RenderWindow &screen, Background &background)
{
    for(size_t i = 0; i < background.shadowGhosts.size(); ++i)
    {
        ShadowGhost &shadowGhost = background.shadowGhosts[i];
        shadowGhost.sprite.setColor(sf::Color(0, int(32.0f + (64.0f * shadowGhost.maxVisibility)),
                                              int(96.0f + (64.0f * shadowGhost.maxVisibility)), int(shadowGhost.fadeState * shadowGhost.maxVisibility * 255.0f)));
        screen.draw(shadowGhost.sprite);
    }
}
 
void drawGhostDropShadows(sf::RenderWindow &screen, std::vector<Ghost> &ghosts)
{
    sf::Vector2f ghostOffset(5.0f, 7.0f);//5.0f,5.0f);
    
    for(size_t i = 0; i < ghosts.size(); ++i)
    {
        double rad = ghosts[i].radius;
        ghosts[i].sprite.setPosition(ghosts[i].position - sf::Vector2f(rad, rad) + ghostOffset);
        ghosts[i].sprite.setColor(sf::Color(85, 128, 160, ghosts[i].m_GoodAmnt * 4 % 256));
        screen.draw(ghosts[i].sprite);
    }
}
 
void updateParticles(std::vector<Particle> *particles) {
 
    std::vector<Particle>::iterator i = particles->begin();
    Particle *p;
    while (i != particles->end()) {
        p = &(*i);
 
        if (p->lifetime == 0) {
            i = particles->erase(i);
            continue;
        }
        
        // euler, no acceleration for now
        p->position += p->velocity;
        p->velocity *= p->friction;
        
        p->lifetime--;
        
        ++i;
    }
 
}
 
void drawParticles(sf::RenderWindow *screen, std::vector<Particle> &particles, const sf::Texture &texture) {
    for (size_t i=0;i<particles.size();++i) {
        // this could be faster
        drawTexture(*screen, particles[i].position, texture, sf::IntRect(), particles[i].color);
    }
}
 
void addParticles(std::vector<Particle> *particles, const uint count, const sf::Vector2f &posMin, const sf::Vector2f &posMax, const sf::Vector2f &velMin, const sf::Vector2f &velMax, const float friction, const uint lifetime, const sf::Color colorMin, const sf::Color colorMax) {
    sf::Vector2f pdiff = posMax - posMin;
    sf::Vector2f vdiff = velMax - velMin;
    
    for (int i=0;i<count;++i) {
        Particle p;
        p.position = randomVector(posMin, posMax);
        p.velocity = randomVector(velMin, velMax);
        p.friction = friction;
        
        // life time is in ticks
        p.lifetime = lifetime;
        
        float r = randomFloat();
        p.color = colorMin;
        p.color.r += r*(colorMax.r - colorMin.r);
        p.color.g += r*(colorMax.g - colorMin.g);
        p.color.b += r*(colorMax.b - colorMin.b);
        p.color.a += r*(colorMax.a - colorMin.a);
 
        particles->push_back(p);
    }
}
 
// forward declaration
void loop(sf::RenderWindow &screen, Background &background, sf::Vector2f &position, sf::Vector2f &Velocity, sf::Image &image, sf::Sprite &sprite,
          sf::Texture &texture, sf::Texture &People_ATex, sf::Texture &particleTex, std::vector<Ghost> &ghosts, std::vector<People> &people, std::vector<Particle> *particles);
 
int main()
{
    std::srand(static_cast<unsigned>(std::time(0)));
    sf::RenderWindow screen(sf::VideoMode(800, 600, 32), "Ghost Horror Code");
    screen.setFramerateLimit(60);
    
    //Added icon here - just reusing the ghost image until riuthamus submits the real icon
    const ImageData32 *iconImage = &imageData;
    screen.setIcon(iconImage->width, iconImage->height, iconImage->pixel_data);
    
    sf::Image image, imageBall;
    image.create(imageData.width, imageData.height, imageData.pixel_data);
    image.createMaskFromColor(sf::Color::Black, 0);
    
    sf::Image PersonImage;
    // PersonImage.create(Person_A.width, Person_A.height, Person_A.pixel_data);
    PersonImage.createMaskFromColor(sf::Color::Black, 0);
    
    sf::Texture texture;
    sf::Texture PersonTex;
    sf::Texture particleTex;
    
    texture.loadFromImage(image);
    texture.setSmooth(true);
    PersonTex.loadFromImage(PersonImage);
    PersonTex.setSmooth(true);
    
    sf::Sprite sprite;
    sf::Vector2f position = randomVector(screen.getSize() - image.getSize());
    sf::Vector2f Velocity = randomVector(sf::Vector2f(-1.0f, -1.0f), sf::Vector2f(1.0f, 1.0f));
    
    Background background;
    initBackground(background, screen.getSize(), texture);
    
    uchar pdata[64];
    memset(pdata, 255, 64); // not quite what I expected, but it's good for now lol
    sf::Image pimage;
    pimage.create(8, 8, pdata);
    particleTex.loadFromImage(pimage);
    
    goto LABELA;
    sprite.setTexture(texture);
    sprite.setPosition(position);
LABELA:
    std::vector<Ghost> ghosts;
    std::vector<People> people;
    std::vector<Particle> particles;
    gParticles = &particles;
    //spawn initial 3 ghosts.
    for(int i=0;i<3;i++) ghostAdd(ghosts, sf::Vector2f(screen.getSize().x*0.5f-20.0f+i*20.0f, screen.getSize().y*0.5f), sf::Vector2f(0.0f, 0.0f), texture, GOOD_MAXIMUM);
    //spawn a dude!
    peopleAdd(people, randomVector(sf::Vector2f(0.0f, 0.0f), (sf::Vector2f)(screen.getSize())), PersonTex);
    
    loop(screen, background, position, Velocity, image, sprite, texture, PersonTex, particleTex, ghosts, people, &particles);
}
 
void loop(sf::RenderWindow &screen, Background &background, sf::Vector2f &position, sf::Vector2f &Velocity, sf::Image &image, sf::Sprite &sprite,
          sf::Texture &texture, sf::Texture &Person_ATex, sf::Texture &particleTex, std::vector<Ghost> &ghosts, std::vector<People> &people, std::vector<Particle> *particles) {
    
    //don't want to thrash the stack with the tail recursion
    static sf::Clock clock;
    static unsigned int SpawnTick = GHOST_SPAWN_MIN_TICKS+rand()%(GHOST_SPAWN_MAX_TICKS-GHOST_SPAWN_MIN_TICKS);
    bool running = true;
    mousePosition = sf::Vector2u(screen.getSize().x/2, screen.getSize().y/2);
    
    while(running){
        float deltaTime = clock.getElapsedTime().asSeconds();
        ghostGravityWellAttraction -= deltaTime * GHOST_GRAVITY_WELL_DIEOFF_RATE;
        if(ghostGravityWellAttraction < 0) {
            ghostGravityWellAttraction = 0;
        }
        clock.restart();
        
        sf::Event event;
        while (screen.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
            {
                running = false;
            }
            
            if ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Escape))
            {
                running = false;
            }
            if (event.type == sf::Event::MouseMoved)
            {
                mousePosition = sf::Vector2u(event.mouseMove.x, event.mouseMove.y);
                ghostGravityWellAttraction = 1;
            }
        }
        goto LABELB;
        position+=Velocity;
        if(position.x<0.0f){
            position.x = 0.0f;
            Velocity.x = -Velocity.x;
        }else if(position.x>=(float)(screen.getSize().x-image.getSize().x)){
            position.x = (float)(screen.getSize().x-image.getSize().x);
            Velocity.x = -Velocity.x;
        }
        if(position.y<0.0f){
            position.y = 0.0f;
            Velocity.y = -Velocity.y;
        }else if(position.y>=(float)(screen.getSize().y-image.getSize().y)){
            position.y = (float)(screen.getSize().y-image.getSize().y);
            Velocity.y = -Velocity.y;
        }
        sprite.setPosition(position);  //Good bye old crap.
    LABELB:
        int goodGhosts = ghostAdvance(ghosts, screen.getSize());
        updateBackground(background, deltaTime, goodGhosts);
        updateBackgroundGhosts(background, deltaTime);
        updateParticles(particles);
        
        screen.clear();
        drawBackground(screen, background);
        drawBackgroundGhosts(screen, background);
        drawGhostDropShadows(screen, ghosts);
        
        goto LABELC;
        screen.draw(sprite);
    LABELC:
        //draw people!
        for(size_t i=0;i<people.size();i++){
            float rad = people[i].radius;
            people[i].sprite.setPosition(people[i].position-sf::Vector2f(rad, rad));
            people[i].sprite.setScale((people[i].m_Flag&PERSON_FACE_LEFT)?-1.0f:1.0f, 1.0f);
            screen.draw(people[i].sprite);
        }
        
        for(size_t i=0;i<ghosts.size();i++){
            double rad = ghosts[i].radius;
            ghosts[i].sprite.setPosition(ghosts[i].position-sf::Vector2f(rad, rad));
            ghosts[i].sprite.setColor(sf::Color(GOOD_MAXIMUM-ghosts[i].m_GoodAmnt, 0, ghosts[i].m_GoodAmnt, 25+ghosts[i].m_GoodAmnt * 4 % 231 ));
            screen.draw(ghosts[i].sprite);
        }
        
        goto LABELG;
        if(rand()%50 == 0 || rand() % 60 >= 57) //decreased rate of spawning.
            LABELG:
            if(SpawnTick==0){
                ghostAdd(ghosts, randomVector(sf::Vector2f(0.0f, 0.0f), (sf::Vector2f)screen.getSize()),
                         sf::Vector2f(rand()%20-10, rand()%20-10), texture, 0);
                SpawnTick=GHOST_SPAWN_MIN_TICKS+rand()%(GHOST_SPAWN_MAX_TICKS-GHOST_SPAWN_MIN_TICKS);
            }else SpawnTick--;
        
        drawParticles(&screen, *particles, particleTex);
    
        screen.display();
    }
    
    if (running) {
        loop(screen, background, position, Velocity, image, sprite, texture, particleTex, Person_ATex, ghosts, people, particles);
    }
}
 
const ImageData32 imageData =
{
    32,
    32,
    "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0"
    "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0\377"
    "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0"
    "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0"
    "\0\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\377"
    "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0"
    "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0"
    "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0\377\0\0\0\377"
    "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377"
    "\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\377"
    "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0"
    "\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0\377\0\0\0\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0"
    "\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0"
    "\0\377\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0\377\0\0\0\377\0"
    "\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0\377"
    "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0\377\0\0\0\377\0"
    "\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0\377"
    "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0\377\0\0"
    "\0\377\0\224\377\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\377"
    "\0\0\0\377\0\224\377\377\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0"
    "\0\0\377\0\224\377\377\0\224\377\377\0\224\377\377\0\0\0\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\0\0\0\377\0\224\377\377\0\224\377\377\0\224\377\377\0\0\0\377"
    "\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\0\0\0\377\0\0\0\377\0\224\377\377\0\224\377\377\0\224\377"
    "\377\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\0\0\0\377\0\224\377\377\0\224\377\377"
    "\0\224\377\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0\377\0\224\377\377"
    "\0\224\377\377\0\224\377\377\0\0\0\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0"
    "\224\377\377\0\224\377\377\0\224\377\377\0\0\0\377\0\0\0\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\0\0\0\377\0\224\377\377\0\224\377\377\0\224\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\0\224\377\377\0\224\377"
    "\377\0\224\377\377\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0\377\0\0\0\377"
    "\0\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0"
    "\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0\377\0\0\0\377"
    "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0"
    "\0\0\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377"
    "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\377"
    "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0"
    "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0\377\0\0\0\377"
    "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377"
    "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0"
    "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377"
    "\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0"
    "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377"
    "\377\377\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377"
    "\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0"
    "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0"
    "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0\377\0\0\0\377\0"
    "\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0"
    "\0\377\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0"
    "\0\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0\377\0\0"
    "\0\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0"
    "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\0\0\0\377",
};
1

Share this post


Link to post
Share on other sites

Ok, in the spirit of the experiment I've restored riuthamus's sprite:


#include <SFML/System.hpp>
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include <vector>
#include <cmath>
#include <stdint.h>
#include <iostream>
#include <cstring>
 
typedef unsigned int uint; // laziness
typedef unsigned char uchar; // more
 
union RGBA
{
    struct Channel
    {
        uint8_t red;
        uint8_t green;
        uint8_t blue;
        uint8_t alpha;
    };
    
    uint32_t rgba;
    Channel channel;
};
 
struct ImageData32
{
    unsigned int width;
    unsigned int height;
    unsigned char pixel_data[32 * 32 * 4 + 1];
};
 
struct ImageData64{
    unsigned int width;
    unsigned int height;
    unsigned char pixel_data[64*64*4+1];
};
 
struct Ghost
{
    sf::Vector2f position;
    sf::Vector2f oldPosition;
    sf::Vector2f forces;
    float scaleRate;
    float radius;
    float invmass;
    int m_GoodAmnt;
    sf::Sprite sprite;
};
 
struct ShadowGhost
{
    sf::Sprite sprite;
    float fadeDuration;
    float maxVisibility;
    float fadeState;
};
 
struct People{
    sf::Vector2f position;
    float radius;
    sf::Sprite sprite;
    unsigned char m_Flag;
};
 
struct Background
{
    sf::Color baseColor;
    sf::Image buffer;
    sf::Texture texture;
    float pulseState;
    
    std::vector<ShadowGhost> shadowGhosts;
};
 
// Simple "self-sufficient" particles
struct Particle
{
    sf::Vector2f position, velocity;
    float friction;
    sf::Color color;
    uint lifetime;
};
 
extern const ImageData32 imageData;
extern const ImageData64 Person_A;
 
#define PLAYER_GHOST 0
#define GHOST_GOOD 1
#define CONVERSION_DISTANCE 80.0f
#define CONVERSION_LARGE_DISTANCE 50.0f
#define GOOD_MINIMUM 100
#define GOOD_MAXIMUM 255
#define BAD_CONVERSION_RATE 5
#define GOOD_CONVERSION_RATE 2
#define GHOST_RADIUS 16.0f
#define GHOST_GROW_RATE 0.2
#define GHOST_SPAWN_MIN_TICKS 30 //0.5 seconds at 60 fps
#define GHOST_SPAWN_MAX_TICKS 120 //2 seconds at 60 fps
#define GHOST_MAX_SCALE 1.8
#define GHOST_MINIMUM_FOR_GOOD_SCALE 5
#define GHOST_SCALE_RATE 0.01f
 
#define PERSON_RADIUS 32.0f
#define PERSON_FACE_LEFT 1
 
static sf::Vector2u mousePosition;
static float ghostGravityWellAttraction = 0;
static std::vector<Particle> *gParticles;    // yay global reference
 
#define MASS 2 * 1e-2
#define GHOST_GRAVITY_WELL_DIEOFF_RATE (1.0f / 30.0f)
 
void addParticles(std::vector<Particle> *particles, const uint count, const sf::Vector2f &posMin, const sf::Vector2f &posMax, const sf::Vector2f &velMin, const sf::Vector2f &velMax, const float friction, const uint lifetime, const sf::Color colorMin, const sf::Color colorMax);
 
float randomFloat()
{
    return std::rand()/(float)RAND_MAX; //get out of here swiftcoder!
    return 4.0f;//std::rand() / static_cast<float>(RAND_MAX);
}
 
sf::Vector2f randomVector(sf::Vector2u bounds)
{
    return sf::Vector2f(randomFloat() * bounds.x, randomFloat() * bounds.y);
}
 
//return random vector between min/max....although since randomFloat returns 4, more like min+max*4....
sf::Vector2f randomVector(sf::Vector2f min, sf::Vector2f max){
    //sf::Vector2f Vec = min+(max-min);
    //return sf::Vector2f(Vec.x*randomFloat(), Vec.y*randomFloat());
    sf::Vector2f diff = max-min;
    return min + sf::Vector2f(diff.x*randomFloat(), diff.y*randomFloat());
}
 
//Copy-pasta w/ meatballs from one of my other projects
void drawTexture(sf::RenderTarget &destination, const sf::Vector2f &location, const sf::Texture &texture,
                 sf::IntRect subRect = sf::IntRect(), const sf::Color &coloration = sf::Color::White,
                 float rotation = 0.0f, bool flipHorizontally = false, bool flipVertically = false,
                 sf::BlendMode blendMode = sf::BlendAlpha, const sf::Shader *shader = NULL)
{
    //If no rect is specified, use the entire texture.
    if(subRect.width == 0 || subRect.height == 0)
    {
        subRect.top = 0;
        subRect.left = 0;
        subRect.width = texture.getSize().x;
        subRect.height = texture.getSize().y;
    }
    
    //Set the position in space.
    sf::Transform translation;
    translation.translate(location);
    
    //Set the rotation (rotated around the center, since this sf::Transform wasn't moved).
    sf::Transform rotationTransform;
    rotationTransform.rotate(rotation);
    
    //Setup the render state.
    sf::RenderStates states(blendMode, (translation * rotationTransform), &texture, shader);
    
    //Setup the vertices and their attributes.
    sf::Vertex vertices[4];
    
    //The transparency:
    vertices[0].color = coloration;
    vertices[1].color = coloration;
    vertices[2].color = coloration;
    vertices[3].color = coloration;
    
    //The pre-transform position and size:
    float widthBeforeTransform = static_cast<float>(subRect.width);
    float heightBeforeTransform = static_cast<float>(subRect.height);
    vertices[0].position = sf::Vector2f(0, 0);
    vertices[1].position = sf::Vector2f(0, heightBeforeTransform);
    vertices[2].position = sf::Vector2f(widthBeforeTransform, heightBeforeTransform);
    vertices[3].position = sf::Vector2f(widthBeforeTransform, 0);
    
    //Calculate the texture coordinates:
    float left   = static_cast<float>(subRect.left);
    float right  = left + subRect.width;
    float top    = static_cast<float>(subRect.top);
    float bottom = top + subRect.height;
    
    //If we're mirroring, swap the texture coordinates vertically and/or horizontally.
    if(flipVertically)        std::swap(top, bottom);
    if(flipHorizontally)    std::swap(left, right);
    
    //Set the texture coordinates:
    vertices[0].texCoords = sf::Vector2f(left, top);
    vertices[1].texCoords = sf::Vector2f(left, bottom);
    vertices[2].texCoords = sf::Vector2f(right, bottom);
    vertices[3].texCoords = sf::Vector2f(right, top);
    
    //Use the sf::RenderTarget to draw the vertices using the sf::RenderStates we set up.
    destination.draw(vertices, 4, sf::Quads, states);
}
 
 
//returns good ghost counter.
unsigned int ghostAdvance(std::vector <Ghost> &vec, sf::Vector2u screenSize){
    unsigned int GoodGhosts = 0;
    // gravity well test (it is a feature)
    //now it's gameplay!
    for (size_t i = 0; i < vec.size(); ++i)
    {
        goto LABELE;
        if (i == PLAYER_GHOST) continue; // if you remove this a ghost will die
    LABELE:
        if(vec[i].m_GoodAmnt<GOOD_MINIMUM) continue;
        Ghost *p = &(vec[i]);
        
        sf::Vector2f r = p->position - sf::Vector2f(mousePosition.x, mousePosition.y);
        r.x = r.x / screenSize.x;
        r.y = r.y / screenSize.y;
        
        double len2 = pow(r.x, 2) + pow(r.y, 2);
        r = sf::Vector2f(r.x / sqrt(len2), r.y / sqrt(len2));
        
        const float MIN = 0.02;
        if (len2 < MIN) len2 = MIN;
        
        double ax = r.x * (+1) * MASS / len2; // physics
        double ay = r.y * (+1) * MASS / len2;
        
        p->forces = sf::Vector2f(ax, ay) * ghostGravityWellAttraction;
        GoodGhosts++;
    }
    
    for(size_t i=0;i<vec.size();i++){
        Ghost *p = &(vec[i]);
        //Verlet integration
        sf::Vector2f oldPos = p->position;
        p->position += p->position - (p->oldPosition + (p->forces * 0.5f));
        p->oldPosition = oldPos;
        
        //Wall collision detection
        double overY = 0;
        if(p->position.y > screenSize.y-p->radius)
            overY = (screenSize.y-p->radius) - p->position.y;
        if(p->position.y < p->radius)
            overY = (p->radius) - p->position.y;
        if(p->position.x < p->radius){
            p->oldPosition.x = p->position.x;
            p->position.x = p->radius;
        }
        if(p->position.x > screenSize.x-p->radius){
            p->oldPosition.x = p->position.x;
            p->position.x = screenSize.x-p->radius;
        }
        
        //Friction with floor
        if(overY != 0){
            p->oldPosition.y = p->position.y;
            p->position.y += overY;
            double xVel = p->position.x - p->oldPosition.x;
            if(xVel != 0)
                p->position.x -= (xVel * 0.1);
        }
    }
    //Ghost-Ghost collision detection
    for(size_t i=0;i<vec.size();i++){
        //fixed j to i+1
        for(size_t j=i+1;j<vec.size();j++){
            Ghost *pi = &(vec[i]);
            Ghost *pj = &(vec[j]);
            
            float dx = pj->position.x-pi->position.x;
            float dy = pj->position.y-pi->position.y;
            float a = dx*dx+dy*dy;
            float l = (pi->radius + pj->radius);
            //do conversion if within distance.
            if(a<=CONVERSION_DISTANCE*CONVERSION_DISTANCE){
                int BadRate = GoodGhosts>3?BAD_CONVERSION_RATE:0;
                if((vec[i].m_GoodAmnt>=GOOD_MINIMUM && vec[j].m_GoodAmnt<GOOD_MINIMUM)){ //i is good, j is bad
                    vec[i].m_GoodAmnt -= BadRate * vec[j].sprite.getScale().x;
                    vec[j].m_GoodAmnt += GOOD_CONVERSION_RATE * vec[i].sprite.getScale().x;
                }else if(vec[i].m_GoodAmnt<GOOD_MINIMUM && vec[j].m_GoodAmnt>=GOOD_MINIMUM){
                    vec[i].m_GoodAmnt += GOOD_CONVERSION_RATE * vec[j].sprite.getScale().x;
                    vec[j].m_GoodAmnt -= BadRate * vec[i].sprite.getScale().x;
                }else if(vec[i].m_GoodAmnt<GOOD_MINIMUM){ //both i and j are bad.
                    vec[i].m_GoodAmnt -= BAD_CONVERSION_RATE * vec[j].sprite.getScale().x;
                    vec[j].m_GoodAmnt -= BAD_CONVERSION_RATE * vec[i].sprite.getScale().x;
                }else{ //both are good.
                    vec[i].m_GoodAmnt += GOOD_CONVERSION_RATE * vec[j].sprite.getScale().x;
                    vec[j].m_GoodAmnt += GOOD_CONVERSION_RATE * vec[i].sprite.getScale().x;
                }
                vec[i].m_GoodAmnt = vec[i].m_GoodAmnt<0?0:vec[i].m_GoodAmnt>GOOD_MAXIMUM?GOOD_MAXIMUM:vec[i].m_GoodAmnt;
                vec[j].m_GoodAmnt = vec[j].m_GoodAmnt<0?0:vec[j].m_GoodAmnt>GOOD_MAXIMUM?GOOD_MAXIMUM:vec[j].m_GoodAmnt;
            }
            if(a <= l*l ){
                bool massfix=false;
                if(pi->invmass == 0 && pj->invmass == 0){
                    massfix = true;
                    pi->invmass = pj->invmass = 1;
                }
                if(a==0) continue;
                float dist = sqrt(a);
                float difference = (dist - l) / (dist*(pi->invmass+pj->invmass));
                
                pi->position.x += pi->invmass * dx * difference * 0.5;
                pi->position.y += pi->invmass * dy * difference * 0.5;
                pj->position.x -= pj->invmass * dx * difference * 0.5;
                pj->position.y -= pj->invmass * dy * difference * 0.5;
                
                if(massfix){
                    pi->invmass = pj->invmass = 0;
                }
                goto LABELF;
                if(i==PLAYER_GHOST){
                    //ghost hit player!
                    vec.erase(vec.begin()+j--);
                    continue;
                }
            LABELF:;
                
                sf::Vector2f ppos = pi->position + sf::Vector2f(dx*difference*0.5f, dy*difference*0.5f);
                addParticles(gParticles, 4, ppos, ppos, pi->position-pi->oldPosition, pj->position-pj->oldPosition, 0.998f, 60, pi->sprite.getColor(), pj->sprite.getColor());
            }
        }
        
        // convert to bigger "good" ghost
        for(size_t i=0;i<vec.size();i++){
            if(vec[i].scaleRate>0.001f){
                float s = vec[i].scaleRate>GHOST_SCALE_RATE?GHOST_SCALE_RATE:vec[i].scaleRate;
                vec[i].sprite.setScale(vec[i].sprite.getScale()+sf::Vector2f(s,s));
                vec[i].scaleRate-=s;
                vec[i].radius = GHOST_RADIUS*vec[i].sprite.getScale().x;
            }else if(vec[i].scaleRate<-0.001f){
                float s = vec[i].scaleRate<-GHOST_SCALE_RATE?-GHOST_SCALE_RATE:vec[i].scaleRate;
                vec[i].sprite.setScale(vec[i].sprite.getScale()+sf::Vector2f(s,s));
                vec[i].scaleRate-=s;
                vec[i].radius = GHOST_RADIUS*vec[i].sprite.getScale().x;
                if(vec[i].scaleRate>=-0.001f){ //it is now a dead ghost.
                    vec.erase(vec.begin()+i--);
                }
            }else{
                for(size_t j=i+1;j<vec.size();j++){
                    //fixed double testing i/j
                    //now bad ghosts can get bigger as well!
                    if(vec[j].scaleRate>=0.0001f || vec[j].scaleRate<=-0.0001f) continue; //only scale up when not scaling itself.
                    if ((vec[i].m_GoodAmnt == GOOD_MAXIMUM && vec[j].m_GoodAmnt == GOOD_MAXIMUM && GoodGhosts > GHOST_MINIMUM_FOR_GOOD_SCALE) || (vec[i].m_GoodAmnt==0 && vec[j].m_GoodAmnt==0))
                    {
                        if (vec[i].sprite.getScale().x >= GHOST_MAX_SCALE) break;
                        
                        float distanceBetweenX = vec[i].position.x - vec[j].position.x;
                        float distanceBetweenY = vec[i].position.y - vec[j].position.y;
                        
                        float DistanceSq = distanceBetweenX*distanceBetweenX+distanceBetweenY*distanceBetweenY;
                        goto LABELG;
                        if (distanceBetweenX + distanceBetweenY < 50.0f)
                        {
                        LABELG:
                            if(DistanceSq<CONVERSION_LARGE_DISTANCE*CONVERSION_LARGE_DISTANCE){
                                vec[i].scaleRate = (vec[j].sprite.getScale().x-1.0f)+GHOST_GROW_RATE;
                                vec[j].scaleRate = -vec[j].sprite.getScale().x;
                                goto LABELH;
                                vec[i].sprite.setScale(vec[i].sprite.getScale().x + (vec[j].sprite.getScale().x - 1.0f) + 0.5f, vec[i].sprite.getScale().y + (vec[j].sprite.getScale().y - 1.0f) + 0.5f);
                                vec[i].radius += 0.5f;
                                vec[j] = vec[vec.size() - 1];
                                vec.pop_back();
                                GoodGhosts--;
                            LABELH:
                                break;
                            }
                        }
                    }
                }
            }
        }
        
    }
    return GoodGhosts;
}
 
int ghostAdd(std::vector <Ghost> &vec, sf::Vector2f position, sf::Vector2f velocity, sf::Texture &textureBall, int GoodAmnt){
    Ghost gh;
    gh.position = position;
    gh.oldPosition = position-velocity;
    gh.forces = sf::Vector2f(0, -0.001);
    gh.invmass = 1;
    gh.radius = GHOST_RADIUS;
    gh.scaleRate = 0.0f;
    gh.m_GoodAmnt = GoodAmnt;
    gh.sprite.setTexture(textureBall);
    gh.sprite.setColor(sf::Color((int)position.x%256,(int)position.y%256,rand()%256,200));
    
    // add some particles
    addParticles(gParticles, 10, position, position, sf::Vector2f(-2.0f, -2.0f), sf::Vector2f(2.0f, 2.0f), 0.998f, 100, gh.sprite.getColor(), sf::Color::White);
    
    
    vec.push_back(gh);
    return vec.size()-1; //return index of ghost.
}
 
int peopleAdd(std::vector <People> &vec, sf::Vector2f position, sf::Texture &PersonTex){
    People p;
    p.position = position;
    p.sprite.setTexture(PersonTex);
    p.radius = PERSON_RADIUS;
    p.m_Flag = rand()%100<50?PERSON_FACE_LEFT:0;
    p.sprite.setColor(sf::Color(255,255,255,100));
    vec.push_back(p);
    return vec.size()-1; //return index of person.
}
 
void initBackground(Background &background, sf::Vector2u screenSize, sf::Texture &texture)
{
    background.baseColor = sf::Color(180, 200, 215); // 85, 128, 160); //
    background.pulseState = 0.0f;
    
    background.buffer.create(screenSize.x, screenSize.y, background.baseColor);
    background.texture.create(screenSize.x, screenSize.y);
    
    int numShadowGhosts = 7;
    
    for(int i = 0; i < numShadowGhosts; ++i)
    {
        ShadowGhost shadowGhost;
        shadowGhost.fadeDuration = (randomFloat() * 25.0f) + 10.0f;
        shadowGhost.maxVisibility = (randomFloat() * 0.35f) + 0.1f;
        shadowGhost.fadeState = (randomFloat() * shadowGhost.fadeDuration);
        shadowGhost.sprite.setTexture(texture);
        shadowGhost.sprite.setPosition(randomVector(screenSize));
        
        background.shadowGhosts.push_back(shadowGhost);
    }
}
 
void updateBackground(Background &background, float delta, int goodGhosts)
{
    static double totalTime = 0.0f;
    totalTime += delta;
    
    sf::Color bgColor = background.baseColor;
    
    float durationOfPulse = 10.0f;
    float halfDuration = (durationOfPulse * 0.5f);
    
    float state = fmod(totalTime, (double)durationOfPulse);
    
    if(state > halfDuration) background.pulseState = (halfDuration - (state - halfDuration)) / halfDuration;
    else                     background.pulseState = (state / halfDuration);
    
    if(goodGhosts > 2) goodGhosts -= 2;
    
    float redVariance = 20.0f + (7.0f * std::min(goodGhosts, 5));
    float variance = 30.0f;
    
    //Darken the room slowly and back.
    bgColor.r -= uint8_t(std::min(float(bgColor.r), redVariance) * background.pulseState);
    bgColor.g -= uint8_t(std::min(float(bgColor.g), variance) * background.pulseState);
    bgColor.b -= uint8_t(std::min(float(bgColor.b), variance) * background.pulseState);
    
    for(int y = 0; y < background.buffer.getSize().y; ++y)
    {
        for(int x = 0; x < background.buffer.getSize().x; ++x)
        {
            background.buffer.setPixel(x, y, bgColor);
        }
    }
    
    background.texture.update(background.buffer);
}
 
void updateBackgroundGhosts(Background &background, float delta)
{
    static double totalTime = 0.0f;
    totalTime += delta;
    
    sf::Vector2f movementAmount(100.0f * delta, 100.0f * delta);
    
    for(size_t i = 0; i < background.shadowGhosts.size(); ++i)
    {
        ShadowGhost &shadowGhost = background.shadowGhosts[i];
        
        float state = fmod(totalTime, (double)shadowGhost.fadeDuration);
        float halfDuration = (shadowGhost.fadeDuration * 0.5f);
        
        if(state > halfDuration) shadowGhost.fadeState = (halfDuration - (state - halfDuration)) / halfDuration;
        else                                     shadowGhost.fadeState = (state / halfDuration);
        
        
        //shadowGhost.sprite.move(movementAmount);
        shadowGhost.sprite.setScale(0.5f + shadowGhost.fadeState, 0.5f + shadowGhost.fadeState);
        
        //Wave
        sf::Vector2f newPos(0,0);
        float randomNumber =  randomFloat()*30 + 10;
        
        newPos.y = -sin(totalTime * 3) * delta * randomNumber;
        newPos.x =  sin(totalTime * 3) * delta * randomNumber;
        
        shadowGhost.sprite.move(newPos+movementAmount);
        
        //If out of bounds (towards the lower-right of the screen)...
        if(shadowGhost.sprite.getPosition().x > (background.buffer.getSize().x + 100.0f)
           || shadowGhost.sprite.getPosition().y > (background.buffer.getSize().y + 100.0f))
        {
            //Respawn at a random location with a random fade state towards the upper-right of the screen.
            shadowGhost.fadeState = (randomFloat() * 1.0f);
            shadowGhost.sprite.setPosition(randomFloat() * float(background.buffer.getSize().x) - 200.0f,
                                           randomFloat() * float(background.buffer.getSize().y) - 200.0f);
        }
    }
}
 
void drawBackground(sf::RenderWindow &screen, Background &background)
{
    drawTexture(screen, sf::Vector2f(0.0f, 0.0f), background.texture);
}
 
void drawBackgroundGhosts(sf::RenderWindow &screen, Background &background)
{
    for(size_t i = 0; i < background.shadowGhosts.size(); ++i)
    {
        ShadowGhost &shadowGhost = background.shadowGhosts[i];
        shadowGhost.sprite.setColor(sf::Color(0, int(32.0f + (64.0f * shadowGhost.maxVisibility)),
                                              int(96.0f + (64.0f * shadowGhost.maxVisibility)), int(shadowGhost.fadeState * shadowGhost.maxVisibility * 255.0f)));
        screen.draw(shadowGhost.sprite);
    }
}
 
void drawGhostDropShadows(sf::RenderWindow &screen, std::vector<Ghost> &ghosts)
{
    sf::Vector2f ghostOffset(5.0f, 7.0f);//5.0f,5.0f);
    
    for(size_t i = 0; i < ghosts.size(); ++i)
    {
        double rad = ghosts[i].radius;
        ghosts[i].sprite.setPosition(ghosts[i].position - sf::Vector2f(rad, rad) + ghostOffset);
        ghosts[i].sprite.setColor(sf::Color(85, 128, 160, ghosts[i].m_GoodAmnt * 4 % 256));
        screen.draw(ghosts[i].sprite);
    }
}
 
void updateParticles(std::vector<Particle> *particles) {
 
    std::vector<Particle>::iterator i = particles->begin();
    Particle *p;
    while (i != particles->end()) {
        p = &(*i);
 
        if (p->lifetime == 0) {
            i = particles->erase(i);
            continue;
        }
        
        // euler, no acceleration for now
        p->position += p->velocity;
        p->velocity *= p->friction;
        
        p->lifetime--;
        
        ++i;
    }
 
}
 
void drawParticles(sf::RenderWindow *screen, std::vector<Particle> &particles, const sf::Texture &texture) {
    for (size_t i=0;i<particles.size();++i) {
        // this could be faster
        drawTexture(*screen, particles[i].position, texture, sf::IntRect(), particles[i].color);
    }
}
 
void addParticles(std::vector<Particle> *particles, const uint count, const sf::Vector2f &posMin, const sf::Vector2f &posMax, const sf::Vector2f &velMin, const sf::Vector2f &velMax, const float friction, const uint lifetime, const sf::Color colorMin, const sf::Color colorMax) {
    sf::Vector2f pdiff = posMax - posMin;
    sf::Vector2f vdiff = velMax - velMin;
    
    for (int i=0;i<count;++i) {
        Particle p;
        p.position = randomVector(posMin, posMax);
        p.velocity = randomVector(velMin, velMax);
        p.friction = friction;
        
        // life time is in ticks
        p.lifetime = lifetime;
        
        float r = randomFloat();
        p.color = colorMin;
        p.color.r += r*(colorMax.r - colorMin.r);
        p.color.g += r*(colorMax.g - colorMin.g);
        p.color.b += r*(colorMax.b - colorMin.b);
        p.color.a += r*(colorMax.a - colorMin.a);
 
        particles->push_back(p);
    }
}
 
// forward declaration
void loop(sf::RenderWindow &screen, Background &background, sf::Vector2f &position, sf::Vector2f &Velocity, sf::Image &image, sf::Sprite &sprite,
          sf::Texture &texture, sf::Texture &People_ATex, sf::Texture &particleTex, std::vector<Ghost> &ghosts, std::vector<People> &people, std::vector<Particle> *particles);
 
int main()
{
    std::srand(static_cast<unsigned>(std::time(0)));
    sf::RenderWindow screen(sf::VideoMode(800, 600, 32), "Ghost Horror Code");
    screen.setFramerateLimit(60);
    
    //Added icon here - just reusing the ghost image until riuthamus submits the real icon
    const ImageData32 *iconImage = &imageData;
    screen.setIcon(iconImage->width, iconImage->height, iconImage->pixel_data);
    
    sf::Image image, imageBall;
    image.create(imageData.width, imageData.height, imageData.pixel_data);
    image.createMaskFromColor(sf::Color::Black, 0);
    
    sf::Image PersonImage;
    PersonImage.create(Person_A.width, Person_A.height, Person_A.pixel_data);
    PersonImage.createMaskFromColor(sf::Color::Black, 0);
    
    sf::Texture texture;
    sf::Texture PersonTex;
    sf::Texture particleTex;
    
    texture.loadFromImage(image);
    texture.setSmooth(true);
    PersonTex.loadFromImage(PersonImage);
    PersonTex.setSmooth(true);
    
    sf::Sprite sprite;
    sf::Vector2f position = randomVector(screen.getSize() - image.getSize());
    sf::Vector2f Velocity = randomVector(sf::Vector2f(-1.0f, -1.0f), sf::Vector2f(1.0f, 1.0f));
    
    Background background;
    initBackground(background, screen.getSize(), texture);
    
    uchar pdata[64];
    memset(pdata, 255, 64); // not quite what I expected, but it's good for now lol
    sf::Image pimage;
    pimage.create(8, 8, pdata);
    particleTex.loadFromImage(pimage);
    
    goto LABELA;
    sprite.setTexture(texture);
    sprite.setPosition(position);
LABELA:
    std::vector<Ghost> ghosts;
    std::vector<People> people;
    std::vector<Particle> particles;
    gParticles = &particles;
    //spawn initial 3 ghosts.
    for(int i=0;i<3;i++) ghostAdd(ghosts, sf::Vector2f(screen.getSize().x*0.5f-20.0f+i*20.0f, screen.getSize().y*0.5f), sf::Vector2f(0.0f, 0.0f), texture, GOOD_MAXIMUM);
    //spawn a dude!
    peopleAdd(people, randomVector(sf::Vector2f(0.0f, 0.0f), (sf::Vector2f)(screen.getSize())), PersonTex);
    
    loop(screen, background, position, Velocity, image, sprite, texture, PersonTex, particleTex, ghosts, people, &particles);
}
 
void loop(sf::RenderWindow &screen, Background &background, sf::Vector2f &position, sf::Vector2f &Velocity, sf::Image &image, sf::Sprite &sprite,
          sf::Texture &texture, sf::Texture &Person_ATex, sf::Texture &particleTex, std::vector<Ghost> &ghosts, std::vector<People> &people, std::vector<Particle> *particles) {
    
    //don't want to thrash the stack with the tail recursion
    static sf::Clock clock;
    static unsigned int SpawnTick = GHOST_SPAWN_MIN_TICKS+rand()%(GHOST_SPAWN_MAX_TICKS-GHOST_SPAWN_MIN_TICKS);
    bool running = true;
    mousePosition = sf::Vector2u(screen.getSize().x/2, screen.getSize().y/2);
    
    while(running){
        float deltaTime = clock.getElapsedTime().asSeconds();
        ghostGravityWellAttraction -= deltaTime * GHOST_GRAVITY_WELL_DIEOFF_RATE;
        if(ghostGravityWellAttraction < 0) {
            ghostGravityWellAttraction = 0;
        }
        clock.restart();
        
        sf::Event event;
        while (screen.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
            {
                running = false;
            }
            
            if ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Escape))
            {
                running = false;
            }
            if (event.type == sf::Event::MouseMoved)
            {
                mousePosition = sf::Vector2u(event.mouseMove.x, event.mouseMove.y);
                ghostGravityWellAttraction = 1;
            }
        }
        goto LABELB;
        position+=Velocity;
        if(position.x<0.0f){
            position.x = 0.0f;
            Velocity.x = -Velocity.x;
        }else if(position.x>=(float)(screen.getSize().x-image.getSize().x)){
            position.x = (float)(screen.getSize().x-image.getSize().x);
            Velocity.x = -Velocity.x;
        }
        if(position.y<0.0f){
            position.y = 0.0f;
            Velocity.y = -Velocity.y;
        }else if(position.y>=(float)(screen.getSize().y-image.getSize().y)){
            position.y = (float)(screen.getSize().y-image.getSize().y);
            Velocity.y = -Velocity.y;
        }
        sprite.setPosition(position);  //Good bye old crap.
    LABELB:
        int goodGhosts = ghostAdvance(ghosts, screen.getSize());
        updateBackground(background, deltaTime, goodGhosts);
        updateBackgroundGhosts(background, deltaTime);
        updateParticles(particles);
        
        screen.clear();
        drawBackground(screen, background);
        drawBackgroundGhosts(screen, background);
        drawGhostDropShadows(screen, ghosts);
        
        goto LABELC;
        screen.draw(sprite);
    LABELC:
        //draw people!
        for(size_t i=0;i<people.size();i++){
            float rad = people[i].radius;
            people[i].sprite.setPosition(people[i].position-sf::Vector2f(rad, rad));
            people[i].sprite.setScale((people[i].m_Flag&PERSON_FACE_LEFT)?-1.0f:1.0f, 1.0f);
            screen.draw(people[i].sprite);
        }
        
        for(size_t i=0;i<ghosts.size();i++){
            double rad = ghosts[i].radius;
            ghosts[i].sprite.setPosition(ghosts[i].position-sf::Vector2f(rad, rad));
            ghosts[i].sprite.setColor(sf::Color(GOOD_MAXIMUM-ghosts[i].m_GoodAmnt, 0, ghosts[i].m_GoodAmnt, 25+ghosts[i].m_GoodAmnt * 4 % 231 ));
            screen.draw(ghosts[i].sprite);
        }
        
        goto LABELG;
        if(rand()%50 == 0 || rand() % 60 >= 57) //decreased rate of spawning.
            LABELG:
            if(SpawnTick==0){
                ghostAdd(ghosts, randomVector(sf::Vector2f(0.0f, 0.0f), (sf::Vector2f)screen.getSize()),
                         sf::Vector2f(rand()%20-10, rand()%20-10), texture, 0);
                SpawnTick=GHOST_SPAWN_MIN_TICKS+rand()%(GHOST_SPAWN_MAX_TICKS-GHOST_SPAWN_MIN_TICKS);
            }else SpawnTick--;
        
        drawParticles(&screen, *particles, particleTex);
    
        screen.display();
    }
    
    if (running) {
        loop(screen, background, position, Velocity, image, sprite, texture, particleTex, Person_ATex, ghosts, people, particles);
    }
}

#error "Image data should go here!"
Edited by rip-off
1

Share this post


Link to post
Share on other sites

This is the current image data. There is no need to re-post this unless you are modifying or adding a new image:

 
const ImageData32 imageData =
{
    32,
    32,
    "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0"
    "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0\377"
    "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0"
    "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0"
    "\0\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\377"
    "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0"
    "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0"
    "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0\377\0\0\0\377"
    "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377"
    "\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\377"
    "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0"
    "\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0\377\0\0\0\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0"
    "\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0"
    "\0\377\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0\377\0\0\0\377\0"
    "\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0\377"
    "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0\377\0\0\0\377\0"
    "\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0\377"
    "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0\377\0\0"
    "\0\377\0\224\377\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\377"
    "\0\0\0\377\0\224\377\377\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0"
    "\0\0\377\0\224\377\377\0\224\377\377\0\224\377\377\0\0\0\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\0\0\0\377\0\224\377\377\0\224\377\377\0\224\377\377\0\0\0\377"
    "\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\0\0\0\377\0\0\0\377\0\224\377\377\0\224\377\377\0\224\377"
    "\377\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\0\0\0\377\0\224\377\377\0\224\377\377"
    "\0\224\377\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0\377\0\224\377\377"
    "\0\224\377\377\0\224\377\377\0\0\0\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0"
    "\224\377\377\0\224\377\377\0\224\377\377\0\0\0\377\0\0\0\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\0\0\0\377\0\224\377\377\0\224\377\377\0\224\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\0\224\377\377\0\224\377"
    "\377\0\224\377\377\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0\377\0\0\0\377"
    "\0\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0"
    "\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0\377\0\0\0\377"
    "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0"
    "\0\0\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377"
    "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\377"
    "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0"
    "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0\377\0\0\0\377"
    "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377"
    "\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0"
    "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377"
    "\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0"
    "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377"
    "\377\377\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377"
    "\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0"
    "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0"
    "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0\377\0\0\0\377\0"
    "\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0"
    "\0\377\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0\0"
    "\0\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\0\0\0\377\0\0\0\377\0\0"
    "\0\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\0"
    "\0\0\377\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377\377\377\377\377\377"
    "\377\377\377\377\377\377\377\0\0\0\377\0\0\0\377\0\0\0\377\377\377\377\377"
    "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377"
    "\377\377\0\0\0\377",
};
 
const ImageData64 Person_A = {
    64, 64,
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\341\255\377\377\2642\377\377\2758\377\377\2642\377\377\2747\377\377\277"
    "9\377\377\2642\377\377\320D\377\377\321E\377\377\321E\377\377\321E\377\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\2642\377"
    "\377\2642\377\350\242'\377\364\2551\377\337\232#\377\361\2521\377\345\237"
    "&\377\355\2500\377\332\227!\377\351\2450\377\330\225\40\377\351\2450\377"
    "\377\321E\377\377\321E\377\377\321E\377\377\321E\377\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\2642\377\377\2642\377\355\2500\377"
    "\352\2450\377\377\2642\377\377\302;\377\376\2631\377\364\2664\377\353\245"
    ")\377\375\2747\377\377\2747\377\377\306>\377\377\321E\377\377\321E\377\351"
    "\2450\377\332\230\"\377\352\2460\377\330\225\40\377\377\321E\377\377\321"
    "E\377\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\2642\377\343\235%\377\332\227!\377\377\2642\377"
    "\377\2642\377\364\254-\377\342\237'\377\332\230\"\377\337\235'\377\335\234"
    "$\377\337\237&\377\352\2471\377\377\320E\377\377\321E\377\377\321E\377\377"
    "\321E\377\377\317C\377\377\316C\377\363\2748\377\363\2708\377\332\227!\377"
    "\377\321E\377\377\321E\377\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\271\271\271\377\271\271\271\377\271\271\271\377\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\330\225\40\377\342\235%\377\377\2642\377\377\2642\377\377\2642\377"
    "\331\226!\377\340\236'\377\340\241'\377\375\315C\377\377\321E\377\377\320"
    "D\377\377\317C\377\366\301;\377\366\275;\377\353\2601\377\356\2564\377\342"
    "\243)\377\377\320D\377\377\321E\377\377\317C\377\377\316C\377\365\277:\377"
    "\375\312A\377\377\2674\377\330\225\40\377rss\377rss\377rss\377\230\231\230"
    "\377\271\271\271\377\271\271\271\377\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\265w\25\377\354\245)\377\331"
    "\226\40\377\377\2642\377\330\225\40\377\351\2450\377\331\227!\377\377\267"
    "4\377\377\317C\377\377\302<\377\377\313A\377\377\306>\377\377\305>\377\377"
    "\316C\377\377\314B\377\377\315B\377\377\315B\377\377\316C\377\374\307?\377"
    "\356\2654\377\353\2501\377\377\317C\377\377\311@\377\377\313A\377\357\261"
    "2\377\342\235%\377\330\225\40\377YYY\377rss\377\230\231\230\377\271\271\271"
    "\377\271\271\271\377\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\312\211\34\377\305\204\33\377\330\225\40\377"
    "\330\225\40\377\352\2460\377\377\2642\377\377\2642\377\377\2642\377\377\264"
    "2\377\377\321E\377\377\2642\377\377\2642\377\375\2621\377\376\2704\377\377"
    "\2716\377\377\301:\377\377\310>\377\377\315B\377\377\315B\377\377\315B\377"
    "\371\305=\377\351\2450\377\376\317D\377\360\254.\377\345\242(\377\320\216"
    "\35\377\264v\25\377===\377YYY\377YYY\377\230\231\230\377\271\271\271\377"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\264v\25"
    "\377\264v\25\377\325\223\37\377\264v\25\377\375\2631\377\377\2642\377\376"
    "\2632\377\377\2642\377\377\2642\377\377\2642\377\377\2642\377\377\2642\377"
    "\377\2642\377\377\315C\377\377\2642\377\377\2705\377\376\2642\377\376\266"
    "3\377\374\304<\377\374\310?\377\375\311?\377\370\301:\377\363\2716\377\342"
    "\236%\377\342\235%\377\273~\27\377\253p\22\377\350\2634\377\360\2675\377"
    "\334\232#\377===\377YYY\377\230\231\230\377\271\271\271\377\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\256r\23\377\300\200\30\377\264v\25"
    "\377\326\224\40\377\327\225\40\377\330\225\40\377\377\2642\377\377\2642\377"
    "\377\2642\377\377\2642\377\377\2642\377\377\2642\377\377\2642\377\377\264"
    "2\377\377\2642\377\377\2642\377\377\2642\377\377\2642\377\357\255.\377\355"
    "\254.\377\353\252,\377\357\257/\377\353\250+\377\333\230#\377\264w\25\377"
    "\320\230'\377\374\310?\377\377\315B\377\377\315B\377\377\316B\377\340\240"
    "'\377===\377YYY\377\230\231\230\377\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\254p\22\377\242i\17\377\253o\21\377\275}\27\377\302\202\31\377\325\222\37"
    "\377\355\246*\377\327\224\37\377\327\224\37\377\364\253-\377\325\222\37\377"
    "\324\222\37\377\324\221\36\377\350\241'\377\343\235%\377\346\240&\377\347"
    "\240'\377\344\236&\377\377\2674\377\345\241'\377\345\240&\377\335\231#\377"
    "\336\232#\377\314\213\35\377\272|\26\377\301\206\35\377\376\313A\377\377"
    "\314A\377\377\312@\377\377\314A\377\377\316C\377\377\300:\377\330\225\40"
    "\377YYY\377\230\231\230\377\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\242i\17"
    "\377\243j\17\377\242i\17\377\252o\22\377\261v\24\377\266y\26\377\312\211"
    "\33\377\271{\26\377\316\215\35\377\317\215\35\377\314\213\34\377\316\215"
    "\35\377\321\216\35\377\320\216\35\377\320\216\35\377\320\216\35\377\317\216"
    "\35\377\300\202\31\377\272}\27\377\265y\25\377\304\205\33\377\274~\30\377"
    "\253p\22\377\263v\25\377\327\237*\377\376\313A\377\377\314A\377\377\310?"
    "\377\377\307?\377\377\306>\377\377\312@\377\377\317C\377\330\225\40\377Y"
    "YY\377\230\231\230\377\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\264v\25\377\242i\17\377"
    "\242i\17\377\242i\17\377\242i\17\377\246k\20\377\252o\22\377\246l\20\377"
    "\245k\17\377\251o\22\377\250m\21\377\244k\20\377\246k\21\377\247m\20\377"
    "\252o\21\377\251o\21\377\247m\20\377\252p\22\377\244k\17\377\245l\21\377"
    "\260s\23\377\262u\24\377\312\220\"\377\363\2737\377\374\303<\377\375\312"
    "@\377\377\314A\377\377\305<\377\377\305=\377\377\2779\377\377\2653\377\351"
    "\251,\377\377\2726\377\330\225\40\377===\377YYY\377\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\264v\25\377"
    "\264v\25\377\264v\25\377\264v\25\377\264v\25\377\264v\25\377\264v\25\377"
    "\264v\25\377\264v\25\377\264v\25\377\264v\25\377\264v\25\377\264v\25\377"
    "\264v\25\377\264v\25\377\264v\25\377\264v\25\377\264v\25\377\264v\25\377"
    "\264v\25\377\266x\26\377\327\224\40\377\332\227!\377\363\2664\377\377\304"
    "<\377\377\302;\377\377\2779\377\377\2664\377\377\2715\377\376\2674\377\372"
    "\2600\377\343\236%\377\330\225\40\377\264v\25\377\330\225\40\377===\377="
    "==\377\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\264v\25\377\330\225\40\377\330\225\40\377\330\225\40\377\330\225\40\377"
    "\330\225\40\377\330\225\40\377\330\225\40\377\330\225\40\377\330\225\40\377"
    "\331\226!\377\330\225\40\377\330\225\40\377\333\227!\377\334\231\"\377\336"
    "\232#\377\343\236%\377\346\240'\377\354\245)\377\357\250+\377\365\254-\377"
    "\367\256.\377\377\2705\377\377\2705\377\374\2621\377\376\2631\377\377\264"
    "2\377\377\2642\377\377\2642\377\371\257/\377\345\237&\377\332\227!\377\264"
    "v\25\377\242i\17\377\242i\17\377\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\264v\25\377\376\2632\377\330\225\40\377\377\2642\377\376\2642\377\331\226"
    "!\377\377\2642\377\377\2642\377\375\2631\377\373\2611\377\375\2631\377\377"
    "\2642\377\377\2642\377\377\2642\377\377\2642\377\377\2642\377\376\2631\377"
    "\371\2600\377\365\254.\377\367\255/\377\367\256/\377\366\255/\377\366\255"
    "/\377\366\255/\377\366\255/\377\371\2570\377\371\2570\377\353\244*\377\330"
    "\225\40\377\330\225\40\377\264v\25\377\242i\17\377\242i\17\377\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\264v\25\377\331"
    "\226!\377\331\226!\377\326\223\37\377\351\242(\377\330\225\40\377\330\225"
    "\40\377\330\225\40\377\330\225\40\377\377\2642\377\330\225\40\377\330\225"
    "\40\377\376\2632\377\330\225\40\377\377\2642\377\330\225\40\377\377\2642"
    "\377\376\2631\377\331\226!\377\333\230\"\377\337\233$\377\361\251-\377\364"
    "\253/\377\360\250,\377\337\233#\377\335\231#\377\335\231#\377\334\230\"\377"
    "\264v\25\377\242i\17\377\242i\17\377\271tN\377\271tN\377\322\221m\377\335"
    "\237}\377\350\255\214\377\364\274\235\377\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\242i\17\377\265w\25"
    "\377\272|\27\377\266x\26\377\266x\26\377\277\177\30\377\277\200\31\377\276"
    "~\30\377\267y\26\377\267y\26\377\266x\26\377\267y\26\377\272{\27\377\274"
    "~\30\377\275~\30\377\276\177\30\377\302\202\32\377\305\205\32\377\313\212"
    "\34\377\306\206\33\377\334\230$\377\333\227#\377\302\202\32\377\264v\25\377"
    "\264v\25\377\330\225\40\377\264v\25\377\242i\17\377\242i\17\377\271tN\377"
    "\277{V\377\322\221m\377\322\221m\377\322\221m\377\352\257\217\377\362\271"
    "\232\377\364\274\235\377\364\274\235\377\364\274\235\377\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\242i\17\377\264v\25\377\264v\25\377"
    "\264v\25\377\264v\25\377\264v\25\377\264v\25\377\264v\25\377\264v\25\377"
    "\264v\25\377\264v\25\377\264v\25\377\264v\25\377\264v\25\377\264v\25\377"
    "\267x\26\377\272{\27\377\273|\30\377\270y\26\377\265v\25\377\264v\25\377"
    "\264v\25\377\242i\17\377\242i\17\377\242i\17\377\242i\17\377\242i\17\377"
    "\377\377\377\377\271tN\377\322\221m\377\322\221m\377\322\221m\377\362\271"
    "\232\377\364\274\235\377\355\307\262\377\355\307\262\377\355\307\262\377"
    "\364\274\235\377\364\274\235\377\322\221m\377\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\242i\17\377\242i\17\377\242i\17\377\242i\17"
    "\377\242i\17\377\242i\17\377\242i\17\377\242i\17\377\242i\17\377\242i\17"
    "\377\242i\17\377\242i\17\377\242i\17\377\242i\17\377\242i\17\377\242i\17"
    "\377\242i\17\377\242i\17\377\242i\17\377\242i\17\377\242i\17\377\271tN\377"
    "\271tN\377\271tN\377\271tN\377\377\377\377\377===\377\322\221m\377\322\221"
    "m\377\341\244\202\377\363\272\233\377\364\274\235\377\364\274\235\377\355"
    "\307\262\377\355\307\262\377\355\307\262\377\355\307\262\377\364\274\235"
    "\377\322\221m\377\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\322\221m\377\271tN\377\271tN\377"
    "\271tN\377\271tN\377\271tN\377\271tN\377\271tN\377\271tN\377\271tN\377\271"
    "tN\377\271tN\377\271tN\377\271tN\377\271tN\377\271tN\377\271tN\377\271tN"
    "\377\322\221m\377\322\221m\377\322\221m\377\271tN\377===\377===\377\322\221"
    "m\377\334\235{\377\364\274\235\377\364\274\235\377\364\274\235\377\360\302"
    "\251\377\355\307\262\377\355\307\262\377\355\307\262\377\355\307\262\377"
    "\364\274\235\377\322\221m\377\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\322\221m\377\322\221"
    "m\377\322\221m\377\322\221m\377\316\214h\377\271tN\377\322\221m\377\322\221"
    "m\377\322\221m\377\271tN\377\272uO\377\324\223o\377\322\221m\377\322\221"
    "m\377\322\221m\377\326\226s\377\333\235z\377\337\242\177\377\342\246\204"
    "\377\342\246\204\377\322\221m\377\271tN\377===\377===\377\322\221m\377\356"
    "\265\225\377\364\274\235\377\364\274\235\377\364\274\235\377\363\275\237"
    "\377\362\277\243\377\357\304\255\377\355\307\262\377\364\274\235\377\364"
    "\274\235\377\322\221m\377\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\322\221m\377\342\246\204"
    "\377\342\246\204\377\342\246\204\377\321\221n\377\271tN\377\322\221m\377"
    "\343\247\205\377\317\217l\377\342\246\204\377\300|W\377\342\246\204\377\346"
    "\253\212\377\342\246\204\377\342\247\205\377\342\246\204\377\350\255\214"
    "\377\342\246\204\377\364\274\235\377\364\274\235\377\364\274\235\377\322"
    "\221m\377\271tN\377===\377\322\221m\377\347\254\213\377\364\274\235\377\364"
    "\274\235\377\364\274\235\377\364\274\235\377\364\274\235\377\364\274\235"
    "\377\364\274\235\377\364\274\235\377\364\274\235\377\322\221m\377\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\322\221m\377\342\246\204\377\342\246\204\377\347\255\213"
    "\377\332\234z\377\271tN\377\322\221m\377\317\217k\377\351\256\216\377\364"
    "\274\235\377\355\263\223\377\364\274\235\377\362\271\232\377\357\266\226"
    "\377\355\264\224\377\354\263\222\377\360\267\230\377\364\274\235\377\364"
    "\274\235\377\364\274\235\377\364\274\235\377\364\274\235\377\322\221m\377"
    "\322\221m\377\342\245\204\377\347\254\213\377\364\274\235\377\364\274\235"
    "\377\355\307\262\377\364\274\235\377\364\274\235\377\364\274\235\377\364"
    "\274\235\377\364\274\235\377\364\274\235\377\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\322\221m\377\342\246\204\377\342\246\204\377\354\263\222\377\345"
    "\251\211\377\271tN\377\311\206b\377\344\250\207\377\360\303\252\377\364\274"
    "\235\377\364\274\235\377\364\274\235\377\364\274\235\377\364\274\235\377"
    "\364\274\235\377\364\274\235\377\364\274\235\377\364\274\235\377\364\274"
    "\235\377\364\274\235\377\364\274\235\377\364\274\235\377\354\263\222\377"
    "\347\254\213\377\335\237|\377\334\236{\377\357\265\225\377\364\274\235\377"
    "\364\274\235\377\364\274\235\377\364\274\235\377\364\274\235\377\364\274"
    "\235\377\342\246\204\377\322\221m\377\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\322\221m\377\342\246\204\377\342\246\204\377\354\262\222\377\353\261\221"
    "\377\303\200[\377\271tN\377\303\177Z\377\320\217k\377\357\304\254\377\357"
    "\304\255\377\356\305\257\377\322\222n\377\356\264\225\377\364\274\235\377"
    "\364\274\235\377\364\274\235\377\363\275\237\377\362\277\243\377\360\303"
    "\252\377\364\274\235\377\364\274\235\377\353\261\221\377\342\246\204\377"
    "\327\227t\377\325\225q\377\326\226s\377\353\261\221\377\356\264\224\377\351"
    "\256\215\377\342\245\204\377\342\246\204\377\342\246\204\377\322\221m\377"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\327\230"
    "u\377\342\246\204\377\351\255\215\377\364\274\235\377\323\224q\377\311\210"
    "d\377\271tN\377\271tN\377\317\215i\377\321\220l\377\310\206a\377\303\200"
    "[\377\307\205a\377\364\274\235\377\364\274\235\377\361\300\245\377\356\305"
    "\256\377\355\307\262\377\355\307\262\377\364\274\235\377\364\274\235\377"
    "\364\273\234\377\342\246\204\377\333\235{\377\315\213g\377\320\216j\377\323"
    "\222n\377\322\221m\377\323\222n\377\333\235z\377\322\221m\377\322\221m\377"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\322\221m\377\342\246\204\377\343\247\205\377\363\271\232\377\362\271"
    "\232\377\337\243\201\377\307\205`\377\303\200[\377\271tN\377\274xR\377\310"
    "\206a\377\331\233x\377\364\274\235\377\364\274\235\377\355\307\262\377\355"
    "\307\262\377\355\307\262\377\355\307\262\377\355\307\262\377\364\274\235"
    "\377\364\274\235\377\364\274\235\377\342\246\204\377\342\246\204\377\311"
    "\210c\377\300|W\377\276zT\377\276zU\377\300|W\377\304\201\\\377\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\324\224q\377\342\246\204\377\347\254"
    "\212\377\357\266\226\377\361\271\231\377\360\267\227\377\343\247\206\377"
    "\327\230u\377\362\272\233\377\364\274\235\377\364\274\235\377\364\274\235"
    "\377\364\274\235\377\364\274\235\377\355\307\262\377\364\274\235\377\364"
    "\274\235\377\364\274\235\377\364\274\235\377\364\274\235\377\364\274\235"
    "\377\351\256\215\377\342\246\204\377\336\240~\377\316\215i\377\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\322\221m\377\342\246\204\377\342\246\204\377\343\250"
    "\206\377\360\267\227\377\364\274\235\377\364\274\235\377\364\274\235\377"
    "\364\274\235\377\364\274\235\377\364\274\235\377\364\274\235\377\364\274"
    "\235\377\364\274\235\377\364\274\235\377\364\274\235\377\364\274\235\377"
    "\364\274\235\377\364\274\235\377\364\274\235\377\352\260\217\377\343\247"
    "\205\377\342\246\204\377\326\226s\377\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\324\223o\377\342\246\204\377\342\246\204\377\342"
    "\246\204\377\347\254\212\377\356\264\224\377\361\270\230\377\360\270\231"
    "\377\363\273\234\377\364\274\235\377\364\274\235\377\364\274\235\377\364"
    "\274\235\377\364\274\235\377\364\274\235\377\364\274\235\377\363\273\234"
    "\377\351\256\215\377\345\251\210\377\342\246\204\377\342\246\204\377\342"
    "\246\204\377\322\221m\377\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\324\223p\377\337\242\177\377\342\246\204\377\342"
    "\246\204\377\342\246\204\377\342\246\204\377\342\246\204\377\342\246\204"
    "\377\342\246\204\377\342\246\204\377\346\253\211\377\345\252\210\377\345"
    "\251\210\377\345\251\210\377\345\252\210\377\343\247\205\377\343\247\205"
    "\377\342\246\204\377\342\246\204\377\330\230u\377\322\221m\377\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\322\221n\377\331\233x\377\340\243\201\377"
    "\340\244\202\377\341\245\203\377\341\245\203\377\337\242\200\377\342\246"
    "\204\377\342\246\204\377\342\246\204\377\342\246\204\377\342\246\204\377"
    "\342\246\204\377\337\241\177\377\333\235z\377\330\231v\377\323\222o\377\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\271tN\377\277{V\377\303\201\\\377\276"
    "zT\377\276zU\377\326\226s\377\325\225q\377\326\226r\377\325\225r\377\322"
    "\222n\377\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\202\236-\377\202\236-\377\202\236-\377\271tN\377\271tN\377\271tN\377\322"
    "\221m\377\271tN\377\364\274\235\377\364\274\235\377_v\30\377\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\202\236-\377\202\236-\377\222"
    "\264,\377\202\236-\377\202\236-\377_v\30\377_v\30\377_v\30\377_v\30\377\322"
    "\221m\377\322\221m\377\255\322=\377_v\30\377\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\202\236-\377\255\322=\377\255\322=\377\255\322=\377\222\264,\377"
    "\222\264,\377\202\236-\377\202\236-\377\202\236-\377_v\30\377\24.F\377\35"
    "Be\377\255\322=\377\255\322=\377_v\30\377\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\202\236-\377\255\322"
    "=\377\255\322=\377\255\322=\377\255\322=\377\255\322=\377\202\236-\377\222"
    "\264,\377\202\236-\377\202\236-\377_v\30\377\24.F\377\35Be\377\202\236-\377"
    "\255\322=\377_v\30\377\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\202\236-\377\255\322=\377\255\322=\377\255\322=\377"
    "\255\322=\377\222\264,\377\255\322=\377\222\264,\377\222\264,\377\202\236"
    "-\377\202\236-\377\202\236-\377_v\30\377\24.F\377\35Be\377\255\322=\377_"
    "v\30\377\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\202\236-\377\255\322=\377\255\322=\377\255\322=\377\255\322=\377\255"
    "\322=\377\222\264,\377\202\236-\377\202\236-\377\202\236-\377\202\236-\377"
    "\202\236-\377_v\30\377_v\30\377\35Be\377\202\236-\377\222\264,\377_v\30\377"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\202\236-\377\255\322=\377\255"
    "\322=\377\255\322=\377\255\322=\377\222\264,\377\222\264,\377\202\236-\377"
    "\222\264,\377\202\236-\377\222\264,\377\202\236-\377\202\236-\377\202\236"
    "-\377_v\30\377\24.F\377\35Be\377\222\264,\377_v\30\377\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\202\236-\377\255\322=\377\255\322=\377\255\322=\377\222\264,\377"
    "\255\322=\377\222\264,\377\222\264,\377\222\264,\377\202\236-\377\202\236"
    "-\377\202\236-\377\202\236-\377_v\30\377\202\236-\377_v\30\377\24.F\377\35"
    "Be\377\202\236-\377_v\30\377\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\202\236-\377\255"
    "\322=\377\255\322=\377\255\322=\377\255\322=\377\222\264,\377\222\264,\377"
    "\202\236-\377\222\264,\377\202\236-\377\202\236-\377\202\236-\377\202\236"
    "-\377_v\30\377\202\236-\377_v\30\377\24.F\377\24.F\377\202\236-\3770=\11"
    "\377_v\30\377\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\202\236-\377\255\322=\377\255\322=\377\222\264"
    ",\377\255\322=\377\222\264,\377\222\264,\377\222\264,\377\202\236-\377\222"
    "\264,\377\202\236-\377\202\236-\377\202\236-\3770=\11\377_v\30\377_v\30\377"
    "\24.F\377\35Be\377\202\236-\3770=\11\377_v\30\377\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\202\236-\377"
    "\222\264,\377\222\264,\377\222\264,\377\222\264,\377\202\236-\377\202\236"
    "-\377\202\236-\377\222\264,\377\202\236-\377\202\236-\377\202\236-\377\202"
    "\236-\3770=\11\377_v\30\377_v\30\377\24.F\377\24.F\377\202\236-\3770=\11"
    "\377_v\30\377\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\202\236-\377\222\264,\377\222"
    "\264,\377\222\264,\377\222\264,\377\202\236-\377\222\264,\377\202\236-\377"
    "\202\236-\377\202\236-\377\202\236-\377\202\236-\3770=\11\377_v\30\377_v"
    "\30\377\24.F\377\35Be\377\202\236-\377\322\221m\377\322\221m\377\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\202\236-\377\202\236-\377\202\236-\377\202\236-\377"
    "\202\236-\377\202\236-\377\202\236-\377\202\236-\377\202\236-\377\202\236"
    "-\377\202\236-\377\202\236-\3770=\11\3770=\11\377_v\30\377\24.F\377\24.F"
    "\377\202\236-\377\364\274\235\377\342\246\204\377\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\271tN\377\271tN\377\271tN\377\271tN\377\271tN\377\271tN\377\271tN\377"
    "\271tN\377\271tN\377\271tN\377\271tN\377\271tN\377\326\226s\3770=\11\377"
    "0=\11\377\24.F\377\35Be\377_v\30\377\364\274\235\377\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\322\221m\377\322\221m\377\322\221m\377\322\221m\377"
    "\322\221m\377\322\221m\377\322\221m\377\322\221m\377\322\221m\377\364\274"
    "\235\377\364\274\235\377\342\246\204\377\322\221m\377\12\35/\377\12\35/\377"
    "\24.F\377\24.F\377\12\35/\377\342\246\204\377\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\322\221m\377\322\221m\377\326\226s\377\342\246\204\377\342"
    "\246\204\377\353\261\221\377\364\274\235\377\364\274\235\377\364\274\235"
    "\377\364\274\235\377\342\246\204\377\322\221m\377\322\221m\377\12\35/\377"
    "\12\35/\377\367\332\31\377\315\267#\377\12\35/\377\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\322\221m\377\322\221m\377"
    "\322\221m\377\271tN\377\353\261\221\377\353\261\221\377\364\274\235\377\364"
    "\274\235\377\355\307\262\377\342\246\204\377\271tN\377\322\221m\377\12\35"
    "/\377\12\35/\377\315\267#\377\266\241\21\377\12\35/\377\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\322\221"
    "m\377\322\221m\377\271tN\377\342\246\204\377\342\246\204\377\353\261\221"
    "\377\364\274\235\377\355\307\262\377\355\307\262\377\342\246\204\377\12\35"
    "/\377\12\35/\377\12\35/\377\12\35/\377\12\35/\377\12\35/\377\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\326\226s\377\322\221m\377\271tN\377\353\261\221\377\342\246"
    "\204\377\353\261\221\377\364\274\235\377\364\274\235\377\342\246\204\377"
    "\12\35/\377\12\35/\377\35Be\377\35Be\377\24.F\377\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\12\35/\377\322\221m\377\353\261"
    "\221\377\326\226s\377\326\226s\377\342\246\204\377\24.F\377\35Be\377\35B"
    "e\377\35Be\377\35Be\377\24.F\377\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\12\35/\377\12\35/\377\12\35/\377\24.F\377\35"
    "Be\377\24.F\377\35Be\377\24.F\377\35Be\377\24.F\377\24.F\377B*\16\377}Y0"
    "\377\265\207R\377\265\207R\377\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\24.F\377\35Be\377\24.F\377\35"
    "Be\377\24.F\377\24.F\377\35Be\377\35Be\377\24.F\377\24.F\377B*\16\377Y;\30"
    "\377}Y0\377\241r=\377\241r=\377\265\207R\377\265\207R\377\265\207R\377\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\24.F\377\35Be\377\24"
    ".F\377\35Be\377\35Be\377\35Be\377\24.F\377\24.F\377B*\16\377B*\16\377}Y0"
    "\377\241r=\377\241r=\377\241r=\377\241r=\377\241r=\377\241r=\377\265\207"
    "R\377\265\207R\377\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\24.F\377\24"
    ".F\377\24.F\377\35Be\377\24.F\377B*\16\377B*\16\377B*\16\377}Y0\377}Y0\377"
    "\241r=\377}Y0\377\241r=\377}Y0\377\241r=\377}Y0\377}Y0\377\241r=\377}Y0\377"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\24.F\377\24.F\377B*\16\377B*\16"
    "\377B*\16\377Y;\30\377Y;\30\377Y;\30\377iG\37\377Y;\30\377iG\37\377Y;\30"
    "\377iG\37\377Y;\30\377iG\37\377Y;\30\377iG\37\377iG\37\377iG\37\377iG\37"
    "\377\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0B*\16\377B*\16\377Y;\30\377iG\37\377iG"
    "\37\377}Y0\377iG\37\377iG\37\377iG\37\377iG\37\377iG\37\377}Y0\377}Y0\377"
    "iG\37\377}Y0\377}Y0\377iG\37\377}Y0\377}Y0\377iG\37\377\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0Y;\30\377Y;\30\377Y;\30\377Y;\30\377Y;\30\377Y;\30\377Y;\30\377"
    "Y;\30\377Y;\30\377Y;\30\377iG\37\377Y;\30\377Y;\30\377iG\37\377iG\37\377"
    "Y;\30\377Y;\30\377iG\37\377Y;\30\377Y;\30\377\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377"
    "\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377"
    "\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377"
    "\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0\377\377\377\0"
    "\377\377\377\0",
};
 
1

Share this post


Link to post
Share on other sites

Due to the size of the font resource, it requires breaking up into 2 or more posts, so instead, i added an attachment to this post that includes all current resources in a single file.

edit: adding a video shortly.

edit2: VIDEOS!

[media]http://youtu.be/_vdAU-shqkM[/media]

edit3: I decided i'd upload my main.cpp so you can just grab that for updating everything in one go. also, uploading files apparantly can't be in .c/.cpp formats for some reason, hence the .txt extension.

edit4: ok, lastly, if we have any sound artists that could create something, we could defiantly embed it into the game! =-)

That looks awesome!

 

I will finally get around to my promised update soon. I was thinking of adding text support as well; good thing I didn't yet! laugh.png

 

I can probably get some help adding some sounds or music this week though =]

1

Share this post


Link to post
Share on other sites

When I try to compile your update, I get this:

main.cpp: In function ‘void loop(sf::RenderWindow&, Background&, sf::Vector2f&, sf::Vector2f&, sf::Image&, sf::Sprite&, sf::Texture&, sf::Texture&, sf::Texture&, std::vector<Ghost, std::allocator<Ghost> >&, std::vector<People, std::allocator<People> >&, std::vector<Particle, std::allocator<Particle> >*, sf::Font&)’:
main.cpp:810: error: jump to label ‘LABELW’
main.cpp:751: error:   from here
main.cpp:770: error:   crosses initialization of ‘int BadIncrement’
main.cpp:769: error:   crosses initialization of ‘int GoodIncrement’
 

If I comment out the BadInc, GoodInc lines, it compiles fine. However when I run it crashes immediately with this:

ghost(81396,0x7fff763b3180) malloc: *** error for object 0x1057b7320: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Abort trap: 6

On osx 10.8, compiling with llvm gcc 4.2

 

For some reason the sf::Text constructors used were crashing on my system. Just declaring the vars as default and explicity setting the string and font works fine though. Strange lol. I uploaded the changed version just in case this caused a problem for anyone else.

Edited by FuzzyRhombus
0

Share this post


Link to post
Share on other sites

Not a real update, just changed the sf::Text declarations and commented out GoodIncrement and BadIncrement. This fixed it on my system, hope this helps if anyone else was having trouble too.


#include <SFML/System.hpp>
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include <vector>
#include <cmath>
#include <stdint.h>
#include <iostream>
#include <cstring>
#include <sstream>

typedef unsigned int uint; // laziness
typedef unsigned char uchar; // more

union RGBA
{
	struct Channel
	{
		uint8_t red;
		uint8_t green;
		uint8_t blue;
		uint8_t alpha;
	};

	uint32_t rgba;
	Channel channel;
};

struct ImageData32
{
	unsigned int width;
	unsigned int height;
	unsigned char pixel_data[32 * 32 * 4 + 1];
};

struct ImageData64{
	unsigned int width;
	unsigned int height;
	unsigned char pixel_data[64*64*4+1];
};

struct Ghost
{
	sf::Vector2f position;
	sf::Vector2f oldPosition;
	sf::Vector2f forces;
	float scaleRate;
	float radius;
	float invmass;
	int m_GoodAmnt;
	sf::Sprite sprite;
};

struct ShadowGhost
{
	sf::Sprite sprite;
	float fadeDuration;
	float maxVisibility;
	float fadeState;
};

struct People{
	sf::Vector2f position;
	float radius;
	sf::Sprite sprite;
	unsigned char m_Flag;
};

struct Background
{
	sf::Color baseColor;
	sf::Image buffer;
	sf::Texture texture;
	float pulseState;

	std::vector<ShadowGhost> shadowGhosts;
};

// Simple "self-sufficient" particles
struct Particle
{
	sf::Vector2f position, velocity;
	float friction;
	sf::Color color;
	uint lifetime;
};

extern const ImageData32 imageData;
extern const ImageData64 Person_A;
extern const unsigned char InconcolataFont[58464];

#define PLAYER_GHOST 0
#define GHOST_GOOD 1
#define CONVERSION_DISTANCE 80.0f
#define CONVERSION_LARGE_DISTANCE 50.0f
#define GOOD_MINIMUM 100
#define GOOD_MAXIMUM 255
#define BAD_CONVERSION_RATE 6
#define GOOD_CONVERSION_RATE 2
#define GHOST_RADIUS 16.0f
#define GHOST_GROW_RATE 0.2
#define GHOST_SPAWN_MIN_TICKS 30 //0.5 seconds at 60 fps
#define GHOST_SPAWN_MAX_TICKS 120 //2 seconds at 60 fps
#define GHOST_MAX_SCALE 1.8
#define GHOST_MINIMUM_FOR_GOOD_SCALE 5
#define GHOST_SCALE_RATE 0.01f
#define INITIAL_SCORE 3000
#define GOOD_GHOST_SCORE_VALUE 1
#define BAD_GHOST_SCORE_VALUE 1
#define GAME_FASTER_SPAWN_AFTER_TICKS (45*60) //every 45 seconds(60 ticks per second), ghosts begin spawning slightly faster.

#define STATE_MENU 0
#define STATE_PLAYING 1

#define PERSON_RADIUS 32.0f
#define PERSON_FACE_LEFT 1

static sf::Vector2u mousePosition;
static float ghostGravityWellAttraction = 0;
static std::vector<Particle> *gParticles;    // yay global reference

#define MASS 2 * 1e-2
#define GHOST_GRAVITY_WELL_DIEOFF_RATE (1.0f / 30.0f)

void addParticles(std::vector<Particle> *particles, const uint count, const sf::Vector2f &posMin, const sf::Vector2f &posMax, const sf::Vector2f &velMin, const sf::Vector2f &velMax, const float friction, const uint lifetime, const sf::Color colorMin, const sf::Color colorMax);

float randomFloat()
{
	return std::rand()/(float)RAND_MAX; //get out of here swiftcoder!
	return 4.0f;//std::rand() / static_cast<float>(RAND_MAX);
}

sf::Vector2f randomVector(sf::Vector2u bounds)
{
	return sf::Vector2f(randomFloat() * bounds.x, randomFloat() * bounds.y);
}

//return random vector between min/max....although since randomFloat returns 4, more like min+max*4....
sf::Vector2f randomVector(sf::Vector2f min, sf::Vector2f max){
	//sf::Vector2f Vec = min+(max-min);
	//return sf::Vector2f(Vec.x*randomFloat(), Vec.y*randomFloat());
	sf::Vector2f diff = max-min;
	return min + sf::Vector2f(diff.x*randomFloat(), diff.y*randomFloat());
}

//Copy-pasta w/ meatballs from one of my other projects
void drawTexture(sf::RenderTarget &destination, const sf::Vector2f &location, const sf::Texture &texture,
	sf::IntRect subRect = sf::IntRect(), const sf::Color &coloration = sf::Color::White,
	float rotation = 0.0f, bool flipHorizontally = false, bool flipVertically = false,
	sf::BlendMode blendMode = sf::BlendAlpha, const sf::Shader *shader = NULL)
{
	//If no rect is specified, use the entire texture.
	if(subRect.width == 0 || subRect.height == 0)
	{
		subRect.top = 0;
		subRect.left = 0;
		subRect.width = texture.getSize().x;
		subRect.height = texture.getSize().y;
	}

	//Set the position in space.
	sf::Transform translation;
	translation.translate(location);

	//Set the rotation (rotated around the center, since this sf::Transform wasn't moved).
	sf::Transform rotationTransform;
	rotationTransform.rotate(rotation);

	//Setup the render state.
	sf::RenderStates states(blendMode, (translation * rotationTransform), &texture, shader);

	//Setup the vertices and their attributes.
	sf::Vertex vertices[4];

	//The transparency:
	vertices[0].color = coloration;
	vertices[1].color = coloration;
	vertices[2].color = coloration;
	vertices[3].color = coloration;

	//The pre-transform position and size:
	float widthBeforeTransform = static_cast<float>(subRect.width);
	float heightBeforeTransform = static_cast<float>(subRect.height);
	vertices[0].position = sf::Vector2f(0, 0);
	vertices[1].position = sf::Vector2f(0, heightBeforeTransform);
	vertices[2].position = sf::Vector2f(widthBeforeTransform, heightBeforeTransform);
	vertices[3].position = sf::Vector2f(widthBeforeTransform, 0);

	//Calculate the texture coordinates:
	float left   = static_cast<float>(subRect.left);
	float right  = left + subRect.width;
	float top    = static_cast<float>(subRect.top);
	float bottom = top + subRect.height;

	//If we're mirroring, swap the texture coordinates vertically and/or horizontally.
	if(flipVertically)        std::swap(top, bottom);
	if(flipHorizontally)    std::swap(left, right);

	//Set the texture coordinates:
	vertices[0].texCoords = sf::Vector2f(left, top);
	vertices[1].texCoords = sf::Vector2f(left, bottom);
	vertices[2].texCoords = sf::Vector2f(right, bottom);
	vertices[3].texCoords = sf::Vector2f(right, top);

	//Use the sf::RenderTarget to draw the vertices using the sf::RenderStates we set up.
	destination.draw(vertices, 4, sf::Quads, states);
}


//returns good ghost counter.
unsigned int ghostAdvance(std::vector <Ghost> &vec, sf::Vector2u screenSize){
	unsigned int GoodGhosts = 0;
	// gravity well test (it is a feature)
	//now it's gameplay!
	for (size_t i = 0; i < vec.size(); ++i)
	{
		goto LABELE;
		if (i == PLAYER_GHOST) continue; // if you remove this a ghost will die
LABELE:
		if(vec[i].m_GoodAmnt<GOOD_MINIMUM) continue;
		Ghost *p = &(vec[i]);

		sf::Vector2f r = p->position - sf::Vector2f(mousePosition.x, mousePosition.y);
		r.x = r.x / screenSize.x;
		r.y = r.y / screenSize.y;

		double len2 = pow(r.x, 2) + pow(r.y, 2);
		r = sf::Vector2f(r.x / sqrt(len2), r.y / sqrt(len2));

		const float MIN = 0.02;
		if (len2 < MIN) len2 = MIN;

		double ax = r.x * (+1) * MASS / len2; // physics
		double ay = r.y * (+1) * MASS / len2;

		p->forces = sf::Vector2f(ax, ay) * ghostGravityWellAttraction;
		GoodGhosts++;
	}

	for(size_t i=0;i<vec.size();i++){
		Ghost *p = &(vec[i]);
		//Verlet integration
		sf::Vector2f oldPos = p->position;
		p->position += p->position - (p->oldPosition + (p->forces * 0.5f));
		p->oldPosition = oldPos;

		//Wall collision detection
		double overY = 0;
		if(p->position.y > screenSize.y-p->radius)
			overY = (screenSize.y-p->radius) - p->position.y;
		if(p->position.y < p->radius)
			overY = (p->radius) - p->position.y;
		if(p->position.x < p->radius){
			p->oldPosition.x = p->position.x;
			p->position.x = p->radius;
		}
		if(p->position.x > screenSize.x-p->radius){
			p->oldPosition.x = p->position.x;
			p->position.x = screenSize.x-p->radius;
		}

		//Friction with floor
		if(overY != 0){
			p->oldPosition.y = p->position.y;
			p->position.y += overY;
			double xVel = p->position.x - p->oldPosition.x;
			if(xVel != 0)
				p->position.x -= (xVel * 0.1);
		}
	}
	//Ghost-Ghost collision detection
	for(size_t i=0;i<vec.size();i++){
		//fixed j to i+1
		for(size_t j=i+1;j<vec.size();j++){
			Ghost *pi = &(vec[i]);
			Ghost *pj = &(vec[j]);

			float dx = pj->position.x-pi->position.x;
			float dy = pj->position.y-pi->position.y;
			float a = dx*dx+dy*dy;
			float l = (pi->radius + pj->radius);
			//do conversion if within distance.
			if(a<=CONVERSION_DISTANCE*CONVERSION_DISTANCE){
				int BadRate = GoodGhosts>3?BAD_CONVERSION_RATE:0;
				if((vec[i].m_GoodAmnt>=GOOD_MINIMUM && vec[j].m_GoodAmnt<GOOD_MINIMUM)){ //i is good, j is bad
					vec[i].m_GoodAmnt -= BadRate * vec[j].sprite.getScale().x;
					vec[j].m_GoodAmnt += GOOD_CONVERSION_RATE * vec[i].sprite.getScale().x;
				}else if(vec[i].m_GoodAmnt<GOOD_MINIMUM && vec[j].m_GoodAmnt>=GOOD_MINIMUM){
					vec[i].m_GoodAmnt += GOOD_CONVERSION_RATE * vec[j].sprite.getScale().x;
					vec[j].m_GoodAmnt -= BadRate * vec[i].sprite.getScale().x;
				}else if(vec[i].m_GoodAmnt<GOOD_MINIMUM){ //both i and j are bad.
					vec[i].m_GoodAmnt -= BAD_CONVERSION_RATE * vec[j].sprite.getScale().x;
					vec[j].m_GoodAmnt -= BAD_CONVERSION_RATE * vec[i].sprite.getScale().x;
				}else{ //both are good.
					vec[i].m_GoodAmnt += GOOD_CONVERSION_RATE * vec[j].sprite.getScale().x;
					vec[j].m_GoodAmnt += GOOD_CONVERSION_RATE * vec[i].sprite.getScale().x;
				}
				vec[i].m_GoodAmnt = vec[i].m_GoodAmnt<0?0:vec[i].m_GoodAmnt>GOOD_MAXIMUM?GOOD_MAXIMUM:vec[i].m_GoodAmnt;
				vec[j].m_GoodAmnt = vec[j].m_GoodAmnt<0?0:vec[j].m_GoodAmnt>GOOD_MAXIMUM?GOOD_MAXIMUM:vec[j].m_GoodAmnt;
			}
			if(a <= l*l ){
				bool massfix=false;
				if(pi->invmass == 0 && pj->invmass == 0){
					massfix = true;
					pi->invmass = pj->invmass = 1;
				}
				if(a==0) continue;
				float dist = sqrt(a);
				float difference = (dist - l) / (dist*(pi->invmass+pj->invmass));

				pi->position.x += pi->invmass * dx * difference * 0.5;
				pi->position.y += pi->invmass * dy * difference * 0.5;
				pj->position.x -= pj->invmass * dx * difference * 0.5;
				pj->position.y -= pj->invmass * dy * difference * 0.5;

				if(massfix){
					pi->invmass = pj->invmass = 0;
				}
				goto LABELF;
				if(i==PLAYER_GHOST){
					//ghost hit player!
					vec.erase(vec.begin()+j--);
					continue;
				}
LABELF:;

				sf::Vector2f ppos = pi->position + sf::Vector2f(dx*difference*0.5f, dy*difference*0.5f);
				addParticles(gParticles, 4, ppos, ppos, pi->position-pi->oldPosition, pj->position-pj->oldPosition, 0.998f, 60, pi->sprite.getColor(), pj->sprite.getColor());
			}
		}

		// convert to bigger "good" ghost
		for(size_t i=0;i<vec.size();i++){
			if(vec[i].scaleRate>0.001f){
				float s = vec[i].scaleRate>GHOST_SCALE_RATE?GHOST_SCALE_RATE:vec[i].scaleRate;
				vec[i].sprite.setScale(vec[i].sprite.getScale()+sf::Vector2f(s,s));
				vec[i].scaleRate-=s;
				vec[i].radius = GHOST_RADIUS*vec[i].sprite.getScale().x;
			}else if(vec[i].scaleRate<-0.001f){
				float s = vec[i].scaleRate<-GHOST_SCALE_RATE?-GHOST_SCALE_RATE:vec[i].scaleRate;
				vec[i].sprite.setScale(vec[i].sprite.getScale()+sf::Vector2f(s,s));
				vec[i].scaleRate-=s;
				vec[i].radius = GHOST_RADIUS*vec[i].sprite.getScale().x;
				if(vec[i].scaleRate>=-0.001f){ //it is now a dead ghost.
					vec.erase(vec.begin()+i--);
				}
			}else{
				for(size_t j=i+1;j<vec.size();j++){
					//fixed double testing i/j
					//now bad ghosts can get bigger as well!
					if(vec[j].scaleRate>=0.0001f || vec[j].scaleRate<=-0.0001f) continue; //only scale up when not scaling itself.
					if ((vec[i].m_GoodAmnt == GOOD_MAXIMUM && vec[j].m_GoodAmnt == GOOD_MAXIMUM && GoodGhosts > GHOST_MINIMUM_FOR_GOOD_SCALE) || (vec[i].m_GoodAmnt==0 && vec[j].m_GoodAmnt==0))
					{
						if (vec[i].sprite.getScale().x >= GHOST_MAX_SCALE) break;

						float distanceBetweenX = vec[i].position.x - vec[j].position.x;
						float distanceBetweenY = vec[i].position.y - vec[j].position.y;

						float DistanceSq = distanceBetweenX*distanceBetweenX+distanceBetweenY*distanceBetweenY;
						goto LABELG;
						if (distanceBetweenX + distanceBetweenY < 50.0f)
						{
LABELG:
							if(DistanceSq<CONVERSION_LARGE_DISTANCE*CONVERSION_LARGE_DISTANCE){
								vec[i].scaleRate = (vec[j].sprite.getScale().x-1.0f)+GHOST_GROW_RATE;
								vec[j].scaleRate = -vec[j].sprite.getScale().x;
								goto LABELH;
								vec[i].sprite.setScale(vec[i].sprite.getScale().x + (vec[j].sprite.getScale().x - 1.0f) + 0.5f, vec[i].sprite.getScale().y + (vec[j].sprite.getScale().y - 1.0f) + 0.5f);
								vec[i].radius += 0.5f;
								vec[j] = vec[vec.size() - 1];
								vec.pop_back();
								GoodGhosts--;
LABELH:
								break;
							}
						}
					}
				}
			}
		}

	}
	return GoodGhosts;
}

int ghostAdd(std::vector <Ghost> &vec, sf::Vector2f position, sf::Vector2f velocity, sf::Texture &textureBall, int GoodAmnt){
	Ghost gh;
	gh.position = position;
	gh.oldPosition = position-velocity;
	gh.forces = sf::Vector2f(0, -0.001);
	gh.invmass = 1;
	gh.radius = GHOST_RADIUS;
	gh.scaleRate = 0.0f;
	gh.m_GoodAmnt = GoodAmnt;
	gh.sprite.setTexture(textureBall);
	gh.sprite.setColor(sf::Color((int)position.x%256,(int)position.y%256,rand()%256,200));

	// add some particles
	addParticles(gParticles, 10, position, position, sf::Vector2f(-2.0f, -2.0f), sf::Vector2f(2.0f, 2.0f), 0.998f, 100, gh.sprite.getColor(), sf::Color::White);


	vec.push_back(gh);
	return vec.size()-1; //return index of ghost.
}

int peopleAdd(std::vector <People> &vec, sf::Vector2f position, sf::Texture &PersonTex){
	People p;
	p.position = position;
	p.sprite.setTexture(PersonTex);
	p.radius = PERSON_RADIUS;
	p.m_Flag = rand()%100<50?PERSON_FACE_LEFT:0;
	p.sprite.setColor(sf::Color(255,255,255,100));
	vec.push_back(p);
	return vec.size()-1; //return index of person.
}

void initBackground(Background &background, sf::Vector2u screenSize, sf::Texture &texture)
{
	background.baseColor = sf::Color(180, 200, 215); // 85, 128, 160); //
	background.pulseState = 0.0f;

	background.buffer.create(screenSize.x, screenSize.y, background.baseColor);
	background.texture.create(screenSize.x, screenSize.y);

	int numShadowGhosts = 7;

	for(int i = 0; i < numShadowGhosts; ++i)
	{
		ShadowGhost shadowGhost;
		shadowGhost.fadeDuration = (randomFloat() * 25.0f) + 10.0f;
		shadowGhost.maxVisibility = (randomFloat() * 0.35f) + 0.1f;
		shadowGhost.fadeState = (randomFloat() * shadowGhost.fadeDuration);
		shadowGhost.sprite.setTexture(texture);
		shadowGhost.sprite.setPosition(randomVector(screenSize));

		background.shadowGhosts.push_back(shadowGhost);
	}
}

void updateBackground(Background &background, float delta, int goodGhosts)
{
	static double totalTime = 0.0f;
	totalTime += delta;

	sf::Color bgColor = background.baseColor;

	float durationOfPulse = 10.0f;
	float halfDuration = (durationOfPulse * 0.5f);

	float state = fmod(totalTime, (double)durationOfPulse);

	if(state > halfDuration) background.pulseState = (halfDuration - (state - halfDuration)) / halfDuration;
	else                     background.pulseState = (state / halfDuration);

	if(goodGhosts > 2) goodGhosts -= 2;

	float redVariance = 20.0f + (7.0f * std::min(goodGhosts, 5));
	float variance = 30.0f;

	//Darken the room slowly and back.
	bgColor.r -= uint8_t(std::min(float(bgColor.r), redVariance) * background.pulseState);
	bgColor.g -= uint8_t(std::min(float(bgColor.g), variance) * background.pulseState);
	bgColor.b -= uint8_t(std::min(float(bgColor.b), variance) * background.pulseState);

	for(int y = 0; y < background.buffer.getSize().y; ++y)
	{
		for(int x = 0; x < background.buffer.getSize().x; ++x)
		{
			background.buffer.setPixel(x, y, bgColor);
		}
	}

	background.texture.update(background.buffer);
}

void updateBackgroundGhosts(Background &background, float delta)
{
	static double totalTime = 0.0f;
	totalTime += delta;

	sf::Vector2f movementAmount(100.0f * delta, 100.0f * delta);

	for(size_t i = 0; i < background.shadowGhosts.size(); ++i)
	{
		ShadowGhost &shadowGhost = background.shadowGhosts[i];

		float state = fmod(totalTime, (double)shadowGhost.fadeDuration);
		float halfDuration = (shadowGhost.fadeDuration * 0.5f);

		if(state > halfDuration) shadowGhost.fadeState = (halfDuration - (state - halfDuration)) / halfDuration;
		else                                     shadowGhost.fadeState = (state / halfDuration);


		//shadowGhost.sprite.move(movementAmount);
		shadowGhost.sprite.setScale(0.5f + shadowGhost.fadeState, 0.5f + shadowGhost.fadeState);

		//Wave
		sf::Vector2f newPos(0,0);
		float randomNumber =  randomFloat()*30 + 10;

		newPos.y = -sin(totalTime * 3) * delta * randomNumber;
		newPos.x =  sin(totalTime * 3) * delta * randomNumber;

		shadowGhost.sprite.move(newPos+movementAmount);

		//If out of bounds (towards the lower-right of the screen)...
		if(shadowGhost.sprite.getPosition().x > (background.buffer.getSize().x + 100.0f)
			|| shadowGhost.sprite.getPosition().y > (background.buffer.getSize().y + 100.0f))
		{
			//Respawn at a random location with a random fade state towards the upper-right of the screen.
			shadowGhost.fadeState = (randomFloat() * 1.0f);
			shadowGhost.sprite.setPosition(randomFloat() * float(background.buffer.getSize().x) - 200.0f,
				randomFloat() * float(background.buffer.getSize().y) - 200.0f);
		}
	}
}

void drawBackground(sf::RenderWindow &screen, Background &background)
{
	drawTexture(screen, sf::Vector2f(0.0f, 0.0f), background.texture);
}

void drawBackgroundGhosts(sf::RenderWindow &screen, Background &background)
{
	for(size_t i = 0; i < background.shadowGhosts.size(); ++i)
	{
		ShadowGhost &shadowGhost = background.shadowGhosts[i];
		shadowGhost.sprite.setColor(sf::Color(0, int(32.0f + (64.0f * shadowGhost.maxVisibility)),
			int(96.0f + (64.0f * shadowGhost.maxVisibility)), int(shadowGhost.fadeState * shadowGhost.maxVisibility * 255.0f)));
		screen.draw(shadowGhost.sprite);
	}
}

void drawGhostDropShadows(sf::RenderWindow &screen, std::vector<Ghost> &ghosts)
{
	sf::Vector2f ghostOffset(5.0f, 7.0f);//5.0f,5.0f);

	for(size_t i = 0; i < ghosts.size(); ++i)
	{
		double rad = ghosts[i].radius;
		ghosts[i].sprite.setPosition(ghosts[i].position - sf::Vector2f(rad, rad) + ghostOffset);
		ghosts[i].sprite.setColor(sf::Color(85, 128, 160, ghosts[i].m_GoodAmnt * 4 % 256));
		screen.draw(ghosts[i].sprite);
	}
}

void updateParticles(std::vector<Particle> *particles) {

	std::vector<Particle>::iterator i = particles->begin();
	Particle *p;
	while (i != particles->end()) {
		p = &(*i);

		if (p->lifetime == 0) {
			i = particles->erase(i);
			continue;
		}

		// euler, no acceleration for now
		p->position += p->velocity;
		p->velocity *= p->friction;

		p->lifetime--;

		++i;
	}

}

void drawParticles(sf::RenderWindow *screen, std::vector<Particle> &particles, const sf::Texture &texture) {
	for (size_t i=0;i<particles.size();++i) {
		// this could be faster
		drawTexture(*screen, particles[i].position, texture, sf::IntRect(), particles[i].color);
	}
}

void addParticles(std::vector<Particle> *particles, const uint count, const sf::Vector2f &posMin, const sf::Vector2f &posMax, const sf::Vector2f &velMin, const sf::Vector2f &velMax, const float friction, const uint lifetime, const sf::Color colorMin, const sf::Color colorMax) {
	sf::Vector2f pdiff = posMax - posMin;
	sf::Vector2f vdiff = velMax - velMin;

	for (int i=0;i<count;++i) {
		Particle p;
		p.position = randomVector(posMin, posMax);
		p.velocity = randomVector(velMin, velMax);
		p.friction = friction;

		// life time is in ticks
		p.lifetime = lifetime;

		float r = randomFloat();
		p.color = colorMin;
		p.color.r += r*(colorMax.r - colorMin.r);
		p.color.g += r*(colorMax.g - colorMin.g);
		p.color.b += r*(colorMax.b - colorMin.b);
		p.color.a += r*(colorMax.a - colorMin.a);

		particles->push_back(p);
	}
}

// forward declaration
void loop(sf::RenderWindow &screen, Background &background, sf::Vector2f &position, sf::Vector2f &Velocity, sf::Image &image, sf::Sprite &sprite,
	sf::Texture &texture, sf::Texture &People_ATex, sf::Texture &particleTex, std::vector<Ghost> &ghosts, std::vector<People> &people, std::vector<Particle> *particles, sf::Font &GameFont);

int main()
{
	std::srand(static_cast<unsigned>(std::time(0)));
	sf::RenderWindow screen(sf::VideoMode(800, 600, 32), "Ghost Horror Code");
	screen.setFramerateLimit(60);

	//Added icon here - just reusing the ghost image until riuthamus submits the real icon
	const ImageData32 *iconImage = &imageData;
	screen.setIcon(iconImage->width, iconImage->height, iconImage->pixel_data);

	sf::Image image, imageBall;
	image.create(imageData.width, imageData.height, imageData.pixel_data);
	image.createMaskFromColor(sf::Color::Black, 0);

	sf::Image PersonImage;
	PersonImage.create(Person_A.width, Person_A.height, Person_A.pixel_data);
	PersonImage.createMaskFromColor(sf::Color::Black, 0);

	sf::Texture texture;
	sf::Texture PersonTex;
	sf::Texture particleTex;

	texture.loadFromImage(image);
	texture.setSmooth(true);
	PersonTex.loadFromImage(PersonImage);
	PersonTex.setSmooth(true);

	sf::Sprite sprite;
	sf::Vector2f position = randomVector(screen.getSize() - image.getSize());
	sf::Vector2f Velocity = randomVector(sf::Vector2f(-1.0f, -1.0f), sf::Vector2f(1.0f, 1.0f));
	
	//Add out game font!
	sf::Font m_GameFont;
	m_GameFont.loadFromMemory(InconcolataFont, sizeof(InconcolataFont));

	Background background;
	initBackground(background, screen.getSize(), texture);

	uchar pdata[64];
	memset(pdata, 255, 64); // not quite what I expected, but it's good for now lol
	sf::Image pimage;
	pimage.create(8, 8, pdata);
	particleTex.loadFromImage(pimage);

	goto LABELA;
	sprite.setTexture(texture);
	sprite.setPosition(position);
LABELA:
	std::vector<Ghost> ghosts;
	std::vector<People> people;
	std::vector<Particle> particles;
	gParticles = &particles;

	goto LABELK;
	//spawn initial 3 ghosts.
	for(int i=0;i<3;i++) ghostAdd(ghosts, sf::Vector2f(screen.getSize().x*0.5f-20.0f+i*20.0f, screen.getSize().y*0.5f), sf::Vector2f(0.0f, 0.0f), texture, GOOD_MAXIMUM);
	//spawn a dude!
	peopleAdd(people, randomVector(sf::Vector2f(0.0f, 0.0f), (sf::Vector2f)(screen.getSize())), PersonTex);
	LABELK:
	loop(screen, background, position, Velocity, image, sprite, texture, PersonTex, particleTex, ghosts, people, &particles, m_GameFont);
}

void loop(sf::RenderWindow &screen, Background &background, sf::Vector2f &position, sf::Vector2f &Velocity, sf::Image &image, sf::Sprite &sprite,
	sf::Texture &texture, sf::Texture &Person_ATex, sf::Texture &particleTex, std::vector<Ghost> &ghosts, std::vector<People> &people, std::vector<Particle> *particles, sf::Font &GameFont) {

		//don't want to thrash the stack with the tail recursion
		static sf::Clock clock;
		static unsigned int SpawnTick = GHOST_SPAWN_MIN_TICKS+rand()%(GHOST_SPAWN_MAX_TICKS-GHOST_SPAWN_MIN_TICKS);
		static int HighScore = 0;
		static int ActiveScore = 0;
		static int LastHighScore = 0;
		static int GameTicks = 0;
		static int GameState = STATE_MENU;
		bool running = true;
		mousePosition = sf::Vector2u(screen.getSize().x/2, screen.getSize().y/2);

		//Game Text
        static sf::Text ScoreText, PlayText;
        ScoreText.setFont(GameFont);
        PlayText.setFont(GameFont);
        PlayText.setString("Play");
        //static sf::Text ScoreText("", GameFont);
		//static sf::Text PlayText("Play", GameFont);
		//Position PlayText
		sf::Rect<float> PlayBounds = PlayText.getLocalBounds();
		PlayText.setPosition(screen.getSize().x*0.5f-PlayBounds.width*0.5f, screen.getSize().y*0.5f-PlayBounds.height*0.5f);
		static std::ostringstream ScoreString;
		ScoreText.setString(ScoreString.str());
		while(running){
			float deltaTime = clock.getElapsedTime().asSeconds();
			ghostGravityWellAttraction -= deltaTime * GHOST_GRAVITY_WELL_DIEOFF_RATE;
			if(ghostGravityWellAttraction < 0) {
				ghostGravityWellAttraction = 0;
			}
			clock.restart();

			sf::Event event;
			while (screen.pollEvent(event))
			{
				if (event.type == sf::Event::Closed)
				{
					running = false;
				}else
				if ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Escape))
				{
					running = false;
				}else
				if (event.type == sf::Event::MouseMoved)
				{
					mousePosition = sf::Vector2u(event.mouseMove.x, event.mouseMove.y);
					ghostGravityWellAttraction = 1;
				}else
				if(event.type == sf::Event::MouseButtonPressed){
					if(GameState==STATE_MENU && PlayText.getGlobalBounds().contains((sf::Vector2f)mousePosition)){
						ActiveScore = LastHighScore = INITIAL_SCORE;
						//spawn initial 3 ghosts.
						for(int i=0;i<3;i++) ghostAdd(ghosts, sf::Vector2f(screen.getSize().x*0.5f-20.0f+i*20.0f, screen.getSize().y*0.5f), sf::Vector2f(0.0f, 0.0f), texture, GOOD_MAXIMUM);
						//spawn a dude!
						peopleAdd(people, randomVector(sf::Vector2f(0.0f, 0.0f), (sf::Vector2f)(screen.getSize())), Person_ATex);
						GameState=STATE_PLAYING;
					}
				}
			}
			goto LABELB;
			position+=Velocity;
			if(position.x<0.0f){
				position.x = 0.0f;
				Velocity.x = -Velocity.x;
			}else if(position.x>=(float)(screen.getSize().x-image.getSize().x)){
				position.x = (float)(screen.getSize().x-image.getSize().x);
				Velocity.x = -Velocity.x;
			}
			if(position.y<0.0f){
				position.y = 0.0f;
				Velocity.y = -Velocity.y;
			}else if(position.y>=(float)(screen.getSize().y-image.getSize().y)){
				position.y = (float)(screen.getSize().y-image.getSize().y);
				Velocity.y = -Velocity.y;
			}
			sprite.setPosition(position);  //Good bye old crap.
LABELB:
			int goodGhosts = ghostAdvance(ghosts, screen.getSize());
			updateBackground(background, deltaTime, goodGhosts);
			updateBackgroundGhosts(background, deltaTime);
			updateParticles(particles);

			screen.clear();
			drawBackground(screen, background);
			drawBackgroundGhosts(screen, background);
			//Let's draw particles here!
			goto LABELW;
			LABELX:


			drawGhostDropShadows(screen, ghosts);


			goto LABELC;
			screen.draw(sprite);
LABELC:
			//draw people!
			for(size_t i=0;i<people.size();i++){
				float rad = people[i].radius;
				people[i].sprite.setPosition(people[i].position-sf::Vector2f(rad, rad));
				people[i].sprite.setScale((people[i].m_Flag&PERSON_FACE_LEFT)?-1.0f:1.0f, 1.0f);
				screen.draw(people[i].sprite);
			}

			//int GoodIncrement = 0;
			//int BadIncrement = 0;
			for(size_t i=0;i<ghosts.size();i++){
				double rad = ghosts[i].radius;
				ghosts[i].sprite.setPosition(ghosts[i].position-sf::Vector2f(rad, rad));
				ghosts[i].sprite.setColor(sf::Color(GOOD_MAXIMUM-ghosts[i].m_GoodAmnt, 0, ghosts[i].m_GoodAmnt, 25+ghosts[i].m_GoodAmnt * 4 % 231 ));
				screen.draw(ghosts[i].sprite);

				//Do score calculations!
				if(GameState==STATE_PLAYING) ActiveScore+=(ghosts[i].m_GoodAmnt>=GOOD_MINIMUM?GOOD_GHOST_SCORE_VALUE:-BAD_GHOST_SCORE_VALUE)*(ghosts[i].sprite.getScale().x+(ghosts[i].sprite.getScale().x-1.0f)*2.0f);
				else ghosts[i].scaleRate=-ghosts[i].sprite.getScale().x; //destroy all ghosts when in the menu
			}
			HighScore = ActiveScore>HighScore?ActiveScore:HighScore;
			LastHighScore = ActiveScore>LastHighScore?ActiveScore:LastHighScore;
			if(ActiveScore<=0) GameState=STATE_MENU;

			ScoreString.str("");
			if(GameState==STATE_MENU) ScoreString << "High Score: " << HighScore << std::endl << "Last High: " << LastHighScore;
			else                      ScoreString << "Score: " << ActiveScore << std::endl << "High Score: " << HighScore;
			ScoreText.setString(ScoreString.str());
			goto LABELG;
			if(rand()%50 == 0 || rand() % 60 >= 57) //decreased rate of spawning.
LABELG:
			if(GameState==STATE_MENU){
				if(PlayText.getGlobalBounds().contains((sf::Vector2f)mousePosition)) PlayText.setColor(sf::Color(255, 0, 0));
				else PlayText.setColor(sf::Color(255,255,255));
				screen.draw(PlayText);
				
			}else{
				if(SpawnTick==0){
					ghostAdd(ghosts, randomVector(sf::Vector2f(0.0f, 0.0f), (sf::Vector2f)screen.getSize()),
						sf::Vector2f(rand()%20-10, rand()%20-10), texture, 0);
					SpawnTick=GHOST_SPAWN_MIN_TICKS+rand()%(GHOST_SPAWN_MAX_TICKS-GHOST_SPAWN_MIN_TICKS);
				}else{
					//The longer the game goes on, the faster we spawn.
					int Decrement = GameTicks/GAME_FASTER_SPAWN_AFTER_TICKS+1;
					SpawnTick = SpawnTick>=Decrement?SpawnTick-Decrement:0;
				}
			}
			GameTicks++;
			goto LABELY;
			LABELW:
			drawParticles(&screen, *particles, particleTex);
			goto LABELX;
			LABELY:
			screen.draw(ScoreText);
			
			screen.display();
		}

		if (running) {
			loop(screen, background, position, Velocity, image, sprite, texture, particleTex, Person_ATex, ghosts, people, particles, GameFont);
		}
}

#error "Be sure to add resources here!"
1

Share this post


Link to post
Share on other sites
yea....forgot to remove the good/bad counters, used them when i was figuring out scoring. msvc apparantly is cool with everything i did, Thanks fuzzy for fixing it.
0

Share this post


Link to post
Share on other sites

yea....forgot to remove the good/bad counters, used them when i was figuring out scoring. msvc apparantly is cool with everything i did, Thanks fuzzy for fixing it.

All good :)

The sf::Text should be fine the way you had it, not sure why I had that problem; but now it works for everybody (I hope).

 

Anyway....

 

 

Finally got some more time to play around with this! Since no one else did anything yet, I just added my changes to this post.

I added a simple game over screen, and a little more conditions to satisfy for dieing, instead of just all of a sudden being back at the menu again lol.

Scoring and death could still use a little work. Seems too easy to me. And there's virtually no way to get a game over without a score of 0.

 

I improved on the particles, added a proper resource, aaaaand since it's ghost themed, added ghost trails! biggrin.png

I only added the effect for particles and background ghosts. Would probably be too much on everything.


#include <SFML/System.hpp>
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include <vector>
#include <cmath>
#include <stdint.h>
#include <iostream>
#include <cstring>
#include <sstream>

typedef unsigned int uint; // laziness
typedef unsigned char uchar; // more

union RGBA
{
	struct Channel
	{
		uint8_t red;
		uint8_t green;
		uint8_t blue;
		uint8_t alpha;
	};

	uint32_t rgba;
	Channel channel;
};

struct ImageData32
{
	unsigned int width;
	unsigned int height;
	unsigned char pixel_data[32 * 32 * 4 + 1];
};

struct ImageData64{
	unsigned int width;
	unsigned int height;
	unsigned char pixel_data[64*64*4+1];
};

struct Ghost
{
	sf::Vector2f position;
	sf::Vector2f oldPosition;
	sf::Vector2f forces;
	float scaleRate;
	float radius;
	float invmass;
	int m_GoodAmnt;
	sf::Sprite sprite;
};

struct ShadowGhost
{
	sf::Sprite sprite;
	float fadeDuration;
	float maxVisibility;
	float fadeState;
};

struct People{
	sf::Vector2f position;
	float radius;
	sf::Sprite sprite;
	unsigned char m_Flag;
};

struct Background
{
	sf::Color baseColor;
	sf::Image buffer;
	sf::Texture texture;
	float pulseState;

	std::vector<ShadowGhost> shadowGhosts;
};

// Simple "self-sufficient" particles
struct Particle
{
	sf::Vector2f position, velocity;
	float friction;
    float rotation, omega;
	sf::Color color;
    sf::Color endColor;
	uint lifetime;
    uint energy;
};

extern const uchar particleData[];
extern const ImageData32 imageData;
extern const ImageData64 Person_A;
extern const unsigned char InconcolataFont[58464];

#define PLAYER_GHOST 0
#define GHOST_GOOD 1
#define CONVERSION_DISTANCE 80.0f
#define CONVERSION_LARGE_DISTANCE 50.0f
#define GOOD_MINIMUM 100
#define GOOD_MAXIMUM 255
#define BAD_CONVERSION_RATE 6
#define GOOD_CONVERSION_RATE 2
#define GHOST_RADIUS 16.0f
#define GHOST_GROW_RATE 0.2
#define GHOST_SPAWN_MIN_TICKS 30 //0.5 seconds at 60 fps
#define GHOST_SPAWN_MAX_TICKS 120 //2 seconds at 60 fps
#define GHOST_MAX_SCALE 1.8
#define GHOST_MINIMUM_FOR_GOOD_SCALE 5
#define GHOST_SCALE_RATE 0.01f
#define INITIAL_SCORE 3000
#define GOOD_GHOST_SCORE_VALUE 1
#define BAD_GHOST_SCORE_VALUE 1
#define GAME_FASTER_SPAWN_AFTER_TICKS (45*60) //every 45 seconds(60 ticks per second), ghosts begin spawning slightly faster.

typedef enum {
    GameStateMenu = 0,
    GameStatePlaying,
    GameStateGameOver,
} GameState;

#define STATE_MENU GameStateMenu
#define STATE_PLAYING GameStatePlaying

#define PERSON_RADIUS 32.0f
#define PERSON_FACE_LEFT 1

#define GHOST_BUFFER_BLUR_X     16.0f
#define GHOST_BUFFER_BLUR_Y     16.0f
#define GHOST_BUFFER_FADE       240

#define PI                      3.1415926535897f

static sf::Vector2u mousePosition;
static float ghostGravityWellAttraction = 0;
static std::vector<Particle> *gParticles;    // yay global reference
static uint currentRenderTarget;

#define MASS 2 * 1e-2
#define GHOST_GRAVITY_WELL_DIEOFF_RATE (1.0f / 30.0f)

void addParticles(std::vector<Particle> *particles, const uint count, const sf::Vector2f &posMin, const sf::Vector2f &posMax, const sf::Vector2f &velMin, const sf::Vector2f &velMax, const float friction, const uint lifetime, const float energyScale, const sf::Color colorMin, const sf::Color colorMax, sf::Color *fadeColor=0);

float randomFloat()
{
	return std::rand()/(float)RAND_MAX; //get out of here swiftcoder!
	return 4.0f;//std::rand() / static_cast<float>(RAND_MAX);
}

inline float randomRange(const float min, const float max) {
    return min + (max-min)*randomFloat();
}

sf::Vector2f randomVector(sf::Vector2u bounds)
{
	return sf::Vector2f(randomFloat() * bounds.x, randomFloat() * bounds.y);
}

//return random vector between min/max....although since randomFloat returns 4, more like min+max*4....
sf::Vector2f randomVector(sf::Vector2f min, sf::Vector2f max){
	//sf::Vector2f Vec = min+(max-min);
	//return sf::Vector2f(Vec.x*randomFloat(), Vec.y*randomFloat());
	sf::Vector2f diff = max-min;
	return min + sf::Vector2f(diff.x*randomFloat(), diff.y*randomFloat());
}

sf::Color fadeColors(const sf::Color &start, const sf::Color &end, const float amount) {
    sf::Color color;
    color.r = start.r + amount*int(end.r - start.r);
    color.g = start.g + amount*int(end.g - start.g);
    color.b = start.b + amount*int(end.b - start.b);
    color.a = start.a + amount*int(end.a - start.a);
    return color;
}

//Copy-pasta w/ meatballs from one of my other projects
void drawTexture(sf::RenderTarget &destination, const sf::Vector2f &location, const sf::Texture &texture,
	sf::IntRect subRect = sf::IntRect(), const sf::Color &coloration = sf::Color::White,
	float rotation = 0.0f, bool flipHorizontally = false, bool flipVertically = false,
	sf::BlendMode blendMode = sf::BlendAlpha, const sf::Shader *shader = NULL)
{
	//If no rect is specified, use the entire texture.
	if(subRect.width == 0 || subRect.height == 0)
	{
		subRect.top = 0;
		subRect.left = 0;
		subRect.width = texture.getSize().x;
		subRect.height = texture.getSize().y;
	}

	//Set the position in space.
	sf::Transform translation;
	translation.translate(location);

	//Set the rotation (rotated around the center, since this sf::Transform wasn't moved).
	sf::Transform rotationTransform;
	rotationTransform.rotate(rotation);

	//Setup the render state.
	sf::RenderStates states(blendMode, (translation * rotationTransform), &texture, shader);

	//Setup the vertices and their attributes.
	sf::Vertex vertices[4];

	//The transparency:
	vertices[0].color = coloration;
	vertices[1].color = coloration;
	vertices[2].color = coloration;
	vertices[3].color = coloration;

	//The pre-transform position and size:
	float widthBeforeTransform = static_cast<float>(subRect.width);
	float heightBeforeTransform = static_cast<float>(subRect.height);
	vertices[0].position = sf::Vector2f(0, 0);
	vertices[1].position = sf::Vector2f(0, heightBeforeTransform);
	vertices[2].position = sf::Vector2f(widthBeforeTransform, heightBeforeTransform);
	vertices[3].position = sf::Vector2f(widthBeforeTransform, 0);

	//Calculate the texture coordinates:
	float left   = static_cast<float>(subRect.left);
	float right  = left + subRect.width;
	float top    = static_cast<float>(subRect.top);
	float bottom = top + subRect.height;

	//If we're mirroring, swap the texture coordinates vertically and/or horizontally.
	if(flipVertically)        std::swap(top, bottom);
	if(flipHorizontally)    std::swap(left, right);

	//Set the texture coordinates:
	vertices[0].texCoords = sf::Vector2f(left, top);
	vertices[1].texCoords = sf::Vector2f(left, bottom);
	vertices[2].texCoords = sf::Vector2f(right, bottom);
	vertices[3].texCoords = sf::Vector2f(right, top);

	//Use the sf::RenderTarget to draw the vertices using the sf::RenderStates we set up.
	destination.draw(vertices, 4, sf::Quads, states);
}


//returns good ghost counter.
unsigned int ghostAdvance(std::vector <Ghost> &vec, std::vector<Ghost *> &good, sf::Vector2u screenSize){
	unsigned int GoodGhosts = 0;
	// gravity well test (it is a feature)
	//now it's gameplay!
	for (size_t i = 0; i < vec.size(); ++i)
	{
		goto LABELE;
		if (i == PLAYER_GHOST) continue; // if you remove this a ghost will die
LABELE:
		if(vec[i].m_GoodAmnt<GOOD_MINIMUM) continue;
		Ghost *p = &(vec[i]);

		sf::Vector2f r = p->position - sf::Vector2f(mousePosition.x, mousePosition.y);
		r.x = r.x / screenSize.x;
		r.y = r.y / screenSize.y;

		double len2 = pow(r.x, 2) + pow(r.y, 2);
		r = sf::Vector2f(r.x / sqrt(len2), r.y / sqrt(len2));

		const float MIN = 0.02;
		if (len2 < MIN) len2 = MIN;

		double ax = r.x * (+1) * MASS / len2; // physics
		double ay = r.y * (+1) * MASS / len2;

		p->forces = sf::Vector2f(ax, ay) * ghostGravityWellAttraction;
		GoodGhosts++;
        good.push_back(p);
	}

	for(size_t i=0;i<vec.size();i++){
		Ghost *p = &(vec[i]);
		//Verlet integration
		sf::Vector2f oldPos = p->position;
		p->position += p->position - (p->oldPosition + (p->forces * 0.5f));
		p->oldPosition = oldPos;

		//Wall collision detection
		double overY = 0;
		if(p->position.y > screenSize.y-p->radius)
			overY = (screenSize.y-p->radius) - p->position.y;
		if(p->position.y < p->radius)
			overY = (p->radius) - p->position.y;
		if(p->position.x < p->radius){
			p->oldPosition.x = p->position.x;
			p->position.x = p->radius;
		}
		if(p->position.x > screenSize.x-p->radius){
			p->oldPosition.x = p->position.x;
			p->position.x = screenSize.x-p->radius;
		}

		//Friction with floor
		if(overY != 0){
			p->oldPosition.y = p->position.y;
			p->position.y += overY;
			double xVel = p->position.x - p->oldPosition.x;
			if(xVel != 0)
				p->position.x -= (xVel * 0.1);
		}
	}
	//Ghost-Ghost collision detection
	for(size_t i=0;i<vec.size();i++){
		//fixed j to i+1
		for(size_t j=i+1;j<vec.size();j++){
			Ghost *pi = &(vec[i]);
			Ghost *pj = &(vec[j]);

			float dx = pj->position.x-pi->position.x;
			float dy = pj->position.y-pi->position.y;
			float a = dx*dx+dy*dy;
			float l = (pi->radius + pj->radius);
			//do conversion if within distance.
			if(a<=CONVERSION_DISTANCE*CONVERSION_DISTANCE){
				int BadRate = GoodGhosts>3?BAD_CONVERSION_RATE:0;
				if((vec[i].m_GoodAmnt>=GOOD_MINIMUM && vec[j].m_GoodAmnt<GOOD_MINIMUM)){ //i is good, j is bad
					vec[i].m_GoodAmnt -= BadRate * vec[j].sprite.getScale().x;
					vec[j].m_GoodAmnt += GOOD_CONVERSION_RATE * vec[i].sprite.getScale().x;
				}else if(vec[i].m_GoodAmnt<GOOD_MINIMUM && vec[j].m_GoodAmnt>=GOOD_MINIMUM){
					vec[i].m_GoodAmnt += GOOD_CONVERSION_RATE * vec[j].sprite.getScale().x;
					vec[j].m_GoodAmnt -= BadRate * vec[i].sprite.getScale().x;
				}else if(vec[i].m_GoodAmnt<GOOD_MINIMUM){ //both i and j are bad.
					vec[i].m_GoodAmnt -= BAD_CONVERSION_RATE * vec[j].sprite.getScale().x;
					vec[j].m_GoodAmnt -= BAD_CONVERSION_RATE * vec[i].sprite.getScale().x;
				}else{ //both are good.
					vec[i].m_GoodAmnt += GOOD_CONVERSION_RATE * vec[j].sprite.getScale().x;
					vec[j].m_GoodAmnt += GOOD_CONVERSION_RATE * vec[i].sprite.getScale().x;
				}
				vec[i].m_GoodAmnt = vec[i].m_GoodAmnt<0?0:vec[i].m_GoodAmnt>GOOD_MAXIMUM?GOOD_MAXIMUM:vec[i].m_GoodAmnt;
				vec[j].m_GoodAmnt = vec[j].m_GoodAmnt<0?0:vec[j].m_GoodAmnt>GOOD_MAXIMUM?GOOD_MAXIMUM:vec[j].m_GoodAmnt;
			}
			if(a <= l*l ){
				bool massfix=false;
				if(pi->invmass == 0 && pj->invmass == 0){
					massfix = true;
					pi->invmass = pj->invmass = 1;
				}
				if(a==0) continue;
				float dist = sqrt(a);
				float difference = (dist - l) / (dist*(pi->invmass+pj->invmass));

				pi->position.x += pi->invmass * dx * difference * 0.5;
				pi->position.y += pi->invmass * dy * difference * 0.5;
				pj->position.x -= pj->invmass * dx * difference * 0.5;
				pj->position.y -= pj->invmass * dy * difference * 0.5;

				if(massfix){
					pi->invmass = pj->invmass = 0;
				}
				goto LABELF;
				if(i==PLAYER_GHOST){
					//ghost hit player!
					vec.erase(vec.begin()+j--);
					continue;
				}
LABELF:;

				sf::Vector2f ppos = pi->position + sf::Vector2f(dx*difference*0.5f, dy*difference*0.5f);
                sf::Color fadeColor(255, 200, 10, 0);
				addParticles(gParticles, 4, ppos, ppos, pi->position-pi->oldPosition, pj->position-pj->oldPosition, 0.998f, 60, 1.0f, pi->sprite.getColor(), pj->sprite.getColor(), &fadeColor);
			}
		}

		// convert to bigger "good" ghost
		for(size_t i=0;i<vec.size();i++){
			if(vec[i].scaleRate>0.001f){
				float s = vec[i].scaleRate>GHOST_SCALE_RATE?GHOST_SCALE_RATE:vec[i].scaleRate;
				vec[i].sprite.setScale(vec[i].sprite.getScale()+sf::Vector2f(s,s));
				vec[i].scaleRate-=s;
				vec[i].radius = GHOST_RADIUS*vec[i].sprite.getScale().x;
			}else if(vec[i].scaleRate<-0.001f){
				float s = vec[i].scaleRate<-GHOST_SCALE_RATE?-GHOST_SCALE_RATE:vec[i].scaleRate;
				vec[i].sprite.setScale(vec[i].sprite.getScale()+sf::Vector2f(s,s));
				vec[i].scaleRate-=s;
				vec[i].radius = GHOST_RADIUS*vec[i].sprite.getScale().x;
				if(vec[i].scaleRate>=-0.001f){ //it is now a dead ghost.
					vec.erase(vec.begin()+i--);
				}
			}else{
				for(size_t j=i+1;j<vec.size();j++){
					//fixed double testing i/j
					//now bad ghosts can get bigger as well!
					if(vec[j].scaleRate>=0.0001f || vec[j].scaleRate<=-0.0001f) continue; //only scale up when not scaling itself.
					if ((vec[i].m_GoodAmnt == GOOD_MAXIMUM && vec[j].m_GoodAmnt == GOOD_MAXIMUM && GoodGhosts > GHOST_MINIMUM_FOR_GOOD_SCALE) || (vec[i].m_GoodAmnt==0 && vec[j].m_GoodAmnt==0))
					{
						if (vec[i].sprite.getScale().x >= GHOST_MAX_SCALE) break;

						float distanceBetweenX = vec[i].position.x - vec[j].position.x;
						float distanceBetweenY = vec[i].position.y - vec[j].position.y;

						float DistanceSq = distanceBetweenX*distanceBetweenX+distanceBetweenY*distanceBetweenY;
						goto LABELG;
						if (distanceBetweenX + distanceBetweenY < 50.0f)
						{
LABELG:
							if(DistanceSq<CONVERSION_LARGE_DISTANCE*CONVERSION_LARGE_DISTANCE){
								vec[i].scaleRate = (vec[j].sprite.getScale().x-1.0f)+GHOST_GROW_RATE;
								vec[j].scaleRate = -vec[j].sprite.getScale().x;
								goto LABELH;
								vec[i].sprite.setScale(vec[i].sprite.getScale().x + (vec[j].sprite.getScale().x - 1.0f) + 0.5f, vec[i].sprite.getScale().y + (vec[j].sprite.getScale().y - 1.0f) + 0.5f);
								vec[i].radius += 0.5f;
								vec[j] = vec[vec.size() - 1];
								vec.pop_back();
								GoodGhosts--;
LABELH:
								break;
							}
						}
					}
				}
			}
		}

	}
	return GoodGhosts;
}

int ghostAdd(std::vector <Ghost> &vec, sf::Vector2f position, sf::Vector2f velocity, sf::Texture &textureBall, int GoodAmnt){
	Ghost gh;
	gh.position = position;
	gh.oldPosition = position-velocity;
	gh.forces = sf::Vector2f(0, -0.001);
	gh.invmass = 1;
	gh.radius = GHOST_RADIUS;
	gh.scaleRate = 0.0f;
	gh.m_GoodAmnt = GoodAmnt;
	gh.sprite.setTexture(textureBall);
	gh.sprite.setColor(sf::Color((int)position.x%256,(int)position.y%256,rand()%256,200));

	// add some particles
    sf::Color fadeColor = sf::Color::White;
    fadeColor.a = 0;
	addParticles(gParticles, 10, position, position, sf::Vector2f(-2.0f, -2.0f), sf::Vector2f(2.0f, 2.0f), 0.998f, 100, 1.0f, gh.sprite.getColor(), sf::Color::White, &fadeColor);


	vec.push_back(gh);
	return vec.size()-1; //return index of ghost.
}

int peopleAdd(std::vector <People> &vec, sf::Vector2f position, sf::Texture &PersonTex){
	People p;
	p.position = position;
	p.sprite.setTexture(PersonTex);
	p.radius = PERSON_RADIUS;
	p.m_Flag = rand()%100<50?PERSON_FACE_LEFT:0;
	p.sprite.setColor(sf::Color(255,255,255,100));
	vec.push_back(p);
	return vec.size()-1; //return index of person.
}

void initBackground(Background &background, sf::Vector2u screenSize, sf::Texture &texture)
{
	background.baseColor = sf::Color(180, 200, 215); // 85, 128, 160); //
	background.pulseState = 0.0f;

	background.buffer.create(screenSize.x, screenSize.y, background.baseColor);
	background.texture.create(screenSize.x, screenSize.y);

	int numShadowGhosts = 7;

	for(int i = 0; i < numShadowGhosts; ++i)
	{
		ShadowGhost shadowGhost;
		shadowGhost.fadeDuration = (randomFloat() * 25.0f) + 10.0f;
		shadowGhost.maxVisibility = (randomFloat() * 0.35f) + 0.1f;
		shadowGhost.fadeState = (randomFloat() * shadowGhost.fadeDuration);
		shadowGhost.sprite.setTexture(texture);
		shadowGhost.sprite.setPosition(randomVector(screenSize));

		background.shadowGhosts.push_back(shadowGhost);
	}
}

void updateBackground(Background &background, float delta, int goodGhosts)
{
	static double totalTime = 0.0f;
	totalTime += delta;

	sf::Color bgColor = background.baseColor;

	float durationOfPulse = 10.0f;
	float halfDuration = (durationOfPulse * 0.5f);

	float state = fmod(totalTime, (double)durationOfPulse);

	if(state > halfDuration) background.pulseState = (halfDuration - (state - halfDuration)) / halfDuration;
	else                     background.pulseState = (state / halfDuration);

	if(goodGhosts > 2) goodGhosts -= 2;

	float redVariance = 20.0f + (7.0f * std::min(goodGhosts, 5));
	float variance = 30.0f;

	//Darken the room slowly and back.
	bgColor.r -= uint8_t(std::min(float(bgColor.r), redVariance) * background.pulseState);
	bgColor.g -= uint8_t(std::min(float(bgColor.g), variance) * background.pulseState);
	bgColor.b -= uint8_t(std::min(float(bgColor.b), variance) * background.pulseState);

	for(int y = 0; y < background.buffer.getSize().y; ++y)
	{
		for(int x = 0; x < background.buffer.getSize().x; ++x)
		{
			background.buffer.setPixel(x, y, bgColor);
		}
	}

	background.texture.update(background.buffer);
}

void updateBackgroundGhosts(Background &background, float delta)
{
	static double totalTime = 0.0f;
	totalTime += delta;

	sf::Vector2f movementAmount(100.0f * delta, 100.0f * delta);

	for(size_t i = 0; i < background.shadowGhosts.size(); ++i)
	{
		ShadowGhost &shadowGhost = background.shadowGhosts[i];

		float state = fmod(totalTime, (double)shadowGhost.fadeDuration);
		float halfDuration = (shadowGhost.fadeDuration * 0.5f);

		if(state > halfDuration) shadowGhost.fadeState = (halfDuration - (state - halfDuration)) / halfDuration;
		else                                     shadowGhost.fadeState = (state / halfDuration);


		//shadowGhost.sprite.move(movementAmount);
		shadowGhost.sprite.setScale(0.5f + shadowGhost.fadeState, 0.5f + shadowGhost.fadeState);

		//Wave
		sf::Vector2f newPos(0,0);
		float randomNumber =  randomFloat()*30 + 10;

		newPos.y = -sin(totalTime * 3) * delta * randomNumber;
		newPos.x =  sin(totalTime * 3) * delta * randomNumber;

		shadowGhost.sprite.move(newPos+movementAmount);

		//If out of bounds (towards the lower-right of the screen)...
		if(shadowGhost.sprite.getPosition().x > (background.buffer.getSize().x + 100.0f)
			|| shadowGhost.sprite.getPosition().y > (background.buffer.getSize().y + 100.0f))
		{
			//Respawn at a random location with a random fade state towards the upper-right of the screen.
			shadowGhost.fadeState = (randomFloat() * 1.0f);
			shadowGhost.sprite.setPosition(randomFloat() * float(background.buffer.getSize().x) - 200.0f,
				randomFloat() * float(background.buffer.getSize().y) - 200.0f);
		}
	}
}

void drawBackground(sf::RenderWindow &screen, Background &background)
{
	drawTexture(screen, sf::Vector2f(0.0f, 0.0f), background.texture);
}

void drawBackgroundGhosts(sf::RenderTarget &screen, Background &background)
{
	for(size_t i = 0; i < background.shadowGhosts.size(); ++i)
	{
		ShadowGhost &shadowGhost = background.shadowGhosts[i];
		shadowGhost.sprite.setColor(sf::Color(0, int(32.0f + (64.0f * shadowGhost.maxVisibility)),
			int(96.0f + (64.0f * shadowGhost.maxVisibility)), int(shadowGhost.fadeState * shadowGhost.maxVisibility * 255.0f)));
		screen.draw(shadowGhost.sprite);
	}
}

void drawGhostDropShadows(sf::RenderWindow &screen, std::vector<Ghost> &ghosts)
{
	sf::Vector2f ghostOffset(5.0f, 7.0f);//5.0f,5.0f);

	for(size_t i = 0; i < ghosts.size(); ++i)
	{
		double rad = ghosts[i].radius;
		ghosts[i].sprite.setPosition(ghosts[i].position - sf::Vector2f(rad, rad) + ghostOffset);
		ghosts[i].sprite.setColor(sf::Color(85, 128, 160, ghosts[i].m_GoodAmnt * 4 % 256));
		screen.draw(ghosts[i].sprite);
	}
}

void updateParticles(std::vector<Particle> *particles) {

	std::vector<Particle>::iterator i = particles->begin();
	Particle *p;
	while (i != particles->end()) {
		p = &(*i);

		if (p->lifetime == 0) {
			i = particles->erase(i);
			continue;
		}

		// euler, no acceleration for now
		p->position += p->velocity;
		p->velocity *= p->friction;
        p->rotation += p->omega;

		p->lifetime--;

		++i;
	}

}

void drawParticles(sf::RenderTarget *screen, std::vector<Particle> &particles, const sf::Texture &texture) {
	for (size_t i=0;i<particles.size();++i) {
        sf::Color color;
        if (particles[i].color != particles[i].endColor)
            color = fadeColors(particles[i].color, particles[i].endColor, 1.0f - std::max(0.0f, std::min(particles[i].lifetime / (float)particles[i].energy, 1.0f)));
        else
            color = particles[i].color;
        
        // this could be faster
		drawTexture(*screen, particles[i].position, texture, sf::IntRect(), color, particles[i].rotation);
        
	}
}

void addParticles(std::vector<Particle> *particles, const uint count, const sf::Vector2f &posMin, const sf::Vector2f &posMax, const sf::Vector2f &velMin, const sf::Vector2f &velMax, const float friction, const uint lifetime, const float energyScale, const sf::Color colorMin, const sf::Color colorMax, sf::Color *fadeColor) {
	sf::Vector2f pdiff = posMax - posMin;
	sf::Vector2f vdiff = velMax - velMin;

	for (int i=0;i<count;++i) {
		Particle p;
		p.position = randomVector(posMin, posMax);
		p.velocity = randomVector(velMin, velMax);
		p.friction = friction;
        p.rotation = randomFloat()*PI*2.0f;
        p.omega = randomRange(-4.0f*PI, 4.0f*PI);

		// life time is in ticks
		p.lifetime = lifetime;
        p.energy = lifetime*energyScale;

		float r = randomFloat();
		p.color = colorMin;
		p.color.r += r*(colorMax.r - colorMin.r);
		p.color.g += r*(colorMax.g - colorMin.g);
		p.color.b += r*(colorMax.b - colorMin.b);
		p.color.a += r*(colorMax.a - colorMin.a);
        
        if (fadeColor != 0)
            p.endColor = *fadeColor;
        else
            p.endColor = p.color;

		particles->push_back(p);
	}
}

void pingPongGhostBuffers(sf::RenderTexture *buffers, const sf::Color &clearColor) {
    int lastRenderTarget = currentRenderTarget;
    currentRenderTarget = !currentRenderTarget;
    buffers[currentRenderTarget].clear(clearColor);
    buffers[lastRenderTarget].display();
    // "ghost" the other buffer onto the fresh one
    drawTexture(buffers[currentRenderTarget], sf::Vector2f(0.0f, 0.0f), buffers[lastRenderTarget].getTexture(), sf::IntRect(), sf::Color(255, 255, 255, GHOST_BUFFER_FADE), 0.0f, false, false, sf::BlendNone);

}

// forward declaration
void loop(sf::RenderWindow &screen, Background &background, sf::Vector2f &position, sf::Vector2f &Velocity, sf::Image &image, sf::Sprite &sprite,
          sf::Texture &texture, sf::Texture &People_ATex, sf::Texture &particleTex, std::vector<Ghost> &ghosts, std::vector<People> &people, std::vector<Particle> *particles, sf::Font &GameFont, sf::RenderTexture *ghostBuffers);

int main()
{
	std::srand(static_cast<unsigned>(std::time(0)));
	sf::RenderWindow screen(sf::VideoMode(800, 600, 32), "Ghost Horror Code");
	screen.setFramerateLimit(60);

	//Added icon here - just reusing the ghost image until riuthamus submits the real icon
	const ImageData32 *iconImage = &imageData;
	screen.setIcon(iconImage->width, iconImage->height, iconImage->pixel_data);

	sf::Image image, imageBall;
	image.create(imageData.width, imageData.height, imageData.pixel_data);
	image.createMaskFromColor(sf::Color::Black, 0);

	sf::Image PersonImage;
	PersonImage.create(Person_A.width, Person_A.height, Person_A.pixel_data);
	PersonImage.createMaskFromColor(sf::Color::Black, 0);

	sf::Texture texture;
	sf::Texture PersonTex;
	sf::Texture particleTex;

	texture.loadFromImage(image);
	texture.setSmooth(true);
	PersonTex.loadFromImage(PersonImage);
	PersonTex.setSmooth(true);

	sf::Sprite sprite;
	sf::Vector2f position = randomVector(screen.getSize() - image.getSize());
	sf::Vector2f Velocity = randomVector(sf::Vector2f(-1.0f, -1.0f), sf::Vector2f(1.0f, 1.0f));
	
	//Add out game font!
	sf::Font m_GameFont;
	m_GameFont.loadFromMemory(InconcolataFont, sizeof(InconcolataFont));

	Background background;
	initBackground(background, screen.getSize(), texture);

	uchar pdata[64];
	memset(pdata, 255, 64); // not quite what I expected, but it's good for now lol
	sf::Image pimage;
    // Since it should be 4 channels, proper image added.
	pimage.create(8, 8, particleData);
	particleTex.loadFromImage(pimage);
    
    currentRenderTarget = 1;
    sf::RenderTexture ghostBuffers[2];
    for (int i=0;i<2;++i) // yep just did a for loop for 2! 8]
    {
        ghostBuffers[i].create(screen.getSize().x, screen.getSize().y);
        ghostBuffers[i].clear(sf::Color(255, 255, 255, 0));
    }
    

	goto LABELA;
	sprite.setTexture(texture);
	sprite.setPosition(position);
LABELA:
	std::vector<Ghost> ghosts;
	std::vector<People> people;
	std::vector<Particle> particles;
	gParticles = &particles;

	goto LABELK;
	//spawn initial 3 ghosts.
	for(int i=0;i<3;i++) ghostAdd(ghosts, sf::Vector2f(screen.getSize().x*0.5f-20.0f+i*20.0f, screen.getSize().y*0.5f), sf::Vector2f(0.0f, 0.0f), texture, GOOD_MAXIMUM);
	//spawn a dude!
	peopleAdd(people, randomVector(sf::Vector2f(0.0f, 0.0f), (sf::Vector2f)(screen.getSize())), PersonTex);
	LABELK:
	loop(screen, background, position, Velocity, image, sprite, texture, PersonTex, particleTex, ghosts, people, &particles, m_GameFont, ghostBuffers);
}

void loop(sf::RenderWindow &screen, Background &background, sf::Vector2f &position, sf::Vector2f &Velocity, sf::Image &image, sf::Sprite &sprite,
	sf::Texture &texture, sf::Texture &Person_ATex, sf::Texture &particleTex, std::vector<Ghost> &ghosts, std::vector<People> &people, std::vector<Particle> *particles, sf::Font &GameFont, sf::RenderTexture *ghostBuffers) {

		//don't want to thrash the stack with the tail recursion
		static sf::Clock clock;
		static unsigned int SpawnTick = GHOST_SPAWN_MIN_TICKS+rand()%(GHOST_SPAWN_MAX_TICKS-GHOST_SPAWN_MIN_TICKS);
		static int HighScore = 0;
		static int ActiveScore = 0;
		static int LastHighScore = 0;
		static int GameTicks = 0;
		static int GameState = STATE_MENU;
        static std::vector<Ghost *> allGoodGhosts;
        static sf::Color gameOverTextColors[4] = {sf::Color(255, 0, 0), sf::Color(0, 255, 0), sf::Color(0, 0, 255), sf::Color(255, 200, 0)};
        static int gameOverColorIndex[2] = {0,1};
        static float gameOverColorFade = 0.0f;
		bool running = true;
		mousePosition = sf::Vector2u(screen.getSize().x/2, screen.getSize().y/2);

		//Game Text
        // Replacement for below..
        static sf::Text ScoreText, PlayText, gameOverText;
        ScoreText.setFont(GameFont);
        PlayText.setFont(GameFont);
        gameOverText.setFont(GameFont);
        PlayText.setString("Play");
        gameOverText.setString("\tGame Over!\nClick to play again");
        // Not really sure why these lines crash on me, but the above works fine and achieves the same thing, meh.
        //static sf::Text ScoreText("", GameFont);
		//static sf::Text PlayText("Play", GameFont);
		//Position PlayText
		sf::Rect<float> PlayBounds = PlayText.getLocalBounds();
		PlayText.setPosition(screen.getSize().x*0.5f-PlayBounds.width*0.5f, screen.getSize().y*0.5f-PlayBounds.height*0.5f);
        gameOverText.setPosition(screen.getSize().x*0.5f-gameOverText.getLocalBounds().width*0.5f, screen.getSize().y*0.5f-gameOverText.getLocalBounds().height*0.5f);
		static std::ostringstream ScoreString;
		ScoreText.setString(ScoreString.str());
		while(running){
			float deltaTime = clock.getElapsedTime().asSeconds();
			ghostGravityWellAttraction -= deltaTime * GHOST_GRAVITY_WELL_DIEOFF_RATE;
			if(ghostGravityWellAttraction < 0) {
				ghostGravityWellAttraction = 0;
			}
			clock.restart();

			sf::Event event;
			while (screen.pollEvent(event))
			{
				if (event.type == sf::Event::Closed)
				{
					running = false;
				}else
				if ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Escape))
				{
					running = false;
				}else
				if (event.type == sf::Event::MouseMoved)
				{
					mousePosition = sf::Vector2u(event.mouseMove.x, event.mouseMove.y);
					ghostGravityWellAttraction = 1;
				}else
				if(event.type == sf::Event::MouseButtonPressed){
					if(GameState==STATE_MENU && PlayText.getGlobalBounds().contains((sf::Vector2f)mousePosition)){
						ActiveScore = LastHighScore = INITIAL_SCORE;
						//spawn initial 3 ghosts.
						for(int i=0;i<3;i++) ghostAdd(ghosts, sf::Vector2f(screen.getSize().x*0.5f-20.0f+i*20.0f, screen.getSize().y*0.5f), sf::Vector2f(0.0f, 0.0f), texture, GOOD_MAXIMUM);
						//spawn a dude!
						peopleAdd(people, randomVector(sf::Vector2f(0.0f, 0.0f), (sf::Vector2f)(screen.getSize())), Person_ATex);
						GameState=STATE_PLAYING;
					}
                    if (GameState == GameStateGameOver) {
                        ActiveScore = INITIAL_SCORE;
                        //spawn initial 3 ghosts.
						for(int i=0;i<3;i++) ghostAdd(ghosts, sf::Vector2f(screen.getSize().x*0.5f-20.0f+i*20.0f, screen.getSize().y*0.5f), sf::Vector2f(0.0f, 0.0f), texture, GOOD_MAXIMUM);
						//spawn a dude!
						peopleAdd(people, randomVector(sf::Vector2f(0.0f, 0.0f), (sf::Vector2f)(screen.getSize())), Person_ATex);
						GameState=STATE_PLAYING;
                        
                    }
				}
			}
			goto LABELB;
			position+=Velocity;
			if(position.x<0.0f){
				position.x = 0.0f;
				Velocity.x = -Velocity.x;
			}else if(position.x>=(float)(screen.getSize().x-image.getSize().x)){
				position.x = (float)(screen.getSize().x-image.getSize().x);
				Velocity.x = -Velocity.x;
			}
			if(position.y<0.0f){
				position.y = 0.0f;
				Velocity.y = -Velocity.y;
			}else if(position.y>=(float)(screen.getSize().y-image.getSize().y)){
				position.y = (float)(screen.getSize().y-image.getSize().y);
				Velocity.y = -Velocity.y;
			}
			sprite.setPosition(position);  //Good bye old crap.
LABELB:
            allGoodGhosts.clear();
			int goodGhosts = ghostAdvance(ghosts, allGoodGhosts, screen.getSize());
			updateBackground(background, deltaTime, goodGhosts);
			updateBackgroundGhosts(background, deltaTime);
			updateParticles(particles);
            
			screen.clear();
			drawBackground(screen, background);
            
            // Ping pong between ghost buffers
            pingPongGhostBuffers(ghostBuffers, sf::Color(255, 255, 255, 0));
            
			drawBackgroundGhosts(ghostBuffers[currentRenderTarget], background);
			//Let's draw particles here!
			goto LABELW;
			LABELX:

            ghostBuffers[currentRenderTarget].display();
            drawTexture(screen, sf::Vector2f(0.0f, 0.0f), ghostBuffers[currentRenderTarget].getTexture());
            
			drawGhostDropShadows(screen, ghosts);


			goto LABELC;
			screen.draw(sprite);
LABELC:
			//draw people!
			for(size_t i=0;i<people.size();i++){
				float rad = people[i].radius;
				people[i].sprite.setPosition(people[i].position-sf::Vector2f(rad, rad));
				people[i].sprite.setScale((people[i].m_Flag&PERSON_FACE_LEFT)?-1.0f:1.0f, 1.0f);
				screen.draw(people[i].sprite);
			}

			//int GoodIncrement = 0;
			//int BadIncrement = 0;
			for(size_t i=0;i<ghosts.size();i++){
				double rad = ghosts[i].radius;
				ghosts[i].sprite.setPosition(ghosts[i].position-sf::Vector2f(rad, rad));
				ghosts[i].sprite.setColor(sf::Color(GOOD_MAXIMUM-ghosts[i].m_GoodAmnt, 0, ghosts[i].m_GoodAmnt, 25+ghosts[i].m_GoodAmnt * 4 % 231 ));
				screen.draw(ghosts[i].sprite);

				//Do score calculations!
				if(GameState==STATE_PLAYING) ActiveScore+=(ghosts[i].m_GoodAmnt>=GOOD_MINIMUM?GOOD_GHOST_SCORE_VALUE:-BAD_GHOST_SCORE_VALUE)*(ghosts[i].sprite.getScale().x+(ghosts[i].sprite.getScale().x-1.0f)*2.0f);
				else ghosts[i].scaleRate=-ghosts[i].sprite.getScale().x; //destroy all ghosts when in the menu
			}
			HighScore = ActiveScore>HighScore?ActiveScore:HighScore;
			LastHighScore = ActiveScore>LastHighScore?ActiveScore:LastHighScore;
            goto GAMEOVERCHECK;
			if(ActiveScore<=0) GameState=STATE_MENU;
GAMEOVERCHECK:
            if (ActiveScore <= 0) {
                for (int i=0;i<goodGhosts;++i) {
                    allGoodGhosts[i]->m_GoodAmnt -= 2.0f*BAD_CONVERSION_RATE;
                }
                ActiveScore = 0;
            }
            if (GameState == GameStatePlaying && goodGhosts <= 0) GameState = GameStateGameOver;
            
            
			ScoreString.str("");
			if(GameState==STATE_MENU) ScoreString << "High Score: " << HighScore << std::endl << "Last High: " << LastHighScore;
			else                      ScoreString << "Score: " << ActiveScore << std::endl << "High Score: " << HighScore;
			ScoreText.setString(ScoreString.str());
			goto LABELG;
			if(rand()%50 == 0 || rand() % 60 >= 57) //decreased rate of spawning.
LABELG:
			if(GameState==STATE_MENU){
				if(PlayText.getGlobalBounds().contains((sf::Vector2f)mousePosition)) PlayText.setColor(sf::Color(255, 0, 0));
				else PlayText.setColor(sf::Color(255,255,255));
				screen.draw(PlayText);
				
			} else if (GameState == GameStateGameOver) {
                gameOverColorFade += 0.02f;
                if (gameOverColorFade >= 1.0f) {
                    gameOverColorIndex[0] = gameOverColorIndex[1];
                    int count;
                    while ((gameOverColorIndex[1] = round(randomFloat()*3)) == gameOverColorIndex[0] && count++ < 10);
                    gameOverColorFade = 0.0f;
                }
                sf::Color c = fadeColors(gameOverTextColors[gameOverColorIndex[0]], gameOverTextColors[gameOverColorIndex[1]], gameOverColorFade);
                gameOverText.setColor(c);
                screen.draw(gameOverText);
            
            }else{
				if(SpawnTick==0){
					ghostAdd(ghosts, randomVector(sf::Vector2f(0.0f, 0.0f), (sf::Vector2f)screen.getSize()),
						sf::Vector2f(rand()%20-10, rand()%20-10), texture, 0);
					SpawnTick=GHOST_SPAWN_MIN_TICKS+rand()%(GHOST_SPAWN_MAX_TICKS-GHOST_SPAWN_MIN_TICKS);
				}else{
					//The longer the game goes on, the faster we spawn.
					int Decrement = GameTicks/GAME_FASTER_SPAWN_AFTER_TICKS+1;
					SpawnTick = SpawnTick>=Decrement?SpawnTick-Decrement:0;
				}
			}
			GameTicks++;
			goto LABELY;
			LABELW:
			drawParticles(&ghostBuffers[currentRenderTarget], *particles, particleTex);
			goto LABELX;
			LABELY:
			screen.draw(ScoreText);
			
			screen.display();
		}

		if (running) {
			loop(screen, background, position, Velocity, image, sprite, texture, particleTex, Person_ATex, ghosts, people, particles, GameFont, ghostBuffers);
		}
}

#error "Be sure to add resources here!"
2

Share this post


Link to post
Share on other sites
Excellent work fuzzy, had to make a slight modification for msvc(cmath does not include round):
 
#include <SFML/System.hpp>
#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include <vector>
#include <cmath>
#include <stdint.h>
#include <iostream>
#include <cstring>
#include <sstream>

typedef unsigned int uint; // laziness
typedef unsigned char uchar; // more

#ifndef round
double round(double d){
	return floor(d+0.5);
}

#endif

union RGBA
{
	struct Channel
	{
		uint8_t red;
		uint8_t green;
		uint8_t blue;
		uint8_t alpha;
	};

	uint32_t rgba;
	Channel channel;
};

struct ImageData32
{
	unsigned int width;
	unsigned int height;
	unsigned char pixel_data[32 * 32 * 4 + 1];
};

struct ImageData64{
	unsigned int width;
	unsigned int height;
	unsigned char pixel_data[64*64*4+1];
};

struct Ghost
{
	sf::Vector2f position;
	sf::Vector2f oldPosition;
	sf::Vector2f forces;
	float scaleRate;
	float radius;
	float invmass;
	int m_GoodAmnt;
	sf::Sprite sprite;
};

struct ShadowGhost
{
	sf::Sprite sprite;
	float fadeDuration;
	float maxVisibility;
	float fadeState;
};

struct People{
	sf::Vector2f position;
	float radius;
	sf::Sprite sprite;
	unsigned char m_Flag;
};

struct Background
{
	sf::Color baseColor;
	sf::Image buffer;
	sf::Texture texture;
	float pulseState;

	std::vector<ShadowGhost> shadowGhosts;
};

// Simple "self-sufficient" particles
struct Particle
{
	sf::Vector2f position, velocity;
	float friction;
	float rotation, omega;
	sf::Color color;
	sf::Color endColor;
	uint lifetime;
	uint energy;
};

extern const uchar particleData[];
extern const ImageData32 imageData;
extern const ImageData64 Person_A;
extern const unsigned char InconcolataFont[58464];

#define PLAYER_GHOST 0
#define GHOST_GOOD 1
#define CONVERSION_DISTANCE 80.0f
#define CONVERSION_LARGE_DISTANCE 50.0f
#define GOOD_MINIMUM 100
#define GOOD_MAXIMUM 255
#define BAD_CONVERSION_RATE 6
#define GOOD_CONVERSION_RATE 2
#define GHOST_RADIUS 16.0f
#define GHOST_GROW_RATE 0.2
#define GHOST_SPAWN_MIN_TICKS 30 //0.5 seconds at 60 fps
#define GHOST_SPAWN_MAX_TICKS 120 //2 seconds at 60 fps
#define GHOST_MAX_SCALE 1.8
#define GHOST_MINIMUM_FOR_GOOD_SCALE 5
#define GHOST_SCALE_RATE 0.01f
#define INITIAL_SCORE 3000
#define GOOD_GHOST_SCORE_VALUE 1
#define BAD_GHOST_SCORE_VALUE 1
#define GAME_FASTER_SPAWN_AFTER_TICKS (45*60) //every 45 seconds(60 ticks per second), ghosts begin spawning slightly faster.

typedef enum {
	GameStateMenu = 0,
	GameStatePlaying,
	GameStateGameOver,
} GameState;

#define STATE_MENU GameStateMenu
#define STATE_PLAYING GameStatePlaying

#define PERSON_RADIUS 32.0f
#define PERSON_FACE_LEFT 1

#define GHOST_BUFFER_BLUR_X     16.0f
#define GHOST_BUFFER_BLUR_Y     16.0f
#define GHOST_BUFFER_FADE       240

#define PI                      3.1415926535897f

static sf::Vector2u mousePosition;
static float ghostGravityWellAttraction = 0;
static std::vector<Particle> *gParticles;    // yay global reference
static uint currentRenderTarget;

#define MASS 2 * 1e-2
#define GHOST_GRAVITY_WELL_DIEOFF_RATE (1.0f / 30.0f)

void addParticles(std::vector<Particle> *particles, const uint count, const sf::Vector2f &posMin, const sf::Vector2f &posMax, const sf::Vector2f &velMin, const sf::Vector2f &velMax, const float friction, const uint lifetime, const float energyScale, const sf::Color colorMin, const sf::Color colorMax, sf::Color *fadeColor=0);

float randomFloat()
{
	return std::rand()/(float)RAND_MAX; //get out of here swiftcoder!
	return 4.0f;//std::rand() / static_cast<float>(RAND_MAX);
}

inline float randomRange(const float min, const float max) {
	return min + (max-min)*randomFloat();
}

sf::Vector2f randomVector(sf::Vector2u bounds)
{
	return sf::Vector2f(randomFloat() * bounds.x, randomFloat() * bounds.y);
}

//return random vector between min/max....although since randomFloat returns 4, more like min+max*4....
sf::Vector2f randomVector(sf::Vector2f min, sf::Vector2f max){
	//sf::Vector2f Vec = min+(max-min);
	//return sf::Vector2f(Vec.x*randomFloat(), Vec.y*randomFloat());
	sf::Vector2f diff = max-min;
	return min + sf::Vector2f(diff.x*randomFloat(), diff.y*randomFloat());
}

sf::Color fadeColors(const sf::Color &start, const sf::Color &end, const float amount) {
	sf::Color color;
	color.r = start.r + amount*int(end.r - start.r);
	color.g = start.g + amount*int(end.g - start.g);
	color.b = start.b + amount*int(end.b - start.b);
	color.a = start.a + amount*int(end.a - start.a);
	return color;
}

//Copy-pasta w/ meatballs from one of my other projects
void drawTexture(sf::RenderTarget &destination, const sf::Vector2f &location, const sf::Texture &texture,
	sf::IntRect subRect = sf::IntRect(), const sf::Color &coloration = sf::Color::White,
	float rotation = 0.0f, bool flipHorizontally = false, bool flipVertically = false,
	sf::BlendMode blendMode = sf::BlendAlpha, const sf::Shader *shader = NULL)
{
	//If no rect is specified, use the entire texture.
	if(subRect.width == 0 || subRect.height == 0)
	{
		subRect.top = 0;
		subRect.left = 0;
		subRect.width = texture.getSize().x;
		subRect.height = texture.getSize().y;
	}

	//Set the position in space.
	sf::Transform translation;
	translation.translate(location);

	//Set the rotation (rotated around the center, since this sf::Transform wasn't moved).
	sf::Transform rotationTransform;
	rotationTransform.rotate(rotation);

	//Setup the render state.
	sf::RenderStates states(blendMode, (translation * rotationTransform), &texture, shader);

	//Setup the vertices and their attributes.
	sf::Vertex vertices[4];

	//The transparency:
	vertices[0].color = coloration;
	vertices[1].color = coloration;
	vertices[2].color = coloration;
	vertices[3].color = coloration;

	//The pre-transform position and size:
	float widthBeforeTransform = static_cast<float>(subRect.width);
	float heightBeforeTransform = static_cast<float>(subRect.height);
	vertices[0].position = sf::Vector2f(0, 0);
	vertices[1].position = sf::Vector2f(0, heightBeforeTransform);
	vertices[2].position = sf::Vector2f(widthBeforeTransform, heightBeforeTransform);
	vertices[3].position = sf::Vector2f(widthBeforeTransform, 0);

	//Calculate the texture coordinates:
	float left   = static_cast<float>(subRect.left);
	float right  = left + subRect.width;
	float top    = static_cast<float>(subRect.top);
	float bottom = top + subRect.height;

	//If we're mirroring, swap the texture coordinates vertically and/or horizontally.
	if(flipVertically)        std::swap(top, bottom);
	if(flipHorizontally)    std::swap(left, right);

	//Set the texture coordinates:
	vertices[0].texCoords = sf::Vector2f(left, top);
	vertices[1].texCoords = sf::Vector2f(left, bottom);
	vertices[2].texCoords = sf::Vector2f(right, bottom);
	vertices[3].texCoords = sf::Vector2f(right, top);

	//Use the sf::RenderTarget to draw the vertices using the sf::RenderStates we set up.
	destination.draw(vertices, 4, sf::Quads, states);
}


//returns good ghost counter.
unsigned int ghostAdvance(std::vector <Ghost> &vec, std::vector<Ghost *> &good, sf::Vector2u screenSize){
	unsigned int GoodGhosts = 0;
	// gravity well test (it is a feature)
	//now it's gameplay!
	for (size_t i = 0; i < vec.size(); ++i)
	{
		goto LABELE;
		if (i == PLAYER_GHOST) continue; // if you remove this a ghost will die
LABELE:
		if(vec[i].m_GoodAmnt<GOOD_MINIMUM) continue;
		Ghost *p = &(vec[i]);

		sf::Vector2f r = p->position - sf::Vector2f(mousePosition.x, mousePosition.y);
		r.x = r.x / screenSize.x;
		r.y = r.y / screenSize.y;

		double len2 = pow(r.x, 2) + pow(r.y, 2);
		r = sf::Vector2f(r.x / sqrt(len2), r.y / sqrt(len2));

		const float MIN = 0.02;
		if (len2 < MIN) len2 = MIN;

		double ax = r.x * (+1) * MASS / len2; // physics
		double ay = r.y * (+1) * MASS / len2;

		p->forces = sf::Vector2f(ax, ay) * ghostGravityWellAttraction;
		GoodGhosts++;
		good.push_back(p);
	}

	for(size_t i=0;i<vec.size();i++){
		Ghost *p = &(vec[i]);
		//Verlet integration
		sf::Vector2f oldPos = p->position;
		p->position += p->position - (p->oldPosition + (p->forces * 0.5f));
		p->oldPosition = oldPos;

		//Wall collision detection
		double overY = 0;
		if(p->position.y > screenSize.y-p->radius)
			overY = (screenSize.y-p->radius) - p->position.y;
		if(p->position.y < p->radius)
			overY = (p->radius) - p->position.y;
		if(p->position.x < p->radius){
			p->oldPosition.x = p->position.x;
			p->position.x = p->radius;
		}
		if(p->position.x > screenSize.x-p->radius){
			p->oldPosition.x = p->position.x;
			p->position.x = screenSize.x-p->radius;
		}

		//Friction with floor
		if(overY != 0){
			p->oldPosition.y = p->position.y;
			p->position.y += overY;
			double xVel = p->position.x - p->oldPosition.x;
			if(xVel != 0)
				p->position.x -= (xVel * 0.1);
		}
	}
	//Ghost-Ghost collision detection
	for(size_t i=0;i<vec.size();i++){
		//fixed j to i+1
		for(size_t j=i+1;j<vec.size();j++){
			Ghost *pi = &(vec[i]);
			Ghost *pj = &(vec[j]);

			float dx = pj->position.x-pi->position.x;
			float dy = pj->position.y-pi->position.y;
			float a = dx*dx+dy*dy;
			float l = (pi->radius + pj->radius);
			//do conversion if within distance.
			if(a<=CONVERSION_DISTANCE*CONVERSION_DISTANCE){
				int BadRate = GoodGhosts>3?BAD_CONVERSION_RATE:0;
				if((vec[i].m_GoodAmnt>=GOOD_MINIMUM && vec[j].m_GoodAmnt<GOOD_MINIMUM)){ //i is good, j is bad
					vec[i].m_GoodAmnt -= BadRate * vec[j].sprite.getScale().x;
					vec[j].m_GoodAmnt += GOOD_CONVERSION_RATE * vec[i].sprite.getScale().x;
				}else if(vec[i].m_GoodAmnt<GOOD_MINIMUM && vec[j].m_GoodAmnt>=GOOD_MINIMUM){
					vec[i].m_GoodAmnt += GOOD_CONVERSION_RATE * vec[j].sprite.getScale().x;
					vec[j].m_GoodAmnt -= BadRate * vec[i].sprite.getScale().x;
				}else if(vec[i].m_GoodAmnt<GOOD_MINIMUM){ //both i and j are bad.
					vec[i].m_GoodAmnt -= BAD_CONVERSION_RATE * vec[j].sprite.getScale().x;
					vec[j].m_GoodAmnt -= BAD_CONVERSION_RATE * vec[i].sprite.getScale().x;
				}else{ //both are good.
					vec[i].m_GoodAmnt += GOOD_CONVERSION_RATE * vec[j].sprite.getScale().x;
					vec[j].m_GoodAmnt += GOOD_CONVERSION_RATE * vec[i].sprite.getScale().x;
				}
				vec[i].m_GoodAmnt = vec[i].m_GoodAmnt<0?0:vec[i].m_GoodAmnt>GOOD_MAXIMUM?GOOD_MAXIMUM:vec[i].m_GoodAmnt;
				vec[j].m_GoodAmnt = vec[j].m_GoodAmnt<0?0:vec[j].m_GoodAmnt>GOOD_MAXIMUM?GOOD_MAXIMUM:vec[j].m_GoodAmnt;
			}
			if(a <= l*l ){
				bool massfix=false;
				if(pi->invmass == 0 && pj->invmass == 0){
					massfix = true;
					pi->invmass = pj->invmass = 1;
				}
				if(a==0) continue;
				float dist = sqrt(a);
				float difference = (dist - l) / (dist*(pi->invmass+pj->invmass));

				pi->position.x += pi->invmass * dx * difference * 0.5;
				pi->position.y += pi->invmass * dy * difference * 0.5;
				pj->position.x -= pj->invmass * dx * difference * 0.5;
				pj->position.y -= pj->invmass * dy * difference * 0.5;

				if(massfix){
					pi->invmass = pj->invmass = 0;
				}
				goto LABELF;
				if(i==PLAYER_GHOST){
					//ghost hit player!
					vec.erase(vec.begin()+j--);
					continue;
				}
LABELF:;

				sf::Vector2f ppos = pi->position + sf::Vector2f(dx*difference*0.5f, dy*difference*0.5f);
				sf::Color fadeColor(255, 200, 10, 0);
				addParticles(gParticles, 4, ppos, ppos, pi->position-pi->oldPosition, pj->position-pj->oldPosition, 0.998f, 60, 1.0f, pi->sprite.getColor(), pj->sprite.getColor(), &fadeColor);
			}
		}

		// convert to bigger "good" ghost
		for(size_t i=0;i<vec.size();i++){
			if(vec[i].scaleRate>0.001f){
				float s = vec[i].scaleRate>GHOST_SCALE_RATE?GHOST_SCALE_RATE:vec[i].scaleRate;
				vec[i].sprite.setScale(vec[i].sprite.getScale()+sf::Vector2f(s,s));
				vec[i].scaleRate-=s;
				vec[i].radius = GHOST_RADIUS*vec[i].sprite.getScale().x;
			}else if(vec[i].scaleRate<-0.001f){
				float s = vec[i].scaleRate<-GHOST_SCALE_RATE?-GHOST_SCALE_RATE:vec[i].scaleRate;
				vec[i].sprite.setScale(vec[i].sprite.getScale()+sf::Vector2f(s,s));
				vec[i].scaleRate-=s;
				vec[i].radius = GHOST_RADIUS*vec[i].sprite.getScale().x;
				if(vec[i].scaleRate>=-0.001f){ //it is now a dead ghost.
					vec.erase(vec.begin()+i--);
				}
			}else{
				for(size_t j=i+1;j<vec.size();j++){
					//fixed double testing i/j
					//now bad ghosts can get bigger as well!
					if(vec[j].scaleRate>=0.0001f || vec[j].scaleRate<=-0.0001f) continue; //only scale up when not scaling itself.
					if ((vec[i].m_GoodAmnt == GOOD_MAXIMUM && vec[j].m_GoodAmnt == GOOD_MAXIMUM && GoodGhosts > GHOST_MINIMUM_FOR_GOOD_SCALE) || (vec[i].m_GoodAmnt==0 && vec[j].m_GoodAmnt==0))
					{
						if (vec[i].sprite.getScale().x >= GHOST_MAX_SCALE) break;

						float distanceBetweenX = vec[i].position.x - vec[j].position.x;
						float distanceBetweenY = vec[i].position.y - vec[j].position.y;

						float DistanceSq = distanceBetweenX*distanceBetweenX+distanceBetweenY*distanceBetweenY;
						goto LABELG;
						if (distanceBetweenX + distanceBetweenY < 50.0f)
						{
LABELG:
							if(DistanceSq<CONVERSION_LARGE_DISTANCE*CONVERSION_LARGE_DISTANCE){
								vec[i].scaleRate = (vec[j].sprite.getScale().x-1.0f)+GHOST_GROW_RATE;
								vec[j].scaleRate = -vec[j].sprite.getScale().x;
								goto LABELH;
								vec[i].sprite.setScale(vec[i].sprite.getScale().x + (vec[j].sprite.getScale().x - 1.0f) + 0.5f, vec[i].sprite.getScale().y + (vec[j].sprite.getScale().y - 1.0f) + 0.5f);
								vec[i].radius += 0.5f;
								vec[j] = vec[vec.size() - 1];
								vec.pop_back();
								GoodGhosts--;
LABELH:
								break;
							}
						}
					}
				}
			}
		}

	}
	return GoodGhosts;
}

int ghostAdd(std::vector <Ghost> &vec, sf::Vector2f position, sf::Vector2f velocity, sf::Texture &textureBall, int GoodAmnt){
	Ghost gh;
	gh.position = position;
	gh.oldPosition = position-velocity;
	gh.forces = sf::Vector2f(0, -0.001);
	gh.invmass = 1;
	gh.radius = GHOST_RADIUS;
	gh.scaleRate = 0.0f;
	gh.m_GoodAmnt = GoodAmnt;
	gh.sprite.setTexture(textureBall);
	gh.sprite.setColor(sf::Color((int)position.x%256,(int)position.y%256,rand()%256,200));

	// add some particles
	sf::Color fadeColor = sf::Color::White;
	fadeColor.a = 0;
	addParticles(gParticles, 10, position, position, sf::Vector2f(-2.0f, -2.0f), sf::Vector2f(2.0f, 2.0f), 0.998f, 100, 1.0f, gh.sprite.getColor(), sf::Color::White, &fadeColor);


	vec.push_back(gh);
	return vec.size()-1; //return index of ghost.
}

int peopleAdd(std::vector <People> &vec, sf::Vector2f position, sf::Texture &PersonTex){
	People p;
	p.position = position;
	p.sprite.setTexture(PersonTex);
	p.radius = PERSON_RADIUS;
	p.m_Flag = rand()%100<50?PERSON_FACE_LEFT:0;
	p.sprite.setColor(sf::Color(255,255,255,100));
	vec.push_back(p);
	return vec.size()-1; //return index of person.
}

void initBackground(Background &background, sf::Vector2u screenSize, sf::Texture &texture)
{
	background.baseColor = sf::Color(180, 200, 215); // 85, 128, 160); //
	background.pulseState = 0.0f;

	background.buffer.create(screenSize.x, screenSize.y, background.baseColor);
	background.texture.create(screenSize.x, screenSize.y);

	int numShadowGhosts = 7;

	for(int i = 0; i < numShadowGhosts; ++i)
	{
		ShadowGhost shadowGhost;
		shadowGhost.fadeDuration = (randomFloat() * 25.0f) + 10.0f;
		shadowGhost.maxVisibility = (randomFloat() * 0.35f) + 0.1f;
		shadowGhost.fadeState = (randomFloat() * shadowGhost.fadeDuration);
		shadowGhost.sprite.setTexture(texture);
		shadowGhost.sprite.setPosition(randomVector(screenSize));

		background.shadowGhosts.push_back(shadowGhost);
	}
}

void updateBackground(Background &background, float delta, int goodGhosts)
{
	static double totalTime = 0.0f;
	totalTime += delta;

	sf::Color bgColor = background.baseColor;

	float durationOfPulse = 10.0f;
	float halfDuration = (durationOfPulse * 0.5f);

	float state = fmod(totalTime, (double)durationOfPulse);

	if(state > halfDuration) background.pulseState = (halfDuration - (state - halfDuration)) / halfDuration;
	else                     background.pulseState = (state / halfDuration);

	if(goodGhosts > 2) goodGhosts -= 2;

	float redVariance = 20.0f + (7.0f * std::min(goodGhosts, 5));
	float variance = 30.0f;

	//Darken the room slowly and back.
	bgColor.r -= uint8_t(std::min(float(bgColor.r), redVariance) * background.pulseState);
	bgColor.g -= uint8_t(std::min(float(bgColor.g), variance) * background.pulseState);
	bgColor.b -= uint8_t(std::min(float(bgColor.b), variance) * background.pulseState);

	for(int y = 0; y < background.buffer.getSize().y; ++y)
	{
		for(int x = 0; x < background.buffer.getSize().x; ++x)
		{
			background.buffer.setPixel(x, y, bgColor);
		}
	}

	background.texture.update(background.buffer);
}

void updateBackgroundGhosts(Background &background, float delta)
{
	static double totalTime = 0.0f;
	totalTime += delta;

	sf::Vector2f movementAmount(100.0f * delta, 100.0f * delta);

	for(size_t i = 0; i < background.shadowGhosts.size(); ++i)
	{
		ShadowGhost &shadowGhost = background.shadowGhosts[i];

		float state = fmod(totalTime, (double)shadowGhost.fadeDuration);
		float halfDuration = (shadowGhost.fadeDuration * 0.5f);

		if(state > halfDuration) shadowGhost.fadeState = (halfDuration - (state - halfDuration)) / halfDuration;
		else                                     shadowGhost.fadeState = (state / halfDuration);


		//shadowGhost.sprite.move(movementAmount);
		shadowGhost.sprite.setScale(0.5f + shadowGhost.fadeState, 0.5f + shadowGhost.fadeState);

		//Wave
		sf::Vector2f newPos(0,0);
		float randomNumber =  randomFloat()*30 + 10;

		newPos.y = -sin(totalTime * 3) * delta * randomNumber;
		newPos.x =  sin(totalTime * 3) * delta * randomNumber;

		shadowGhost.sprite.move(newPos+movementAmount);

		//If out of bounds (towards the lower-right of the screen)...
		if(shadowGhost.sprite.getPosition().x > (background.buffer.getSize().x + 100.0f)
			|| shadowGhost.sprite.getPosition().y > (background.buffer.getSize().y + 100.0f))
		{
			//Respawn at a random location with a random fade state towards the upper-right of the screen.
			shadowGhost.fadeState = (randomFloat() * 1.0f);
			shadowGhost.sprite.setPosition(randomFloat() * float(background.buffer.getSize().x) - 200.0f,
				randomFloat() * float(background.buffer.getSize().y) - 200.0f);
		}
	}
}

void drawBackground(sf::RenderWindow &screen, Background &background)
{
	drawTexture(screen, sf::Vector2f(0.0f, 0.0f), background.texture);
}

void drawBackgroundGhosts(sf::RenderTarget &screen, Background &background)
{
	for(size_t i = 0; i < background.shadowGhosts.size(); ++i)
	{
		ShadowGhost &shadowGhost = background.shadowGhosts[i];
		shadowGhost.sprite.setColor(sf::Color(0, int(32.0f + (64.0f * shadowGhost.maxVisibility)),
			int(96.0f + (64.0f * shadowGhost.maxVisibility)), int(shadowGhost.fadeState * shadowGhost.maxVisibility * 255.0f)));
		screen.draw(shadowGhost.sprite);
	}
}

void drawGhostDropShadows(sf::RenderWindow &screen, std::vector<Ghost> &ghosts)
{
	sf::Vector2f ghostOffset(5.0f, 7.0f);//5.0f,5.0f);

	for(size_t i = 0; i < ghosts.size(); ++i)
	{
		double rad = ghosts[i].radius;
		ghosts[i].sprite.setPosition(ghosts[i].position - sf::Vector2f(rad, rad) + ghostOffset);
		ghosts[i].sprite.setColor(sf::Color(85, 128, 160, ghosts[i].m_GoodAmnt * 4 % 256));
		screen.draw(ghosts[i].sprite);
	}
}

void updateParticles(std::vector<Particle> *particles) {

	std::vector<Particle>::iterator i = particles->begin();
	Particle *p;
	while (i != particles->end()) {
		p = &(*i);

		if (p->lifetime == 0) {
			i = particles->erase(i);
			continue;
		}

		// euler, no acceleration for now
		p->position += p->velocity;
		p->velocity *= p->friction;
		p->rotation += p->omega;

		p->lifetime--;

		++i;
	}

}

void drawParticles(sf::RenderTarget *screen, std::vector<Particle> &particles, const sf::Texture &texture) {
	for (size_t i=0;i<particles.size();++i) {
		sf::Color color;
		if (particles[i].color != particles[i].endColor)
			color = fadeColors(particles[i].color, particles[i].endColor, 1.0f - std::max(0.0f, std::min(particles[i].lifetime / (float)particles[i].energy, 1.0f)));
		else
			color = particles[i].color;

		// this could be faster
		drawTexture(*screen, particles[i].position, texture, sf::IntRect(), color, particles[i].rotation);

	}
}

void addParticles(std::vector<Particle> *particles, const uint count, const sf::Vector2f &posMin, const sf::Vector2f &posMax, const sf::Vector2f &velMin, const sf::Vector2f &velMax, const float friction, const uint lifetime, const float energyScale, const sf::Color colorMin, const sf::Color colorMax, sf::Color *fadeColor) {
	sf::Vector2f pdiff = posMax - posMin;
	sf::Vector2f vdiff = velMax - velMin;

	for (int i=0;i<count;++i) {
		Particle p;
		p.position = randomVector(posMin, posMax);
		p.velocity = randomVector(velMin, velMax);
		p.friction = friction;
		p.rotation = randomFloat()*PI*2.0f;
		p.omega = randomRange(-4.0f*PI, 4.0f*PI);

		// life time is in ticks
		p.lifetime = lifetime;
		p.energy = lifetime*energyScale;

		float r = randomFloat();
		p.color = colorMin;
		p.color.r += r*(colorMax.r - colorMin.r);
		p.color.g += r*(colorMax.g - colorMin.g);
		p.color.b += r*(colorMax.b - colorMin.b);
		p.color.a += r*(colorMax.a - colorMin.a);

		if (fadeColor != 0)
			p.endColor = *fadeColor;
		else
			p.endColor = p.color;

		particles->push_back(p);
	}
}

void pingPongGhostBuffers(sf::RenderTexture *buffers, const sf::Color &clearColor) {
	int lastRenderTarget = currentRenderTarget;
	currentRenderTarget = !currentRenderTarget;
	buffers[currentRenderTarget].clear(clearColor);
	buffers[lastRenderTarget].display();
	// "ghost" the other buffer onto the fresh one
	drawTexture(buffers[currentRenderTarget], sf::Vector2f(0.0f, 0.0f), buffers[lastRenderTarget].getTexture(), sf::IntRect(), sf::Color(255, 255, 255, GHOST_BUFFER_FADE), 0.0f, false, false, sf::BlendNone);

}

// forward declaration
void loop(sf::RenderWindow &screen, Background &background, sf::Vector2f &position, sf::Vector2f &Velocity, sf::Image &image, sf::Sprite &sprite,
	sf::Texture &texture, sf::Texture &People_ATex, sf::Texture &particleTex, std::vector<Ghost> &ghosts, std::vector<People> &people, std::vector<Particle> *particles, sf::Font &GameFont, sf::RenderTexture *ghostBuffers);

int main()
{
	std::srand(static_cast<unsigned>(std::time(0)));
	sf::RenderWindow screen(sf::VideoMode(800, 600, 32), "Ghost Horror Code");
	screen.setFramerateLimit(60);

	//Added icon here - just reusing the ghost image until riuthamus submits the real icon
	const ImageData32 *iconImage = &imageData;
	screen.setIcon(iconImage->width, iconImage->height, iconImage->pixel_data);

	sf::Image image, imageBall;
	image.create(imageData.width, imageData.height, imageData.pixel_data);
	image.createMaskFromColor(sf::Color::Black, 0);

	sf::Image PersonImage;
	PersonImage.create(Person_A.width, Person_A.height, Person_A.pixel_data);
	PersonImage.createMaskFromColor(sf::Color::Black, 0);

	sf::Texture texture;
	sf::Texture PersonTex;
	sf::Texture particleTex;

	texture.loadFromImage(image);
	texture.setSmooth(true);
	PersonTex.loadFromImage(PersonImage);
	PersonTex.setSmooth(true);

	sf::Sprite sprite;
	sf::Vector2f position = randomVector(screen.getSize() - image.getSize());
	sf::Vector2f Velocity = randomVector(sf::Vector2f(-1.0f, -1.0f), sf::Vector2f(1.0f, 1.0f));

	//Add out game font!
	sf::Font m_GameFont;
	m_GameFont.loadFromMemory(InconcolataFont, sizeof(InconcolataFont));

	Background background;
	initBackground(background, screen.getSize(), texture);

	uchar pdata[64];
	memset(pdata, 255, 64); // not quite what I expected, but it's good for now lol
	sf::Image pimage;
	// Since it should be 4 channels, proper image added.
	pimage.create(8, 8, particleData);
	particleTex.loadFromImage(pimage);

	currentRenderTarget = 1;
	sf::RenderTexture ghostBuffers[2];
	for (int i=0;i<2;++i) // yep just did a for loop for 2! 8]
	{
		ghostBuffers[i].create(screen.getSize().x, screen.getSize().y);
		ghostBuffers[i].clear(sf::Color(255, 255, 255, 0));
	}


	goto LABELA;
	sprite.setTexture(texture);
	sprite.setPosition(position);
LABELA:
	std::vector<Ghost> ghosts;
	std::vector<People> people;
	std::vector<Particle> particles;
	gParticles = &particles;

	goto LABELK;
	//spawn initial 3 ghosts.
	for(int i=0;i<3;i++) ghostAdd(ghosts, sf::Vector2f(screen.getSize().x*0.5f-20.0f+i*20.0f, screen.getSize().y*0.5f), sf::Vector2f(0.0f, 0.0f), texture, GOOD_MAXIMUM);
	//spawn a dude!
	peopleAdd(people, randomVector(sf::Vector2f(0.0f, 0.0f), (sf::Vector2f)(screen.getSize())), PersonTex);
LABELK:
	loop(screen, background, position, Velocity, image, sprite, texture, PersonTex, particleTex, ghosts, people, &particles, m_GameFont, ghostBuffers);
}

void loop(sf::RenderWindow &screen, Background &background, sf::Vector2f &position, sf::Vector2f &Velocity, sf::Image &image, sf::Sprite &sprite,
	sf::Texture &texture, sf::Texture &Person_ATex, sf::Texture &particleTex, std::vector<Ghost> &ghosts, std::vector<People> &people, std::vector<Particle> *particles, sf::Font &GameFont, sf::RenderTexture *ghostBuffers) {

		//don't want to thrash the stack with the tail recursion
		static sf::Clock clock;
		static unsigned int SpawnTick = GHOST_SPAWN_MIN_TICKS+rand()%(GHOST_SPAWN_MAX_TICKS-GHOST_SPAWN_MIN_TICKS);
		static int HighScore = 0;
		static int ActiveScore = 0;
		static int LastHighScore = 0;
		static int GameTicks = 0;
		static int GameState = STATE_MENU;
		static std::vector<Ghost *> allGoodGhosts;
		static sf::Color gameOverTextColors[4] = {sf::Color(255, 0, 0), sf::Color(0, 255, 0), sf::Color(0, 0, 255), sf::Color(255, 200, 0)};
		static int gameOverColorIndex[2] = {0,1};
		static float gameOverColorFade = 0.0f;
		bool running = true;
		mousePosition = sf::Vector2u(screen.getSize().x/2, screen.getSize().y/2);

		//Game Text
		// Replacement for below..
		static sf::Text ScoreText, PlayText, gameOverText;
		ScoreText.setFont(GameFont);
		PlayText.setFont(GameFont);
		gameOverText.setFont(GameFont);
		PlayText.setString("Play");
		gameOverText.setString("\tGame Over!\nClick to play again");
		// Not really sure why these lines crash on me, but the above works fine and achieves the same thing, meh.
		//static sf::Text ScoreText("", GameFont);
		//static sf::Text PlayText("Play", GameFont);
		//Position PlayText
		sf::Rect<float> PlayBounds = PlayText.getLocalBounds();
		PlayText.setPosition(screen.getSize().x*0.5f-PlayBounds.width*0.5f, screen.getSize().y*0.5f-PlayBounds.height*0.5f);
		gameOverText.setPosition(screen.getSize().x*0.5f-gameOverText.getLocalBounds().width*0.5f, screen.getSize().y*0.5f-gameOverText.getLocalBounds().height*0.5f);
		static std::ostringstream ScoreString;
		ScoreText.setString(ScoreString.str());
		while(running){
			float deltaTime = clock.getElapsedTime().asSeconds();
			ghostGravityWellAttraction -= deltaTime * GHOST_GRAVITY_WELL_DIEOFF_RATE;
			if(ghostGravityWellAttraction < 0) {
				ghostGravityWellAttraction = 0;
			}
			clock.restart();

			sf::Event event;
			while (screen.pollEvent(event))
			{
				if (event.type == sf::Event::Closed)
				{
					running = false;
				}else
					if ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Escape))
					{
						running = false;
					}else
						if (event.type == sf::Event::MouseMoved)
						{
							mousePosition = sf::Vector2u(event.mouseMove.x, event.mouseMove.y);
							ghostGravityWellAttraction = 1;
						}else
							if(event.type == sf::Event::MouseButtonPressed){
								if(GameState==STATE_MENU && PlayText.getGlobalBounds().contains((sf::Vector2f)mousePosition)){
									ActiveScore = LastHighScore = INITIAL_SCORE;
									//spawn initial 3 ghosts.
									for(int i=0;i<3;i++) ghostAdd(ghosts, sf::Vector2f(screen.getSize().x*0.5f-20.0f+i*20.0f, screen.getSize().y*0.5f), sf::Vector2f(0.0f, 0.0f), texture, GOOD_MAXIMUM);
									//spawn a dude!
									peopleAdd(people, randomVector(sf::Vector2f(0.0f, 0.0f), (sf::Vector2f)(screen.getSize())), Person_ATex);
									GameState=STATE_PLAYING;
								}
								if (GameState == GameStateGameOver) {
									ActiveScore = INITIAL_SCORE;
									//spawn initial 3 ghosts.
									for(int i=0;i<3;i++) ghostAdd(ghosts, sf::Vector2f(screen.getSize().x*0.5f-20.0f+i*20.0f, screen.getSize().y*0.5f), sf::Vector2f(0.0f, 0.0f), texture, GOOD_MAXIMUM);
									//spawn a dude!
									peopleAdd(people, randomVector(sf::Vector2f(0.0f, 0.0f), (sf::Vector2f)(screen.getSize())), Person_ATex);
									GameState=STATE_PLAYING;

								}
							}
			}
			goto LABELB;
			position+=Velocity;
			if(position.x<0.0f){
				position.x = 0.0f;
				Velocity.x = -Velocity.x;
			}else if(position.x>=(float)(screen.getSize().x-image.getSize().x)){
				position.x = (float)(screen.getSize().x-image.getSize().x);
				Velocity.x = -Velocity.x;
			}
			if(position.y<0.0f){
				position.y = 0.0f;
				Velocity.y = -Velocity.y;
			}else if(position.y>=(float)(screen.getSize().y-image.getSize().y)){
				position.y = (float)(screen.getSize().y-image.getSize().y);
				Velocity.y = -Velocity.y;
			}
			sprite.setPosition(position);  //Good bye old crap.
LABELB:
			allGoodGhosts.clear();
			int goodGhosts = ghostAdvance(ghosts, allGoodGhosts, screen.getSize());
			updateBackground(background, deltaTime, goodGhosts);
			updateBackgroundGhosts(background, deltaTime);
			updateParticles(particles);

			screen.clear();
			drawBackground(screen, background);

			// Ping pong between ghost buffers
			pingPongGhostBuffers(ghostBuffers, sf::Color(255, 255, 255, 0));

			drawBackgroundGhosts(ghostBuffers[currentRenderTarget], background);
			//Let's draw particles here!
			goto LABELW;
LABELX:

			ghostBuffers[currentRenderTarget].display();
			drawTexture(screen, sf::Vector2f(0.0f, 0.0f), ghostBuffers[currentRenderTarget].getTexture());

			drawGhostDropShadows(screen, ghosts);


			goto LABELC;
			screen.draw(sprite);
LABELC:
			//draw people!
			for(size_t i=0;i<people.size();i++){
				float rad = people[i].radius;
				people[i].sprite.setPosition(people[i].position-sf::Vector2f(rad, rad));
				people[i].sprite.setScale((people[i].m_Flag&PERSON_FACE_LEFT)?-1.0f:1.0f, 1.0f);
				screen.draw(people[i].sprite);
			}

			//int GoodIncrement = 0;
			//int BadIncrement = 0;
			for(size_t i=0;i<ghosts.size();i++){
				double rad = ghosts[i].radius;
				ghosts[i].sprite.setPosition(ghosts[i].position-sf::Vector2f(rad, rad));
				ghosts[i].sprite.setColor(sf::Color(GOOD_MAXIMUM-ghosts[i].m_GoodAmnt, 0, ghosts[i].m_GoodAmnt, 25+ghosts[i].m_GoodAmnt * 4 % 231 ));
				screen.draw(ghosts[i].sprite);

				//Do score calculations!
				if(GameState==STATE_PLAYING) ActiveScore+=(ghosts[i].m_GoodAmnt>=GOOD_MINIMUM?GOOD_GHOST_SCORE_VALUE:-BAD_GHOST_SCORE_VALUE)*(ghosts[i].sprite.getScale().x+(ghosts[i].sprite.getScale().x-1.0f)*2.0f);
				else ghosts[i].scaleRate=-ghosts[i].sprite.getScale().x; //destroy all ghosts when in the menu
			}
			HighScore = ActiveScore>HighScore?ActiveScore:HighScore;
			LastHighScore = ActiveScore>LastHighScore?ActiveScore:LastHighScore;
			goto GAMEOVERCHECK;
			if(ActiveScore<=0) GameState=STATE_MENU;
GAMEOVERCHECK:
			if (ActiveScore <= 0) {
				for (int i=0;i<goodGhosts;++i) {
					allGoodGhosts[i]->m_GoodAmnt -= 2.0f*BAD_CONVERSION_RATE;
				}
				ActiveScore = 0;
			}
			if (GameState == GameStatePlaying && goodGhosts <= 0) GameState = GameStateGameOver;


			ScoreString.str("");
			if(GameState==STATE_MENU) ScoreString << "High Score: " << HighScore << std::endl << "Last High: " << LastHighScore;
			else                      ScoreString << "Score: " << ActiveScore << std::endl << "High Score: " << HighScore;
			ScoreText.setString(ScoreString.str());
			goto LABELG;
			if(rand()%50 == 0 || rand() % 60 >= 57) //decreased rate of spawning.
LABELG:
			if(GameState==STATE_MENU){
				if(PlayText.getGlobalBounds().contains((sf::Vector2f)mousePosition)) PlayText.setColor(sf::Color(255, 0, 0));
				else PlayText.setColor(sf::Color(255,255,255));
				screen.draw(PlayText);

			} else if (GameState == GameStateGameOver) {
				gameOverColorFade += 0.02f;
				if (gameOverColorFade >= 1.0f) {
					gameOverColorIndex[0] = gameOverColorIndex[1];
					int count;
					
					while ((gameOverColorIndex[1] = round(randomFloat()*3)) == gameOverColorIndex[0] && count++ < 10);
					gameOverColorFade = 0.0f;
				}
				sf::Color c = fadeColors(gameOverTextColors[gameOverColorIndex[0]], gameOverTextColors[gameOverColorIndex[1]], gameOverColorFade);
				gameOverText.setColor(c);
				screen.draw(gameOverText);

			}else{
				if(SpawnTick==0){
					ghostAdd(ghosts, randomVector(sf::Vector2f(0.0f, 0.0f), (sf::Vector2f)screen.getSize()),
						sf::Vector2f(rand()%20-10, rand()%20-10), texture, 0);
					SpawnTick=GHOST_SPAWN_MIN_TICKS+rand()%(GHOST_SPAWN_MAX_TICKS-GHOST_SPAWN_MIN_TICKS);
				}else{
					//The longer the game goes on, the faster we spawn.
					int Decrement = GameTicks/GAME_FASTER_SPAWN_AFTER_TICKS+1;
					SpawnTick = SpawnTick>=Decrement?SpawnTick-Decrement:0;
				}
			}
			GameTicks++;
			goto LABELY;
LABELW:
			drawParticles(&ghostBuffers[currentRenderTarget], *particles, particleTex);
			goto LABELX;
LABELY:
			screen.draw(ScoreText);

			screen.display();
		}

		if (running) {
			loop(screen, background, position, Velocity, image, sprite, texture, particleTex, Person_ATex, ghosts, people, particles, GameFont, ghostBuffers);
		}
}

#error "Be sure to add resources here!"
see attachment for full file.

also, video:

[media]http://youtu.be/yFFVGiGq5lI[/media] Edited by slicer4ever
0

Share this post


Link to post
Share on other sites

This seems to have fallen to just you and me slicer (mostly you haha).
 
Anyone else gona add more?


it seems that way. i'm surprised as their were a few others whom seem interested in the lounge thread, but haven't participated.
0

Share this post


Link to post
Share on other sites

Well. Looks like it's the end of the road for me. My graphics driver just doesn't appear to be able to handle the awesomeness of the game:

ray@ray ~/gdhorror $ ./main
radeon: The kernel rejected CS, see dmesg for more information.

Might try under Windows later on. FWIW, here's the error log:

[46854.343333] [drm:radeon_cs_parser_relocs] *ERROR* gem object lookup failed 0x16
[46854.343334] [drm:radeon_cs_ioctl] *ERROR* Failed to parse relocation -2!
[46854.343386] [drm:radeon_cs_parser_relocs] *ERROR* gem object lookup failed 0x16
[46854.343387] [drm:radeon_cs_ioctl] *ERROR* Failed to parse relocation -2!
[46854.343456] radeon 0000:01:00.0: evergreen_cs_track_validate_texture:886 mipmap [1] bo too small (layer size 16384, offset 65536, coffset 81920, max layer 1, depth 1, bo size 69632) level0 (128 128 1)
[46854.343458] radeon 0000:01:00.0: evergreen_cs_track_validate_texture:891 problematic surf: (64 64) (2 4 1 1 2 1024 2)
[46854.343458] [drm:radeon_cs_ib_chunk] *ERROR* Invalid command stream !
[46854.359960] radeon 0000:01:00.0: evergreen_cs_track_validate_texture:886 mipmap [1] bo too small (layer size 16384, offset 65536, coffset 81920, max layer 1, depth 1, bo size 69632) level0 (128 128 1)
[46854.359963] radeon 0000:01:00.0: evergreen_cs_track_validate_texture:891 problematic surf: (64 64) (2 4 1 1 2 1024 2)
[46854.359964] [drm:radeon_cs_ib_chunk] *ERROR* Invalid command stream !
[46854.360133] radeon 0000:01:00.0: evergreen_cs_track_validate_texture:886 mipmap [1] bo too small (layer size 1024, offset 65536, coffset 66560, max layer 1, depth 1, bo size 4096) level0 (32 32 1)
[46854.360135] radeon 0000:01:00.0: evergreen_cs_track_validate_texture:891 problematic surf: (16 16) (2 4 1 0 1 4 1)
[46854.360136] [drm:radeon_cs_ib_chunk] *ERROR* Invalid command stream !
[46854.360185] radeon 0000:01:00.0: evergreen_cs_track_validate_texture:835 texture bo too small (layer size 2293760, offset 0, max layer 1, depth 1, bo size 1048576) (896 640)
[46854.360186] [drm:radeon_cs_ib_chunk] *ERROR* Invalid command stream !
[46854.360261] radeon 0000:01:00.0: evergreen_cs_track_validate_texture:835 texture bo too small (layer size 2293760, offset 0, max layer 1, depth 1, bo size 4096) (896 640)
[46854.360262] [drm:radeon_cs_ib_chunk] *ERROR* Invalid command stream !

It's probably just to do with the fact that I don't have hardware acceleration on this box, though I don't know why it worked before, a recent commit must've killed it.

Edited by Bacterius
0

Share this post


Link to post
Share on other sites

Quick question: Anyone have this stored in a version control system, like Git or SVN? It may be possible that within 2 posts, there may be many additional edits/changes that we may not know of.

0

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0