#include "stdafx.h" Game_overwatch::Game_overwatch(){ //Initialize our population head = NULL; population = 0; } void Game_overwatch::move_out(Actor *npc){ //Moving out means killing a citizen from the citizen linked list. citizen *curr, *prev; prev = NULL; for(curr=head;curr!=NULL;prev=curr,curr=curr->next){ if (curr->val == npc) { if (prev == NULL) { head = curr->next; std::cout << "I have deleted an NPC from the top!\n"; } else { prev->next = curr->next; std::cout << "I have deleted an NPC from the middle!\n"; } delete curr; } } population--; } void Game_overwatch::move_in(Actor * npc){ //Moving in means adding a citizen to the linkd list. citizen *curr; curr = new citizen; curr->val = npc; curr->next = head; head=curr; population++; } int Game_overwatch::get_population(){ return population; } void Game_overwatch::draw(SDL_Surface *viewport, Map *mainmap){ //Generic draw function, iterates over the list and draws //each one of them. //NOTE: Further along it may be wise to allow Lua scripts to // override the draw function and just call curr->draw(); citizen *curr; curr = head; while (curr != NULL){ Gfx::drawsurface(curr->val->get_clip_x(),curr->val->get_clip_y(), curr->val->get_w(),curr->val->get_h(), curr->val->get_sprite(), curr->val->get_x()-mainmap->get_sx(),curr->val->get_y()-mainmap->get_sy(), viewport); curr = curr->next; } } void Game_overwatch::act(SDL_Surface *viewport, Map *mainmap, bool keys[323]){ //Iterates over the list and runs the "act" function from the lua script. citizen *curr; curr = head; while (curr != NULL){ curr->val->move(); handleinput(curr->val, keys); //do the lua thing. curr->val->SelectScriptFunction ("act"); curr->val->Go (); curr = curr->next; } } void Game_overwatch::handleinput(Actor *actor, bool keys[323]){ //Right now these actions just map keys to variables the scripts can use //In the future it will be wise to abstract the keys to what they do //Also, take into account gamepads. //Preferably, let lua handle this somehow. if(keys[SDLK_LEFT]){ if(leftkey == 0){ leftkey = SDL_GetTicks(); } }else{ leftkey = 0; } if(keys[SDLK_RIGHT]){ if(rightkey == 0){ rightkey = SDL_GetTicks(); } }else{ rightkey = 0; } if(keys[SDLK_z]){ if(zkey == 0){ zkey = SDL_GetTicks(); } }else{ zkey = 0; } if(keys[SDLK_x]){ if(xkey == 0){ xkey = SDL_GetTicks(); } }else{ xkey = 0; } if(keys[SDLK_c]){ if(ckey == 0){ ckey = SDL_GetTicks(); } }else{ ckey = 0; } actor->set_leftkey(leftkey); actor->set_rightkey(rightkey); actor->set_zkey(zkey); actor->set_xkey(xkey); actor->set_ckey(ckey); } void Game_overwatch::animate(){ //Iterate and run the animate method. citizen *curr; curr = head; while (curr != NULL){ curr->val->animate(); curr = curr->next; } } void Game_overwatch::check_collisions(Map *mainmap){ citizen *curr, *others; bool collided = false; curr = head; others = head->next; Actor *ac1, *ac2; //now check everyone. Never with itself. //It does line collisions, not corner collisions. while (curr != NULL){ ac1 = curr->val; while (others != NULL) { ac2 = others->val; collided = false; if (curr->val != others->val) { if(Game_overwatch::line_colliding(ac1->get_x(), ac1->get_w(), ac1->get_y(), ac1->get_h(), ac2->get_x(), ac2->get_w(), ac2->get_y(), ac2->get_h(), UP)){ ac2->set_collision(true, DOWN); ac2->set_speed(ac1->get_ownspeed()); ac2->set_vertical_speed(ac2->get_vertical_speed()+ac1->get_vertical_speed()); ac1->set_collision(true, UP); collided = true; } if(Game_overwatch::line_colliding(ac1->get_x(), ac1->get_w(), ac1->get_y(), ac1->get_h(), ac2->get_x(), ac2->get_w(), ac2->get_y(), ac2->get_h(), DOWN)){ ac2->set_collision(true, UP); ac1->set_collision(true, DOWN); collided = true; } if(Game_overwatch::line_colliding(ac1->get_x(), ac1->get_w(), ac1->get_y(), ac1->get_h(), ac2->get_x(), ac2->get_w(), ac2->get_y(), ac2->get_h(), LEFT)){ ac2->set_collision(true, RIGHT); ac1->set_collision(true, LEFT); collided = true; } if(Game_overwatch::line_colliding(ac1->get_x(), ac1->get_w(), ac1->get_y(), ac1->get_h(), ac2->get_x(), ac2->get_w(), ac2->get_y(), ac2->get_h(), RIGHT)){ ac2->set_collision(true, LEFT); ac1->set_collision(true, RIGHT); collided = true; } } others = others->next; if(collided){ collision_callback(ac1, ac2); } } curr = curr->next; if (curr != NULL){ others = curr->next; } } } void Game_overwatch::collision_callback(Actor *ac1, Actor *ac2){ std::cout << "The collision has called "; if (ac1->get_enemy() == WEAPON && !ac2->get_dying()) { if (ac2->get_enemy() == EVIL) { ac1->set_dying(true); ac2->set_dying(true); std::cout << "And the shot has destroyed the enemy."; } } if (ac1->get_enemy() == SUPEREVIL) { ac2->set_dying(true); std::cout << "And the shot has destroyed the enemy."; } if (ac1->get_controllable()) { if (ac2->get_enemy() == EVIL) { ac1->set_dying(true); std::cout << "And the enemy has destroyed the main actor."; } } if (ac1->get_enemy() == EVIL) { if (ac2->get_controllable()) { ac2->set_dying(true); std::cout << "And the enemy has destroyed the main actor."; } } std::cout << "\n"; } bool Game_overwatch::line_colliding(int x1, int w1, int y1, int h1, int x2, int w2, int y2, int h2, int direction){ switch (direction) { case UP: if (y1 <= y2+h2 && y1 >= y2+(h2/2) && ((x1 > x2 && x1 < x2+w2) || (x1+w1 > x2 && x1+w2 < x2+w2))) { std::cout << "Foo' is collidin' top\n"; return true; } break; case DOWN: if (y1+h1 >= y2 && y1+h1 <= y2+(h2/2) && ((x1 > x2 && x1 < x2+w2) || (x1+w1 > x2 && x1+w2 < x2+w2))) { std::cout << "Foo' is collidin' bottom\n"; return true; } break; case LEFT: if (x1 <= x2+w2 && x1 >= x2+(w2/2) && ((y1 > y2 && y1 < y2+h2) || (y1+h1 > y2 && y1+h1 < y2+h2))) { std::cout << "Foo' is collidin' left\n"; return true; } break; case RIGHT: if (x1+w1 >= x2 && x1+w1 <= x2+(w2/2) && ((y1 > y2 && y1 < y2+h2) || (y1+h1 > y2 && y1+h1 < y2+h2))) { std::cout << "Foo' is collidin' right\n"; return true; } break; } return false; } void Game_overwatch::handlephysics(Map *mainmap, int ticks1, int ticks2){ citizen *curr; curr = head; while (curr != NULL){ //some are not affected by physics. if(curr->val->get_physics()){ //can it fall? if(curr->val->can_move(DOWN, curr->val->get_x(), curr->val->get_y())){ //change sprite to its jump. switch(curr->val->get_oldclip()){ case 1: curr->val->set_clip_y(curr->val->get_h()*0); break; case 2: curr->val->set_clip_y(curr->val->get_h()*3); break; } //start the fall process if(curr->val->get_falltime() == 0){ curr->val->set_falltime(.5); }else{ curr->val->set_falltime(curr->val->get_falltime()+(ticks2-ticks1)/1000); } }else{ //stop falling. curr->val->set_clip_y(curr->val->get_h()*curr->val->get_oldclip()); curr->val->set_falltime(0); if(curr->val->get_vertical_speed() > 0){ curr->val->set_vertical_speed(0); } } //check for top collision if( !curr->val->can_move(UP, curr->val->get_x(), curr->val->get_y()) && curr->val->get_vertical_speed() < 0){ curr->val->set_vertical_speed(0); } //Avoid falling through the ground while(!curr->val->can_move(DOWN, curr->val->get_x(), curr->val->get_y()+curr->val->get_vertical_speed()) && curr->val->get_vertical_speed() > 0){ curr->val->set_vertical_speed( curr->val->get_vertical_speed() - 1 ); } //V=Vo+at curr->val->set_vertical_speed( curr->val->get_vertical_speed() + (GRAVITY*curr->val->get_falltime())); //translate. curr->val->set_y( curr->val->get_y() + curr->val->get_vertical_speed()); } //NEXT curr = curr->next; } } void Game_overwatch::reset_collisions(){ citizen *curr; curr = head; while (curr != NULL){ curr->val->set_collision(false, LEFT); curr->val->set_collision(false, RIGHT); curr->val->set_collision(false, DOWN); curr->val->set_collision(false, UP); curr = curr->next; } } void Game_overwatch::dieloop(){ //The kill loop: // Every frame, we find out who needs to be killed // We kill them all. citizen *curr; curr = head; while (curr != NULL){ bool killthis = false; if ( curr->val->get_dying() ){ killthis = true; } if (killthis){ Actor *victim = curr->val; curr = curr->next; this->kill(victim); }else{ curr = curr->next; } } } void Game_overwatch::kill(Actor *actor){ //This should probably delegate to the lua die function //So it can animate/change states. if ( actor->get_controllable() ){ actor->set_x(50); actor->set_y(100); actor->set_dying(false); }else{ delete actor; actor = NULL; } }