MarioPartyMaker/src/edit.c

535 lines
19 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <math.h>
#include <stdbool.h>
#include <ncurses.h>
#include <unistd.h>
#include <termios.h>
#include <limits.h>
#include <time.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include "consts.h"
#include "base.h"
#include "display.h"
#include "edit.h"
int edit_cell_count = 2;
cell** all_loaded_cells;
int n_loaded = -1;
int zoom_factor = 200 ;
void link_cells(cell* parent, cell* child) {
if(parent != NULL) {
if(parent->next_1 == NULL) {
parent->next_1 = child;
} else if(parent->next_2 == NULL) {
parent->next_2 = child;
} else if(parent->next_3 == NULL) {
parent->next_3 = child;
} else if(parent->next_4 == NULL) {
parent->next_4 = child;
} else {
fprintf(stderr, "Unable to link cell : parent is at full capacity.\n");
}
};
if(child != NULL) {
if(child->prev_1 == NULL) {
child->prev_1 = parent;
} else if(child->prev_2 == NULL) {
child->prev_2 = parent;
} else if(child->prev_3 == NULL) {
child->prev_3 = parent;
} else if(child->prev_4 == NULL) {
child->prev_4 = parent;
} else {
fprintf(stderr, "Unable to link cell : child is at full capacity.\n");
}
}
}
void unlink_cells(cell* parent, cell* child) {
if(parent != NULL) {
if(parent->next_1 == child) {
parent->next_1 = NULL;
} else if(parent->next_2 == child) {
parent->next_2 = NULL;
} else if(parent->next_3 == child) {
parent->next_3 = NULL;
} else if(parent->next_4 == child) {
parent->next_4 = NULL;
} else {
fprintf(stderr, "Unable to unlink cell : no link found.\n");
}
};
if(child != NULL) {
if(child->prev_1 == parent) {
child->prev_1 = NULL;
} else if(child->prev_2 == parent) {
child->prev_2 = NULL;
} else if(child->prev_3 == parent) {
child->prev_3 = NULL;
} else if(child->prev_4 == parent) {
child->prev_4 = NULL;
} else {
fprintf(stderr, "Unable to unlink cell : no link found.\n");
}
};
}
cell* redirect_cell(cell* cl) {
if(cl != NULL) {
if(cl->prev_1 != NULL) {
return cl->prev_1;
} else if(cl->prev_2 != NULL) {
return cl->prev_2;
} else if(cl->prev_3 != NULL) {
return cl->prev_3;
} else if(cl->prev_4 != NULL) {
return cl->prev_4;
} else {
fprintf(stderr, "Unable to redirect cell : no parent.\n");
}
}
}
void append_cell(int cell_type, int X, int Y, cell* parent) {
cell* new = malloc(sizeof(cell));
new->id = parent->id; // mostly for parkour
new->unique_id = edit_cell_count;
new->coord_x = X;
new->coord_y = Y;
new->star_allowed = is_star_allowed(cell_type);
new->type = (CELLTYPE)cell_type ;
new->prev_1 = NULL ;
new->prev_2 = NULL;
new->prev_3 = NULL;
new->prev_4 = NULL;
new->next_1 = NULL;
new->next_2 = NULL;
new->next_3 = NULL;
new->next_4 = NULL;
char* meta = "none";
edit_cell_count += 1;
link_cells(parent, new);
cell_count[cell_type] += 1;
}
void append_cell_orthogonal(int cell_type, char dir, cell* parent) {
if(dir == 'N' || dir == 'n') {
append_cell(cell_type, parent->coord_x, parent->coord_y + tile_size * 2, parent);
} else if(dir == 'E' || dir == 'e') {
append_cell(cell_type, parent->coord_x + tile_size * 2, parent->coord_y, parent);
} else if(dir == 'W' || dir == 'w') {
append_cell(cell_type, parent->coord_x - tile_size * 2, parent->coord_y, parent);
} else if(dir == 'S' || dir == 's') {
append_cell(cell_type, parent->coord_x, parent->coord_y - tile_size * 2, parent);
} else {
fprintf(stderr, "ERROR : invalid direction (%d)", dir);
}
}
void destroy_cell() {
cell* new_current = redirect_cell(current);
unlink_cells(current, current->next_1);
unlink_cells(current, current->next_2);
unlink_cells(current, current->next_3);
unlink_cells(current, current->next_4);
unlink_cells(current->prev_1, current);
unlink_cells(current->prev_2, current);
unlink_cells(current->prev_3, current);
unlink_cells(current->prev_4, current);
cell_count[(int)current->type] -= 1;
free(current);
current = new_current ;
}
bool isAdding = false ;
int editBuffer = 0 ;
int phase = 0 ;
int editCellType = 0 ;
int editDirection = 0 ;
// -------------------------------- //
bool isLinking = false ;
cell* par ;
cell* chd ;
// -------------------------------- //
bool confirmRemove = false ;
bool cooldownRemove = false ;
void playerEditActions(bool* finished) {
SDL_Event event;
while(SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_QUIT:
break;
case SDL_KEYDOWN:
if(cooldownRemove) {
cooldownRemove = false;
} else {
confirmRemove = false ;
};
switch (event.key.keysym.sym) {
case SDLK_1:
if(!isAdding && current->next_1 != NULL) {
current = current->next_1;
} else if (isAdding) {
editBuffer *= 10;
editBuffer += 1;
};
break;
case SDLK_2:
if(!isAdding && current->next_2 != NULL) {
current = current->next_2;
} else if (isAdding) {
editBuffer *= 10;
editBuffer += 2;
};
break;
case SDLK_3:
if(!isAdding && current->next_3 != NULL) {
current = current->next_3;
} else if (isAdding) {
editBuffer *= 10;
editBuffer += 3;
};
break;
case SDLK_4:
if(!isAdding && current->next_4 != NULL) {
current = current->next_4;
} else if (isAdding) {
editBuffer *= 10;
editBuffer += 4;
};
break;
case SDLK_0:
if(!isAdding && current->prev_1 != NULL) {
current = current->prev_1;
} else if (isAdding) {
editBuffer *= 10;
};
break;
case SDLK_9:
if(!isAdding && current->prev_2 != NULL) {
current = current->prev_2;
} else if (isAdding) {
editBuffer *= 10;
editBuffer += 9;
};
break;
case SDLK_8:
if(!isAdding && current->prev_3 != NULL) {
current = current->prev_3;
} else if (isAdding) {
editBuffer *= 10;
editBuffer += 8;
};
break;
case SDLK_7:
if(!isAdding && current->prev_4 != NULL) {
current = current->prev_4;
} else if (isAdding) {
editBuffer *= 10;
editBuffer += 7;
};
break;
case SDLK_6:
if (isAdding) {
editBuffer *= 10;
editBuffer += 6;
};
break;
case SDLK_5:
if (isAdding) {
editBuffer *= 10;
editBuffer += 5;
};
break;
case SDLK_BACKSPACE:
if (isAdding) {
editBuffer = editBuffer / 10;
};
break;
case SDLK_SPACE:
if(isAdding) {
if(phase == 0) {
editCellType = editBuffer%n_cell_type;
} else if(phase == 1) {
editDirection = editBuffer%4;
phase = -1;
isAdding = false;
char dir ;
if(editDirection == 0) {
dir = 's';
} else if(editDirection == 1) {
dir = 'e';
} else if(editDirection == 2) {
dir = 'n';
} else if(editDirection == 3) {
dir = 'w';
};
append_cell_orthogonal(editCellType, dir, current);
};
phase += 1;
editBuffer = 0;
}
else if(isLinking) {
if(phase == 0) {
par = current ;
} else if(phase == 1) {
if(current != par) {
chd = current;
link_cells(par, chd);
phase = -1;
isLinking = false;
} else {
phase -= 1;
}
};
phase += 1;
};
break;
case SDLK_p:
if(!isLinking) {
isAdding = true ;
phase = 0 ;
printf("now adding...\n");
};
break;
case SDLK_l:
if(!isAdding) {
isLinking = true;
phase = 0 ;
printf("now linking...\n");
};
break;
case SDLK_r:
if(!confirmRemove) {
confirmRemove = true ;
cooldownRemove = true ;
} else {
destroy_cell();
confirmRemove = false ;
cooldownRemove = false ;
};
break;
case SDLK_TAB:
if(isAdding || isLinking || confirmRemove) {
isAdding = false;
isLinking = false;
confirmRemove = false;
cooldownRemove = false ;
} else {
*finished = true;
};
break;
case SDLK_s:
save("level.csv");
printf("Saved level\n");
break;
case SDLK_q:
load("level.csv");
printf("loaded level\n");
break;
case SDLK_F2:
zoom_factor = min(zoom_factor + 50, 1250) ;
break;
case SDLK_F3:
zoom_factor = max(zoom_factor - 50, 50) ;
break;
case SDLK_e:
current->type = (CELLTYPE)(((int)current->type +1)%n_cell_type);
break;
}
}
}
}
void draw_types(SDL_Renderer* renderer) {
drawStringToRenderer(renderer, letters, "start", __width__ - 6 * 75/2, 50, 75/2, 105/2);
drawStringToRenderer(renderer, letters, "blue", __width__ - 5 * 75/2, 100, 75/2, 105/2);
drawStringToRenderer(renderer, letters, "red", __width__ - 4 * 75/2, 150, 75/2, 105/2);
drawStringToRenderer(renderer, letters, "event", __width__ - 6 * 75/2, 200, 75/2, 105/2);
drawStringToRenderer(renderer, letters, "vs", __width__ - 3 * 75/2, 250, 75/2, 105/2);
drawStringToRenderer(renderer, letters, "bowser", __width__ - 7 * 75/2, 300, 75/2, 105/2);
drawStringToRenderer(renderer, letters, "chance", __width__ - 7 * 75/2, 350, 75/2, 105/2);
drawStringToRenderer(renderer, letters, "boo", __width__ - 4 * 75/2, 400, 75/2, 105/2);
drawStringToRenderer(renderer, letters, "star", __width__ - 5 * 75/2, 450, 75/2, 105/2);
drawStringToRenderer(renderer, letters, "bank", __width__ - 5 * 75/2, 500, 75/2, 105/2);
drawStringToRenderer(renderer, letters, "shop", __width__ - 5 * 75/2, 550, 75/2, 105/2);
}
void draw_directions(SDL_Renderer* renderer) {
drawStringToRenderer(renderer, letters, "north", __width__ - 6 * 75/2, 50, 75/2, 105/2);
drawStringToRenderer(renderer, letters, "east", __width__ - 5 * 75/2, 100, 75/2, 105/2);
drawStringToRenderer(renderer, letters, "south", __width__ - 6 * 75/2, 150, 75/2, 105/2);
drawStringToRenderer(renderer, letters, "west", __width__ - 5 * 75/2, 200, 75/2, 105/2);
}
void edit_main(SDL_Renderer* renderer) {
bool finished = false;
while(!finished) {
resetRenderer(renderer);
draw_board(renderer, current->coord_x - zoom_factor, current->coord_x + zoom_factor, current->coord_y - zoom_factor, current->coord_y + zoom_factor, current);
if(isAdding) {
drawStringToRenderer(renderer, letters, "add cell", 50, __height__ - 50, 75/2, 105/2);
if(phase == 0) {
drawStringToRenderer(renderer, letters, "choose type", 50, 50, 75/2, 105/2);
draw_types(renderer);
} else {
drawStringToRenderer(renderer, letters, "choose direction", 50, 50, 75/2, 105/2);
draw_directions(renderer);
};
drawNumberToRenderer(renderer, digits, editBuffer, 50, 150, 75/2, 105/2, 0);
}
else if(isLinking) {
drawStringToRenderer(renderer, letters, "link cells", 50, __height__ - 50, 75/2, 105/2);
if(phase == 0) {
drawStringToRenderer(renderer, letters, "choose parent", 50, 50, 75/2, 105/2);
} else {
drawStringToRenderer(renderer, letters, "choose child", 50, 50, 75/2, 105/2);
}
} else if(confirmRemove) {
drawStringToRenderer(renderer, letters, "press r again to remove", 50, __height__ - 50, 75/2, 105/2);
};
updateRenderer(renderer);
playerEditActions(&finished);
usleep(20000);
}
}
// save/load level
void reassign_id_cell(cell* cl, int* current, int common) {
if(cl != NULL && cl->id != 60000) {
cl->unique_id = *current;
*current += 1;
cl->id = 60000;
reassign_id_cell(cl->next_1, current, common);
reassign_id_cell(cl->next_2, current, common);
reassign_id_cell(cl->next_3, current, common);
reassign_id_cell(cl->next_4, current, common);
}
}
void reassign_ids() {
int p = 1 ;
reassign_id_cell(start, &p, start->id);
}
void write_cell(FILE* ptr, cell* cl, int global_id) {
if(cl != NULL && cl->id == global_id) {
printf("saving cell %d\n", cl->unique_id);
cl->id = global_id+1;
fprintf(ptr, "%d,%d,%d,%d,%d[", cl->unique_id, (int)cl->type, cl->coord_x, cl->coord_y, (int)cl->star_allowed);
printf("%d,%d,%d,%d,%d[", cl->unique_id, (int)cl->type, cl->coord_x, cl->coord_y, (int)cl->star_allowed);
if(cl->next_1 != NULL) {
fprintf(ptr, "%d,", cl->next_1->unique_id);
printf("%d,", cl->next_1->unique_id);
};
if(cl->next_2 != NULL) {
fprintf(ptr, "%d,", cl->next_2->unique_id);
printf("%d,", cl->next_2->unique_id);
};
if(cl->next_3 != NULL) {
fprintf(ptr, "%d,", cl->next_3->unique_id);
printf("%d,", cl->next_3->unique_id);
};
if(cl->next_4 != NULL) {
fprintf(ptr, "%d,", cl->next_4->unique_id);
printf("%d,", cl->next_4->unique_id);
};
fprintf(ptr, "]\n");
printf("]\n");
write_cell(ptr, cl->next_1, global_id);
write_cell(ptr, cl->next_2, global_id);
write_cell(ptr, cl->next_3, global_id);
write_cell(ptr, cl->next_4, global_id);
}
}
void save(char* filename) {
reassign_ids();
FILE* ptr = fopen(filename, "w");
write_cell(ptr, start, start->id);
fclose(ptr);
}
// fprintf(ptr, "%d,%d,%d,%d,%d[", cl->unique_id, (int)cl->type, cl->coord_x, cl->coord_y, (int)cl->star_allowed);
void load(char* filename) {
n_loaded = line_count(filename) -1;
all_loaded_cells = malloc(sizeof(cell*)*n_loaded);
all_loaded_cells[0] = start;
for(int i = 0; i < n_loaded; i++) {
if(i != 0) {
all_loaded_cells[i] = malloc(sizeof(cell));
};
all_loaded_cells[i]->next_1 = NULL;
all_loaded_cells[i]->next_2 = NULL;
all_loaded_cells[i]->next_3 = NULL;
all_loaded_cells[i]->next_4 = NULL;
all_loaded_cells[i]->prev_1 = NULL;
all_loaded_cells[i]->prev_2 = NULL;
all_loaded_cells[i]->prev_3 = NULL;
all_loaded_cells[i]->prev_4 = NULL;
};
FILE* ptr = fopen(filename, "r");
char burn;
printf("Loading %d lines...\n", n_loaded);
for(int i = 0; i < n_loaded; i++) {
printf("%d\n", i);
int unique = get_integer(ptr);
int a_type = get_integer(ptr);
int cx = get_integer(ptr);
int cy = get_integer(ptr);
int ok_star = get_integer(ptr);
//printf(" %d, %d, %d, %d, %d\n", unique, a_type, cx, cy, ok_star);
all_loaded_cells[i]->unique_id = unique;
all_loaded_cells[i]->type = (CELLTYPE)a_type;
all_loaded_cells[i]->coord_x = cx;
all_loaded_cells[i]->coord_y = cy;
all_loaded_cells[i]->star_allowed = (bool)ok_star;
int current_link = get_integer(ptr);
while(current_link > 0) {
link_cells(all_loaded_cells[i], all_loaded_cells[current_link-1]);
//printf(" linking %d <--> %d", i, current_link -1);
current_link = get_integer(ptr);
};
if(i != n_loaded -1) {
terminate_line(ptr);
}
};
current = start;
edit_cell_count = n_loaded;
fclose(ptr);
}