304 lines
9.0 KiB
C
304 lines
9.0 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <math.h>
|
|
#include <stdbool.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <limits.h>
|
|
#include <time.h>
|
|
#include <sys/time.h>
|
|
#include <SDL2/SDL.h>
|
|
#include <SDL2/SDL_image.h>
|
|
|
|
#include "structure.h"
|
|
#include "base.h"
|
|
#include "music.h"
|
|
#include "display.h"
|
|
#include "collisions.h"
|
|
#include "rooms.h"
|
|
#include "cars.h"
|
|
|
|
bool WAIT = true;
|
|
bool SHOW = true;
|
|
bool matchDone = false;
|
|
|
|
bool noise = true;
|
|
|
|
FILE* save;
|
|
|
|
void cameraActions(level* lvl, bool* halt, int* cx, int* cy, int* dezoom, int* sizeR) {
|
|
SDL_Event event;
|
|
while(SDL_PollEvent(&event)) {
|
|
switch (event.type) {
|
|
case SDL_QUIT:
|
|
break;
|
|
case SDL_KEYDOWN:
|
|
switch (event.key.keysym.sym) {
|
|
case SDLK_SPACE:
|
|
*halt = true;
|
|
break;
|
|
|
|
case SDLK_q:
|
|
*cy = max(0, *cy-1);
|
|
break;
|
|
|
|
case SDLK_z:
|
|
*cx = max(0, *cx-1);
|
|
break;
|
|
|
|
case SDLK_d:
|
|
*cy = min(lvl->cols-1, *cy+1);
|
|
break;
|
|
|
|
case SDLK_s:
|
|
*cx = min(lvl->lines-1, *cx+1);
|
|
break;
|
|
|
|
case SDLK_p:
|
|
*dezoom = max(1, *dezoom-1);
|
|
*sizeR = min(WIDTH, HEIGHT)/(2*(*dezoom)+1)+1;
|
|
break;
|
|
|
|
case SDLK_m:
|
|
*dezoom = min(3, *dezoom+1);
|
|
*sizeR = min(WIDTH, HEIGHT)/(2*(*dezoom)+1)+1;
|
|
break;
|
|
|
|
case SDLK_TAB:
|
|
WAIT = !WAIT;
|
|
break;
|
|
|
|
case SDLK_LSHIFT:
|
|
SHOW = !SHOW;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
double playerSpeedModifier(int nPl) {
|
|
// gives players a speed boost/penalty depending on their position
|
|
// -12% if in the lead, and +12% if last
|
|
if(maxRemD-minRemD >= 0.0001) {
|
|
double theta = (remainingD[nPl]-minRemD)/(maxRemD-minRemD);
|
|
//printf("%lf\n", theta);
|
|
return (1.0 + (24.0*theta-12.0)/100.0);
|
|
} else {
|
|
return 1.0;
|
|
}
|
|
}
|
|
|
|
void player_turn(int id, char* exec) {
|
|
if(noise) {
|
|
system(exec);
|
|
FILE* ptr = fopen("answer.txt", "r");
|
|
int angle, mult;
|
|
fscanf(ptr, "%d %d", &angle, &mult);
|
|
fclose(ptr);
|
|
double dvx = 1.0+(rand()%200-100)/100.0*(DELTA_V/100.0);
|
|
double dvy = 1.0+(rand()%200-100)/100.0*(DELTA_V/100.0);
|
|
double psm = playerSpeedModifier(id);
|
|
double dtheta = (rand()%200-100)*DELTA_THETA/100.0;
|
|
set_speed_car(players[id].c,
|
|
psm*dvx*MAX_SPEED*(mult)/100.0*cos((angle+dtheta)*3.14159/180.0),
|
|
psm*dvy*MAX_SPEED*(mult)/100.0*sin((angle+dtheta)*3.14159/180.0)
|
|
);
|
|
fprintf(save, "%lf %lf\n",
|
|
psm*dvx*MAX_SPEED*(mult)/100.0*cos((angle+dtheta)*3.14159/180.0),
|
|
psm*dvy*MAX_SPEED*(mult)/100.0*sin((angle+dtheta)*3.14159/180.0)
|
|
);
|
|
} else {
|
|
double vx, vy;
|
|
fscanf(save, "%lf %lf", &vx, &vy);
|
|
set_speed_car(players[id].c, vx, vy);
|
|
}
|
|
}
|
|
|
|
void parse_all_players(level* lvl, char** execs) {
|
|
currentTurn += 1;
|
|
for(int p = 0; p < nPlayers; p++) {
|
|
if(0==winners[p]) {
|
|
write_output("output.txt", lvl, p);
|
|
if(WAIT)usleep(1000000/10);
|
|
player_turn(p, execs[p]);
|
|
}
|
|
}
|
|
}
|
|
|
|
int main(int argc, char** argv) {
|
|
if(argc < 2) {
|
|
fprintf(stderr, "usage : ./back <level_path> <P1 executable> <P2 executable> ...\n");
|
|
exit(1);
|
|
}
|
|
|
|
int offsetP = 0;
|
|
if(argv[2][0] == 'R' && argv[2][1] == 'E' && argv[2][2] == 'P' && argv[2][3] == '\0') {
|
|
// replay mode
|
|
noise = false;
|
|
printf("---------------------------\n");
|
|
printf("--| Replay mode enabled |--\n");
|
|
printf("---------------------------\n");
|
|
offsetP = 1;
|
|
save = fopen("lastActions.txt", "r");
|
|
} else {
|
|
save = fopen("lastActions.txt", "w");
|
|
}
|
|
|
|
int N_PLAYERS = argc-2-offsetP;
|
|
|
|
char** execs = malloc(sizeof(char*)*N_PLAYERS);
|
|
int* ranks = malloc(sizeof(int)*N_PLAYERS);
|
|
for(int k = 0; k < N_PLAYERS; k++) {
|
|
ranks[k] = N_PLAYERS;
|
|
execs[k] = malloc(sizeof(char)*64);
|
|
execs[k][0] = '.';
|
|
execs[k][1] = '/';
|
|
int i = 2;
|
|
while(i-2 < 64 && argv[k+2+offsetP][i-2] != '\0') {
|
|
execs[k][i] = argv[k+2+offsetP][i-2];
|
|
i += 1;
|
|
}
|
|
execs[k][i] = '\0';
|
|
}
|
|
|
|
for(int k = 0; k < N_PLAYERS; k++) {
|
|
printf("[%d] %s\n", k, execs[k]);
|
|
}
|
|
|
|
double elapsed = 0.0;
|
|
bool halt = false;
|
|
srand(time(NULL));
|
|
if (SDL_Init(SDL_INIT_EVERYTHING) != 0) {
|
|
printf("error initializing SDL: %s\n", SDL_GetError());
|
|
}
|
|
SDL_Window* win = SDL_CreateWindow("Game",
|
|
SDL_WINDOWPOS_CENTERED,
|
|
SDL_WINDOWPOS_CENTERED,
|
|
WIDTH, HEIGHT, 0);
|
|
|
|
Uint32 render_flags = SDL_RENDERER_ACCELERATED;
|
|
SDL_Renderer* rend = SDL_CreateRenderer(win, -1, render_flags);
|
|
SDL_SetRenderDrawBlendMode(rend, SDL_BLENDMODE_BLEND);
|
|
|
|
import_letters(rend);
|
|
import_digits(rend);
|
|
init_music();
|
|
// ---------------------------- //
|
|
//stage_file("levels/stage.txt");
|
|
level* stage = parse_level(argv[1]);
|
|
init_all(N_PLAYERS);
|
|
printf("\n");
|
|
path* pth = getPath(stage);
|
|
printLvl(stage);
|
|
printPath(pth);
|
|
|
|
printf("Starting direction : ");
|
|
if(START_DIR == 0) {
|
|
printf("North\n");
|
|
} else if(START_DIR == 1) {
|
|
printf("East\n");
|
|
} else if(START_DIR == 2) {
|
|
printf("South\n");
|
|
} else if(START_DIR == 3) {
|
|
printf("West\n");
|
|
} else {
|
|
printf("???\n");
|
|
}
|
|
printf("From (%d %d) to (%d %d)\n", START_CHX, START_CHY, FINISH_CHX, FINISH_CHY);
|
|
|
|
int cx = START_CHX;
|
|
int cy = START_CHY;
|
|
int dezoom = 2;
|
|
int sizeR = 200;
|
|
|
|
int count = 0;
|
|
while(!halt) {
|
|
resetRenderer(rend);
|
|
minRemD = 999999.0;
|
|
maxRemD = 0.0;
|
|
renderMap(rend, stage, pth, cx, cy, dezoom, sizeR, SHOW);
|
|
for(int p = 0; p < N_PLAYERS; p++) {
|
|
pt proj = project(p, cx, cy, dezoom, sizeR);
|
|
drawStringToRenderer(rend, &(execs[p][1]), proj.ix, proj.iy, 75/(4+dezoom), 105/(4+dezoom));
|
|
}
|
|
if(elapsed <= 0.7) {
|
|
// just selected speeds
|
|
for(int p = 0; p < N_PLAYERS; p++) {
|
|
pt proj = project(p, cx, cy, dezoom, sizeR);
|
|
double nm = sqrt(proj.ix*1.0*proj.ix + proj.iy*1.0*proj.iy);
|
|
drawLineWithThicc(rend, 2,
|
|
proj.ix,
|
|
proj.ix+(int)(players[p].c->vel.fx/5.0*(nm+PLAYER_R)/nm),
|
|
proj.iy,
|
|
proj.iy+(int)(players[p].c->vel.fy/5.0*(nm+PLAYER_R)/nm),
|
|
players[p].rgb.red, players[p].rgb.green, players[p].rgb.blue, 255
|
|
);
|
|
}
|
|
placeRectToRenderer(rend, 0, HEIGHT-50, 50, 50, 255, 255, 32, 192);
|
|
} else if(updateCars(stage)) {
|
|
// movement
|
|
placeRectToRenderer(rend, 0, HEIGHT-50, 50, 50, 32, 255, 32, 192);
|
|
} else {
|
|
// no movement
|
|
placeRectToRenderer(rend, 0, HEIGHT-50, 50, 50, 255, 32, 32, 192);
|
|
updateWins(ranks);
|
|
if(remainingTurns != 0)parse_all_players(stage, execs);
|
|
if(remainingTurns > 0) {
|
|
remainingTurns -= 1;
|
|
if(remainingTurns == 0) {
|
|
matchDone = true;
|
|
//halt = true;
|
|
}
|
|
}
|
|
elapsed = 0.0;
|
|
}
|
|
if(!noise) {
|
|
drawStringToRenderer(rend, "replay", 10, HEIGHT-75, 75/3, 105/3);
|
|
}
|
|
if(remainingTurns >= 0) {
|
|
draw7SegNumberToRenderer(rend, remainingTurns, WIDTH/2, HEIGHT-75, 25, 25, 3, 255, 32, 32, 255, 0, 0);
|
|
} else {
|
|
draw7SegNumberToRenderer(rend, currentTurn, WIDTH/2, HEIGHT-75, 25, 25, 3, 255, 255, 255, 255, 0, 0);
|
|
}
|
|
updateRenderer(rend);
|
|
elapsed += DT;
|
|
if(WAIT && count%3==0)usleep((int)(1000000*DT));
|
|
cameraActions(stage, &halt, &cx, &cy, &dezoom, &sizeR);
|
|
count += 1;
|
|
}
|
|
|
|
if(matchDone && noise)updateLeaderBoard(execs, ranks);
|
|
// ---------------------------- //
|
|
free_digits(digits);
|
|
free_digits(letters);
|
|
free_level(stage);
|
|
freePath(pth);
|
|
fclose(save);
|
|
end_music();
|
|
for(int k = 0; k < N_PLAYERS; k++) {
|
|
free(execs[k]);
|
|
}
|
|
free(execs);
|
|
free(remainingD);
|
|
free(ranks);
|
|
|
|
SDL_DestroyRenderer(rend);
|
|
SDL_DestroyWindow(win);
|
|
SDL_Quit();
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
TODO :
|
|
- add level generation
|
|
- check seg faults
|
|
+ add items
|
|
+ add hazards
|
|
|
|
KNOWN ISSUES :
|
|
- car can sometimes clip into walls (rare, seems turn-related)
|
|
*/ |