diff --git a/include/constants.h b/include/constants.h index 00ec5bb..8c63b00 100644 --- a/include/constants.h +++ b/include/constants.h @@ -6,13 +6,7 @@ #ifndef STATE_CONSTS_H #define STATE_CONSTS_H -#if defined(_WIN32) || defined(_WIN64) || defined(__MINGW32__) -#define F_SEP "\\" -#elif defined(__linux__) || defined(__GNUC__) #define F_SEP "/" -#else -#error "Unrecognized system." -#endif enum COLORS { BAR_COLOR = 1, diff --git a/include/map.h b/include/map.h index d4223d0..268a01f 100644 --- a/include/map.h +++ b/include/map.h @@ -11,50 +11,50 @@ #define MAX_STR 128 typedef enum FLOOR_TYPES { - VOID = 0, - SOLID_WALL, - SECRET_WALL, - CLEAR_WALL, - NEON_WALL, - WINDOW_WALL, - EMPTY_FLOOR, - RUG, - WATER, - BAR - } floor_t; + VOID = 0, + SOLID_WALL, + SECRET_WALL, + CLEAR_WALL, + NEON_WALL, + WINDOW_WALL, + EMPTY_FLOOR, + RUG, + WATER, + BAR + } floor_t; typedef enum OBJECT_TYPES { - DOOR = 0, - KEY, - PERSON, - PLAYER_START, - EXIT, - DIALOG, - NONE = 9989 - } obj_t; + DOOR = 0, + KEY, + PERSON, + PLAYER_START, + EXIT, + DIALOG, + NONE = 9989 + } obj_t; typedef enum ERROR_CODES { - NO_ERROR = 0, - FILE_NOT_FOUND, - OUT_OF_MEMORY, - PREMATURE_EOF, - MAP_TOO_LARGE, - INVALID_KEY - } errcode_t; + NO_ERROR = 0, + FILE_NOT_FOUND, + OUT_OF_MEMORY, + PREMATURE_EOF, + MAP_TOO_LARGE, + INVALID_KEY + } errcode_t; typedef struct MAP_CELL{ - floor_t f; + floor_t f; } map_cell_t; typedef struct OBJECT { - obj_t type; - short x, y, eX, eY, sX, sY; - short id; - short dId; - char name[MAX_STR]; - char target[MAX_STR]; - char dialog[MAX_STR]; - unsigned char unlocked; + obj_t type; + short x, y, eX, eY, sX, sY; + short id; + short dId; + char name[MAX_STR]; + char target[MAX_STR]; + char dialog[MAX_STR]; + unsigned char unlocked; } game_obj_t; extern errcode_t readMapData(const char *, map_cell_t ***, int *, int *); diff --git a/src/in_game.c b/src/in_game.c index b246739..8feb08b 100644 --- a/src/in_game.c +++ b/src/in_game.c @@ -12,6 +12,13 @@ #include "in_game.h" #include "map.h" +#define MAX_KEYS 15 + +static const char *keyMsg = "You picked up a key."; +static const char *saysMsg = " says: "; +static const char *openDoor = "The door opens."; +static const char *doorLock = "This door is locked."; + typedef struct PLAYER { unsigned short x; unsigned short y; @@ -22,12 +29,16 @@ static bool **seen; static bool ** wmap; static bool w_mov = FALSE; static bool uK, dK, lK, rK; -static clock_t then; +static clock_t then, msgThen; static player_t player; static map_cell_t ** map; -game_obj_t objs[MAX_OBJECTS]; +static game_obj_t objs[MAX_OBJECTS]; static int mW, mH, nO; -fov_settings_type fov_settings; +static fov_settings_type fov_settings; +static int keys[MAX_KEYS]; +static int freeKey; +static char msg[128]; +static bool newMsg = FALSE; void input(); gsname_t update(); @@ -35,9 +46,12 @@ void render(int, int); void drawGui(int, int); void setPlayerStart(); void initObjects(); +void initKeys(); void drawNeon(int, int, floor_t); void apply(void *, int, int, int, int, void *); bool opaque(void *, int, int); +void loadMap(const char *); +bool canMoveTo(int, int); void initInGameState( gs_t * gs) { int i, j; @@ -47,12 +61,12 @@ void initInGameState( gs_t * gs) { gs->update = &update; gs->render = &render; - map = ( map_cell_t ** ) malloc ( sizeof ( map_cell_t * ) * MAX_MAP_SIZE); + map = ( map_cell_t ** ) malloc ( sizeof ( map_cell_t * ) * MAX_MAP_SIZE); for ( i = 0; i < MAX_MAP_SIZE; ++i ) { map[ i ] = ( map_cell_t * ) calloc ( MAX_MAP_SIZE , sizeof ( map_cell_t ) ); } - wmap = ( bool ** ) malloc ( sizeof ( bool * ) * MAX_MAP_SIZE); + wmap = ( bool ** ) malloc ( sizeof ( bool * ) * MAX_MAP_SIZE); for ( i = 0; i < MAX_MAP_SIZE; ++i ) { wmap[ i ] = ( bool * ) calloc ( MAX_MAP_SIZE, sizeof ( bool ) ); for(j = 0; j < MAX_MAP_SIZE; ++j){ @@ -60,37 +74,23 @@ void initInGameState( gs_t * gs) { } } - vis = ( bool ** ) malloc ( sizeof ( bool * ) * MAX_MAP_SIZE); - seen = ( bool ** ) malloc ( sizeof ( bool * ) * MAX_MAP_SIZE); + vis = ( bool ** ) malloc ( sizeof ( bool * ) * MAX_MAP_SIZE); + seen = ( bool ** ) malloc ( sizeof ( bool * ) * MAX_MAP_SIZE); for ( i = 0; i < MAX_MAP_SIZE; ++i ) { vis[ i ] = ( bool * ) calloc ( MAX_MAP_SIZE, sizeof ( bool ) ); - seen[ i ] = ( bool * ) calloc ( MAX_MAP_SIZE, sizeof ( bool ) ); + seen[ i ] = ( bool * ) calloc ( MAX_MAP_SIZE, sizeof ( bool ) ); for(j = 0; j < MAX_MAP_SIZE; ++j){ vis[i][j] = TRUE; - seen[i][j] = FALSE; + seen[i][j] = FALSE; } } - initObjects(); + initObjects(); + loadMap("map_file.map"); - errcode_t rc = readMapData("map_file.map", &map, &mW, &mH); - if(rc != NO_ERROR){ - fprintf(stderr, "\t%s: readMapData() returned %d\n", __FILE__, rc); - exit(rc); - } - - game_obj_t * objsP = objs; - rc = readMapObjects("map_file.map", &objsP, &nO); - if(rc != NO_ERROR){ - fprintf(stderr, "\t%s: readMapObjects() returned %d\n", __FILE__, rc); - exit(rc); - } - - setPlayerStart(); - - fov_settings_init(&fov_settings); - fov_settings_set_opacity_test_function(&fov_settings, opaque); - fov_settings_set_apply_lighting_function(&fov_settings, apply); + fov_settings_init(&fov_settings); + fov_settings_set_opacity_test_function(&fov_settings, opaque); + fov_settings_set_apply_lighting_function(&fov_settings, apply); } void input(){ @@ -99,7 +99,6 @@ void input(){ key = getch(); if(key != ERR){ - fprintf(stderr, "\t%s: Caught keycode %d\n", __FILE__, key); if(key == KEY_UP) uK = TRUE; if(key == KEY_DOWN) dK = TRUE; if(key == KEY_LEFT) lK = TRUE; @@ -108,32 +107,133 @@ void input(){ } gsname_t update(){ - int iX, iY; + clock_t msgNow, delta; + int i, j, k, d, iX, iY, nX, nY; - iX = player.x; - iY = player.y; + iX = player.x; + iY = player.y; + nX = iX; + nY = iY; + if(uK) nY = iY - 1 < 0 ? mH - 1 : iY - 1; + + if(dK) nY = (iY + 1) % mH; + + if(lK) nX = iX - 1 < 0 ? mW - 1 : iX - 1; + + if(rK) nX = (iX + 1) % mW; + + /* Find if the player is standing on an exit, then load the next map. */ + for(i = 0; i < nO; i++){ + if(objs[i].type == EXIT){ + if(objs[i].x == iY && objs[i].y == iX){ + player.x = objs[i].eX; + player.y = objs[i].eY; + loadMap(objs[i].target); + return IN_GAME; + } + } + } + + /* TODO: use keys.*/ + for(i = 0; i < nO; i++){ + if(objs[i].type == KEY){ + if(objs[i].x == iY && objs[i].y == iX){ + keys[freeKey] = objs[i].id; + objs[i].type = NONE; + for(j = 0; keyMsg[j] && j < 128; j++){ + msg[j] = keyMsg[j]; + } + newMsg = TRUE; + msgThen = clock(); + } + } + } + + /* Listen to a person. */ + for(i = 0; i < nO; i++){ + if(objs[i].type == PERSON){ + if(objs[i].x == nY && objs[i].y == nX){ + for(k = 0; k < nO; k++) + if(objs[k].type == DIALOG && objs[k].id == objs[i].dId) break; + + for(j = 0; objs[i].name[j] && j < 128; j++) + msg[j] = objs[i].name[j]; + + for(d = 0; saysMsg[d] && j < 128; j++, d++) + msg[j] = saysMsg[d]; + + for(d = 0; objs[k].dialog[d] && j < 128; j++, d++) + msg[j] = objs[k].dialog[d]; + + newMsg = TRUE; + msgThen = clock(); + } + } + } + + for(i = 0; i < nO; i++){ + if(objs[i].type == DOOR){ + if(objs[i].x == nY && objs[i].y == nX){ + if(!objs[i].unlocked){ + for(j = 0; j < MAX_KEYS; j++){ + if(keys[j] == objs[i].id){ + objs[i].unlocked = 1; + break; + } + } + + if(objs[i].unlocked){ + for(j = 0; openDoor[j] && j < 128; j++){ + msg[j] = openDoor[j]; + } + }else{ + for(j = 0; doorLock[j] && j < 128; j++){ + msg[j] = doorLock[j]; + } + } + + newMsg = TRUE; + msgThen = clock(); + } + } + } + } + + if(newMsg){ + msgNow = clock(); + delta = msgNow - msgThen; + if((int)delta / (int)CLOCKS_PER_SEC >= 4){ + msgThen = msgNow; + for(j = 0; j < 128; j++){ + msg[j] = '\0'; + } + newMsg = FALSE; + } + } + + /* Move the player. */ if(uK){ - iY = iY - 1 < 0 ? mH - 1 : iY - 1; - if((map[iY][iX].f > WINDOW_WALL && map[iY][iX].f <= WATER) || map[iY][iX].f == SECRET_WALL) player.y = iY; + iY = iY - 1 < 0 ? mH - 1 : iY - 1; + if(canMoveTo(iY, iX)) player.y = iY; uK = FALSE; } if(dK){ - iY = (iY + 1) % mH; - if((map[iY][iX].f > WINDOW_WALL && map[iY][iX].f <= WATER) || map[iY][iX].f == SECRET_WALL) player.y = iY; + iY = (iY + 1) % mH; + if(canMoveTo(iY, iX)) player.y = iY; dK = FALSE; } if(lK){ - iX = iX - 1 < 0 ? mW - 1 : iX - 1; - if((map[iY][iX].f > WINDOW_WALL && map[iY][iX].f <= WATER) || map[iY][iX].f == SECRET_WALL) player.x = iX; + iX = iX - 1 < 0 ? mW - 1 : iX - 1; + if(canMoveTo(iY, iX)) player.x = iX; lK = FALSE; } if(rK){ - iX = (iX + 1) % mW; - if((map[iY][iX].f > WINDOW_WALL && map[iY][iX].f <= WATER) || map[iY][iX].f == SECRET_WALL) player.x = iX; + iX = (iX + 1) % mW; + if(canMoveTo(iY, iX)) player.x = iX; rK = FALSE; } @@ -142,7 +242,7 @@ gsname_t update(){ void render(int w, int h){ clock_t now, delta; - int i, j, pi, pj, ioff, joff, di, dj; + int i, j, k, pi, pj, ioff, joff, di, dj; now = clock(); delta = now - then; @@ -151,16 +251,16 @@ void render(int w, int h){ w_mov = TRUE; } - pi = (((w - 1) - 27) / 2) + 27; - pj = (h - 2) / 2 + 1; + pi = (((w - 1) - 1) / 2) + 1; + pj = (h - 3) / 2 + 1; - ioff = (w - 28) / 2; - joff = (h - 2) / 2; + ioff = (w - 28 - 27) / 2; + joff = (h - 3) / 2; - fov_circle(&fov_settings, &map, NULL, player.x, player.y, (MAX_MAP_SIZE / 2) - 1); + fov_circle(&fov_settings, &map, NULL, player.x, player.y, (MAX_MAP_SIZE / 2) - 1); - for(i = 27; i < w - 1; i++){ - for(j = 1; j < h - 1; j++){ + for(i = 1; i < w - 1; i++){ + for(j = 1; j < h - 3; j++){ move(j, i); di = i - 27 + player.x - ioff; @@ -169,67 +269,84 @@ void render(int w, int h){ if( di < 0 || di >= mW || dj < 0 || dj >= mH ){ printw(" "); }else{ - if(vis[dj][di] || seen[dj][di]){ - switch(map[dj][di].f){ - case WATER: - attron(COLOR_PAIR(DW_COLOR)); - if(w_mov) - wmap[dj][di] = !wmap[dj][di]; - if(wmap[dj][di]) - printw("\u2248"); - else - printw("~"); - break; + if(vis[dj][di] || seen[dj][di]){ + switch(map[dj][di].f){ + case WATER: + attron(COLOR_PAIR(DW_COLOR)); + if(w_mov) + wmap[dj][di] = !wmap[dj][di]; + if(wmap[dj][di]) + printw("\u2248"); + else + printw("~"); + break; - case VOID: - if(!vis[dj][di]) attron(COLOR_PAIR(DW_COLOR)); - else attron(COLOR_PAIR(MN_COLOR)); - printw(" "); - break; + case VOID: + if(!vis[dj][di]) attron(COLOR_PAIR(DW_COLOR)); + else attron(COLOR_PAIR(MN_COLOR)); + printw(" "); + break; - case EMPTY_FLOOR: - if(!vis[dj][di]) attron(COLOR_PAIR(DW_COLOR)); - else attron(COLOR_PAIR(MN_COLOR)); - printw(" "); - break; + case EMPTY_FLOOR: + if(!vis[dj][di]) attron(COLOR_PAIR(DW_COLOR)); + else attron(COLOR_PAIR(MN_COLOR)); + printw(" "); + break; - case RUG: - if(!vis[dj][di]) attron(COLOR_PAIR(DW_COLOR)); - else attron(COLOR_PAIR(SN_COLOR)); - printw("\u2592"); - break; + case RUG: + if(!vis[dj][di]) attron(COLOR_PAIR(DW_COLOR)); + else attron(COLOR_PAIR(SN_COLOR)); + printw("\u2592"); + break; - case WINDOW_WALL: - if(!vis[dj][di]) attron(COLOR_PAIR(DW_COLOR)); - else attron(COLOR_PAIR(SW_COLOR)); - printw("\u2591"); - break; + case WINDOW_WALL: + if(!vis[dj][di]) attron(COLOR_PAIR(DW_COLOR)); + else attron(COLOR_PAIR(SW_COLOR)); + printw("\u2591"); + break; - case CLEAR_WALL: - if(!vis[dj][di]) attron(COLOR_PAIR(DW_COLOR)); - else attron(COLOR_PAIR(SW_COLOR)); - printw("\u2588"); - break; + case CLEAR_WALL: + if(!vis[dj][di]) attron(COLOR_PAIR(DW_COLOR)); + else attron(COLOR_PAIR(SW_COLOR)); + printw("\u2588"); + break; - case SECRET_WALL: - case SOLID_WALL: - if(!vis[dj][di]) attron(COLOR_PAIR(DW_COLOR)); - else attron(COLOR_PAIR(MN_COLOR)); - printw("\u2588"); - break; + case SECRET_WALL: + case SOLID_WALL: + if(!vis[dj][di]) attron(COLOR_PAIR(DW_COLOR)); + else attron(COLOR_PAIR(MN_COLOR)); + printw("\u2588"); + break; - case NEON_WALL: - drawNeon(dj, di, NEON_WALL); - break; + case NEON_WALL: + drawNeon(dj, di, NEON_WALL); + break; - case BAR: - drawNeon(dj, di, BAR); - break; - } - }else{ - attron(COLOR_PAIR(MN_COLOR)); - printw(" "); - } + case BAR: + drawNeon(dj, di, BAR); + break; + } + + move(j, i); + for(k = 0; k < nO; k++){ + if(objs[k].x == dj && objs[k].y == di){ + if(!vis[dj][di]) attron(COLOR_PAIR(DW_COLOR)); + else attron(COLOR_PAIR(MN_COLOR)); + + if(objs[k].type == DOOR){ + printw("\u25D9"); + }else if(objs[k].type == KEY){ + printw("k"); + }else if(objs[k].type == PERSON){ + printw("\u263A"); + } + } + } + + }else{ + attron(COLOR_PAIR(MN_COLOR)); + printw(" "); + } } } } @@ -241,7 +358,7 @@ void render(int w, int h){ drawGui(w, h); - for ( i = 0; i < MAX_MAP_SIZE; ++i ) { + for ( i = 0; i < MAX_MAP_SIZE; ++i ) { for(j = 0; j < MAX_MAP_SIZE; ++j){ vis[i][j] = FALSE; } @@ -249,174 +366,241 @@ void render(int w, int h){ } void drawNeon(int i, int j, floor_t floor){ - int r; - bool n, s, e, w; + int r; + bool n, s, e, w; - if(floor == NEON_WALL){ - if(!vis[i][j]) attron(COLOR_PAIR(DW_COLOR)); - else{ - r = rand() % 1000; - if(r < 998) - attron(COLOR_PAIR(FR_COLOR)); - else - attron(COLOR_PAIR(MN_COLOR)); - } - }else if(floor == BAR){ - if(!vis[i][j]) attron(COLOR_PAIR(DW_COLOR)); - else attron(COLOR_PAIR(SN_COLOR)); - } + if(floor == NEON_WALL){ + if(!vis[i][j]) attron(COLOR_PAIR(DW_COLOR)); + else{ + r = rand() % 1000; + if(r < 998) + attron(COLOR_PAIR(FR_COLOR)); + else + attron(COLOR_PAIR(MN_COLOR)); + } + }else if(floor == BAR){ + if(!vis[i][j]) attron(COLOR_PAIR(DW_COLOR)); + else attron(COLOR_PAIR(SN_COLOR)); + } - n = map[i ][j - 1 < 0 ? mH - 1 : j - 1].f == floor; - s = map[i ][(j + 1) % mH ].f == floor; - e = map[i - 1 < 0 ? mW - 1 : i - 1][j ].f == floor; - w = map[(i + 1) % mW ][j ].f == floor; + n = map[i ][j - 1 < 0 ? mH - 1 : j - 1].f == floor; + s = map[i ][(j + 1) % mH ].f == floor; + e = map[i - 1 < 0 ? mW - 1 : i - 1][j ].f == floor; + w = map[(i + 1) % mW ][j ].f == floor; - if((n && s && e) && (!w)){ - printw("\u2560"); - return; - } + if((n && s && e) && (!w)){ + printw("\u2560"); + return; + } - if((n || s) && (!e && !w)){ - printw("\u2550"); - return; - } + if((n || s) && (!e && !w)){ + printw("\u2550"); + return; + } - if((e || w) && (!n && !s)){ - printw("\u2551"); - return; - } + if((e || w) && (!n && !s)){ + printw("\u2551"); + return; + } - if((e && n) && (!s && !w)){ - printw("\u255D"); - return; - } + if((e && n) && (!s && !w)){ + printw("\u255D"); + return; + } - if((w && n) && (!s && !e)){ - printw("\u2557"); - return; - } + if((w && n) && (!s && !e)){ + printw("\u2557"); + return; + } - if((e && s) && (!n && !w)){ - printw("\u255A"); - return; - } + if((e && s) && (!n && !w)){ + printw("\u255A"); + return; + } - if((w && s) && (!n && !e)){ - printw("\u2554"); - return; - } + if((w && s) && (!n && !e)){ + printw("\u2554"); + return; + } - if((s && e && w) && (!n)){ - printw("\u2560"); - return; - } + if((s && e && w) && (!n)){ + printw("\u2560"); + return; + } - if((n && w && e) && (!s)){ - printw("\u2563"); - return; - } + if((n && w && e) && (!s)){ + printw("\u2563"); + return; + } - if(n && s && e && w){ - printw("\u256C"); - return; - } + if(n && s && e && w){ + printw("\u256C"); + return; + } } void drawGui(int w, int h){ - int i, j; + int i; attron(COLOR_PAIR(BSC_COLOR)); /* Clear the gui space. */ - for(i = 1; i < 26; i++){ - for(j = 1; j < h - 1; j++){ - move(j, i); - printw(" "); - } + for(i = 1; i < w - 1; i++){ + move(h - 2, i); + printw(" "); } /* Upper horizontal bar. */ move(0, 0); printw("\u2554"); for(i = 0; i < w - 2; i++){ - if(i != 25){ - printw("\u2550"); - }else{ - printw("\u2566"); - } + printw("\u2550"); } printw("\u2557"); - /* Lower horizontal bar. */ + /* Lower horizontal bars. */ + move(h - 3, 0); + printw("\u255A"); + for(i = 0; i < w - 2; i++){ + printw("\u2550"); + } + printw("\u255D"); + move(h - 1, 0); printw("\u255A"); for(i = 0; i < w - 2; i++){ - if(i != 25){ - printw("\u2550"); - }else{ - printw("\u2569"); - } + printw("\u2550"); } printw("\u255D"); /* Vertical bars. */ for(i = 1; i < h - 1; i++){ move(i, 0); - printw("\u2551"); - move(i, 26); - printw("\u2551"); + if(i != h - 3) printw("\u2551"); + else printw("\u2560"); move(i, w-1); - printw("\u2551"); + if(i != h - 3) printw("\u2551"); + else printw("\u2563"); + } + + move(h - 2, 1); + for(i = 0; msg[i] && i < w - 2; i++){ + printw("%c", msg[i]); } } void setPlayerStart(){ int i; - for(i = 0; i < nO; i++){ - if(objs[i].type == PLAYER_START){ - player.y = objs[i].sX; - player.x = objs[i].sY; - break; - } - } + for(i = 0; i < nO; i++){ + if(objs[i].type == PLAYER_START){ + player.y = objs[i].sX; + player.x = objs[i].sY; + break; + } + } } void initObjects(){ - int i; + int i; - for(i = 0; i < MAX_OBJECTS; ++i){ - objs[i].type = NONE; - objs[i].x = 0; - objs[i].y = 0; - objs[i].eX = 0; - objs[i].eY = 0; - objs[i].sX = 0; - objs[i].sY = 0; - objs[i].id = 0; - objs[i].dId = 0; - objs[i].name[0] = '\0'; - objs[i].target[0] = '\0'; - objs[i].dialog[0] = '\0'; - objs[i].unlocked = 0; - } + for(i = 0; i < MAX_OBJECTS; ++i){ + objs[i].type = NONE; + objs[i].x = 0; + objs[i].y = 0; + objs[i].eX = 0; + objs[i].eY = 0; + objs[i].sX = 0; + objs[i].sY = 0; + objs[i].id = 0; + objs[i].dId = 0; + objs[i].name[0] = '\0'; + objs[i].target[0] = '\0'; + objs[i].dialog[0] = '\0'; + objs[i].unlocked = 0; + } +} + +void initKeys(){ + int i; + + freeKey = 0; + for(i = 0; i < MAX_KEYS; ++i){ + keys[i] = -1; + } } void apply(void *map, int x, int y, int dx, int dy, void *src){ - if(x < 0 || x >= MAX_MAP_SIZE) return; - if(y < 0 || y >= MAX_MAP_SIZE) return; + if(x < 0 || x >= MAX_MAP_SIZE) return; + if(y < 0 || y >= MAX_MAP_SIZE) return; vis[y][x] = TRUE; - seen[y][x] = TRUE; + seen[y][x] = TRUE; } bool opaque(void *m, int x, int y){ - if(x < 0 || x >= MAX_MAP_SIZE) return FALSE; - if(y < 0 || y >= MAX_MAP_SIZE) return FALSE; + int k; + if(x < 0 || x >= MAX_MAP_SIZE) return FALSE; + if(y < 0 || y >= MAX_MAP_SIZE) return FALSE; if(map[y][x].f == SOLID_WALL || map[y][x].f == SECRET_WALL){ - return TRUE; - }else{ - return FALSE; - } + return TRUE; + }else{ + for(k = 0; k < nO; k++){ + if(objs[k].type == DOOR){ + if(objs[k].x == y && objs[k].y == x){ + return TRUE; + } + } + } + + return FALSE; + } +} + +void loadMap(const char * file){ + int i, j; + + errcode_t rc = readMapData(file, &map, &mW, &mH); + if(rc != NO_ERROR){ + fprintf(stderr, "\t%s.loadMap(): readMapData() returned %d\n", __FILE__, rc); + exit(rc); + } + + game_obj_t * objsP = objs; + rc = readMapObjects(file, &objsP, &nO); + if(rc != NO_ERROR){ + fprintf(stderr, "\t%s.loadMap(): readMapObjects() returned %d\n", __FILE__, rc); + exit(rc); + } + + setPlayerStart(); + initKeys(); + + for ( i = 0; i < MAX_MAP_SIZE; ++i ) { + for(j = 0; j < MAX_MAP_SIZE; ++j){ + vis[i][j] = FALSE; + seen[i][j] = FALSE; + } + } +} + +bool canMoveTo(int iY, int iX){ + int k; + + for(k = 0; k < nO; k++){ + if(objs[k].x == iY && objs[k].y == iX){ + if(objs[k].type == DOOR){ + if(objs[k].unlocked) return TRUE; + else return FALSE; + }else if(objs[k].type == PERSON){ + return FALSE; + } + } + } + + if((map[iY][iX].f > WINDOW_WALL && map[iY][iX].f <= WATER) || map[iY][iX].f == SECRET_WALL) + return TRUE; + else + return FALSE; } diff --git a/src/main.c b/src/main.c index 34a1b44..5578155 100644 --- a/src/main.c +++ b/src/main.c @@ -28,22 +28,16 @@ static bool resize = FALSE; int main() { bool finished = FALSE; -#if defined(_WIN32) || defined(_WIN64) || defined(__MINGW32__) - char * home_dir = getenv("APPDATA"); -#elif defined(__linux__) || defined(__GNUC__) - char * home_dir = getenv("HOME"); -#else -#error "Unrecognized system." -#endif - FILE * f; /* To avoid a warning. */ - clock_t then, now, delta; - unsigned int fps = 0, pfps = 0; - char * data_dir; - char * log_file; - time_t raw_date; - struct tm * current_date; - gs_t * states; - int c_state; + char * home_dir = getenv("HOME"); + FILE * f; /* To avoid a warning. */ + clock_t then, now, delta; + unsigned int fps = 0, pfps = 0; + char * data_dir; + char * log_file; + time_t raw_date; + struct tm * current_date; + gs_t * states; + int c_state; atexit(leave); signal(SIGINT, manage_signal); @@ -70,15 +64,11 @@ int main() { fprintf(stderr, "%s", asctime(current_date)); /* Try to create the data directory with permissions 775. */ - if(mkdir(data_dir, S_IRWXU | S_IWGRP | S_IRGRP| S_IROTH | S_IXOTH) == 0){ - /* The data directory was sucessfully created. */ - }else{ + if(mkdir(data_dir, S_IRWXU | S_IWGRP | S_IRGRP| S_IROTH | S_IXOTH) != 0){ if(errno != EEXIST){ /* The directory does not exists and could not be created. */ perror("\t" __FILE__); fprintf(stderr, "\tdata_dir is: %s\n", data_dir); - }else{ - /* The directory already exits. */ } } }else{ diff --git a/src/map.c b/src/map.c index df52593..494b0f4 100644 --- a/src/map.c +++ b/src/map.c @@ -11,360 +11,360 @@ #include "map.h" errcode_t readMapData(const char * file, map_cell_t *** map, int * w, int * h){ - size_t n = 2048; - char *buffer; - FILE * f; + size_t n = 2048; + char *buffer; + FILE * f; - f = fopen(file, "r"); - if(f == NULL) return FILE_NOT_FOUND; + f = fopen(file, "r"); + if(f == NULL) return FILE_NOT_FOUND; - buffer = (char*)calloc(n + 1, sizeof(char)); - if(buffer == NULL) return OUT_OF_MEMORY; + buffer = (char*)calloc(n + 1, sizeof(char)); + if(buffer == NULL) return OUT_OF_MEMORY; - while(getline(&buffer, &n, f) != -1){ - if(strcmp(buffer, "[MAP]\n") == 0){ - int rc, i, j; - char *end; + while(getline(&buffer, &n, f) != -1){ + if(strcmp(buffer, "[MAP]\n") == 0){ + int rc, i, j; + char *end; - fprintf(stderr, "\t%s.readMapData() : found a map.\n", __FILE__); + fprintf(stderr, "\t%s.readMapData() : found a map.\n", __FILE__); - rc = getline(&buffer, &n, f); - if(rc == -1){ - free(buffer); - return PREMATURE_EOF; - } + rc = getline(&buffer, &n, f); + if(rc == -1){ + free(buffer); + return PREMATURE_EOF; + } - *w = strtol(buffer, &end, 10); - *h = strtol(end, NULL, 10); + *w = strtol(buffer, &end, 10); + *h = strtol(end, NULL, 10); - if((*w <= 0 || *w > MAX_MAP_SIZE) || (*h <= 0 || *h > MAX_MAP_SIZE)){ - *w = -1; - *h = -1; - free(buffer); - return MAP_TOO_LARGE; - } + if((*w <= 0 || *w > MAX_MAP_SIZE) || (*h <= 0 || *h > MAX_MAP_SIZE)){ + *w = -1; + *h = -1; + free(buffer); + return MAP_TOO_LARGE; + } - for(i = 0; i < *w; i++){ - rc = getline(&buffer, &n, f); - if(rc == -1){ - free(buffer); - return PREMATURE_EOF; - } + for(i = 0; i < *w; i++){ + rc = getline(&buffer, &n, f); + if(rc == -1){ + free(buffer); + return PREMATURE_EOF; + } - /* Skip commentaries. */ - if(buffer[0] == '%'){ - i--; - continue; - } + /* Skip commentaries. */ + if(buffer[0] == '%'){ + i--; + continue; + } - for(j = 0; buffer[j] && j < *h; j++){ - if(buffer[j] >= '0' && buffer[j] <= '9'){ - switch(buffer[j]){ - case '0': (*map)[i][j].f = VOID; break; - case '1': (*map)[i][j].f = SOLID_WALL; break; - case '2': (*map)[i][j].f = SECRET_WALL; break; - case '3': (*map)[i][j].f = CLEAR_WALL; break; - case '4': (*map)[i][j].f = NEON_WALL; break; - case '5': (*map)[i][j].f = WINDOW_WALL; break; - case '6': (*map)[i][j].f = EMPTY_FLOOR; break; - case '7': (*map)[i][j].f = RUG; break; - case '8': (*map)[i][j].f = WATER; break; - case '9': (*map)[i][j].f = BAR; break; - default: - fprintf(stderr, "\t%s.readMapData() : Invalid character %c in map file %s\n", __FILE__, buffer[j], file); - (*map)[i][j].f = VOID; - break; - } - }else{ - fprintf(stderr, "\t%s.readMapData() : Invalid character %c in map file %s\n", __FILE__, buffer[j], file); - (*map)[i][j].f = VOID; - } - } - } - /* Skip the rest of the file. */ - break; - } - } + for(j = 0; buffer[j] && j < *h; j++){ + if(buffer[j] >= '0' && buffer[j] <= '9'){ + switch(buffer[j]){ + case '0': (*map)[i][j].f = VOID; break; + case '1': (*map)[i][j].f = SOLID_WALL; break; + case '2': (*map)[i][j].f = SECRET_WALL; break; + case '3': (*map)[i][j].f = CLEAR_WALL; break; + case '4': (*map)[i][j].f = NEON_WALL; break; + case '5': (*map)[i][j].f = WINDOW_WALL; break; + case '6': (*map)[i][j].f = EMPTY_FLOOR; break; + case '7': (*map)[i][j].f = RUG; break; + case '8': (*map)[i][j].f = WATER; break; + case '9': (*map)[i][j].f = BAR; break; + default: + fprintf(stderr, "\t%s.readMapData() : Invalid character %c in map file %s\n", __FILE__, buffer[j], file); + (*map)[i][j].f = VOID; + break; + } + }else{ + fprintf(stderr, "\t%s.readMapData() : Invalid character %c in map file %s\n", __FILE__, buffer[j], file); + (*map)[i][j].f = VOID; + } + } + } + /* Skip the rest of the file. */ + break; + } + } - fclose(f); - free(buffer); + fclose(f); + free(buffer); - return NO_ERROR; + return NO_ERROR; } errcode_t readMapObjects(const char * file, game_obj_t ** objArr, int *nObj){ - size_t n = 2048; - int rc; - char *buffer; - FILE * f; + size_t n = 2048; + int rc; + char *buffer; + FILE * f; - *nObj = 0; + *nObj = 0; - f = fopen(file, "r"); - if(f == NULL) return FILE_NOT_FOUND; + f = fopen(file, "r"); + if(f == NULL) return FILE_NOT_FOUND; - buffer = (char*)calloc(n + 1, sizeof(char)); - if(buffer == NULL) return OUT_OF_MEMORY; + buffer = (char*)calloc(n + 1, sizeof(char)); + if(buffer == NULL) return OUT_OF_MEMORY; - rc = getline(&buffer, &n, f); - if(rc == -1){ - free(buffer); - return PREMATURE_EOF; - } + rc = getline(&buffer, &n, f); + if(rc == -1){ + free(buffer); + return PREMATURE_EOF; + } - while(*nObj < MAX_OBJECTS && rc != -1){ - if(buffer[0] == '%') continue; + while(*nObj < MAX_OBJECTS && rc != -1){ + if(buffer[0] == '%') continue; - if(strcmp(buffer, "[MAP]\n") == 0){ - int i, w; + if(strcmp(buffer, "[MAP]\n") == 0){ + int i, w; - rc = getline(&buffer, &n, f); - if(rc == -1){ - free(buffer); - return PREMATURE_EOF; - } + rc = getline(&buffer, &n, f); + if(rc == -1){ + free(buffer); + return PREMATURE_EOF; + } - w = strtol(buffer, NULL, 10); + w = strtol(buffer, NULL, 10); - for(i = 0; i <= w; ++i){ - rc = getline(&buffer, &n, f); - if(rc == -1){ - free(buffer); - return PREMATURE_EOF; - } - } + for(i = 0; i <= w; ++i){ + rc = getline(&buffer, &n, f); + if(rc == -1){ + free(buffer); + return PREMATURE_EOF; + } + } - }else if(strcmp(buffer, "[PLAYER]\n") == 0){ - do{ - rc = getline(&buffer, &n, f); - if(rc == -1) break; + }else if(strcmp(buffer, "[PLAYER]\n") == 0){ + do{ + rc = getline(&buffer, &n, f); + if(rc == -1) break; - if(buffer[0] == '%') continue; - else if(buffer[0] == 'p'){ - int i; + if(buffer[0] == '%') continue; + else if(buffer[0] == 'p'){ + int i; - for(i = 0; buffer[i] && buffer[i] != '='; ++i); - - if(strncmp(buffer, "player =", i) == 0){ - int sX, sY; - char *end; - - sX = strtol(&buffer[i + 1], &end, 10); - sY = strtol(end, NULL, 10); + for(i = 0; buffer[i] && buffer[i] != '='; ++i); + + if(strncmp(buffer, "player =", i) == 0){ + int sX, sY; + char *end; + + sX = strtol(&buffer[i + 1], &end, 10); + sY = strtol(end, NULL, 10); - (*objArr)[*nObj].type = PLAYER_START; - (*objArr)[*nObj].sX = sX; - (*objArr)[*nObj].sY = sY; + (*objArr)[*nObj].type = PLAYER_START; + (*objArr)[*nObj].sX = sX; + (*objArr)[*nObj].sY = sY; - *nObj += 1; + *nObj += 1; - }else{ - fprintf(stderr, "\t%s.readMapObjects(): Skipped invalid data in PLAYER key in map file %s.\n", __FILE__, file); - fprintf(stderr, "\t%s.readMapObjects(): The invalid line is %s.\n", __FILE__, buffer); - continue; - } - } - }while(buffer[0] != '['); + }else{ + fprintf(stderr, "\t%s.readMapObjects(): Skipped invalid data in PLAYER key in map file %s.\n", __FILE__, file); + fprintf(stderr, "\t%s.readMapObjects(): The invalid line is %s.\n", __FILE__, buffer); + continue; + } + } + }while(buffer[0] != '['); - }else if(strcmp(buffer, "[EXITS]\n") == 0){ - do{ - rc = getline(&buffer, &n, f); - if(rc == -1) break; + }else if(strcmp(buffer, "[EXITS]\n") == 0){ + do{ + rc = getline(&buffer, &n, f); + if(rc == -1) break; - if(buffer[0] == '%') continue; - else if(buffer[0] == 'e'){ - int i; + if(buffer[0] == '%') continue; + else if(buffer[0] == 'e'){ + int i; - for(i = 0; buffer[i] && buffer[i] != '='; ++i); - - if(strncmp(buffer, "exit =", i) == 0){ - int x, y, eX, eY; - char *end, *end2, *end3; - - x = strtol(&buffer[i + 1], &end, 10); - y = strtol(end, &end2, 10); - end2++; - - (*objArr)[*nObj].type = EXIT; - (*objArr)[*nObj].x = x; - (*objArr)[*nObj].y = y; - - for(i = 0; end2[i] && end2[i] != ' '; ++i); + for(i = 0; buffer[i] && buffer[i] != '='; ++i); + + if(strncmp(buffer, "exit =", i) == 0){ + int x, y, eX, eY; + char *end, *end2, *end3; + + x = strtol(&buffer[i + 1], &end, 10); + y = strtol(end, &end2, 10); + end2++; + + (*objArr)[*nObj].type = EXIT; + (*objArr)[*nObj].x = x; + (*objArr)[*nObj].y = y; + + for(i = 0; end2[i] && end2[i] != ' '; ++i); - strncpy((*objArr)[*nObj].target, end2, i); - (*objArr)[*nObj].target[i] = '\0'; - - eX = strtol(&end2[i], &end3, 10); - eY = strtol(end3, NULL, 10); + strncpy((*objArr)[*nObj].target, end2, i); + (*objArr)[*nObj].target[i] = '\0'; + + eX = strtol(&end2[i], &end3, 10); + eY = strtol(end3, NULL, 10); - (*objArr)[*nObj].eX = eX; - (*objArr)[*nObj].eY = eY; + (*objArr)[*nObj].eX = eX; + (*objArr)[*nObj].eY = eY; - *nObj += 1; - - }else{ - fprintf(stderr, "\t%s.readMapObjects(): Skipped invalid data in EXITS key in map file %s.\n", __FILE__, file); - fprintf(stderr, "\t%s.readMapObjects(): The invalid line is %s.\n", __FILE__, buffer); - continue; - } - } - }while(buffer[0] != '['); + *nObj += 1; + + }else{ + fprintf(stderr, "\t%s.readMapObjects(): Skipped invalid data in EXITS key in map file %s.\n", __FILE__, file); + fprintf(stderr, "\t%s.readMapObjects(): The invalid line is %s.\n", __FILE__, buffer); + continue; + } + } + }while(buffer[0] != '['); - }else if(strcmp(buffer, "[DOORS]\n") == 0){ - do{ - rc = getline(&buffer, &n, f); - if(rc == -1) break; + }else if(strcmp(buffer, "[DOORS]\n") == 0){ + do{ + rc = getline(&buffer, &n, f); + if(rc == -1) break; - if(buffer[0] == '%') continue; - else if(buffer[0] == 'd'){ - int i; - - for(i = 0; buffer[i] && buffer[i] != '='; ++i); + if(buffer[0] == '%') continue; + else if(buffer[0] == 'd'){ + int i; + + for(i = 0; buffer[i] && buffer[i] != '='; ++i); - if(strncmp(buffer, "door =", i) == 0){ - int dX, dY, dId, un; - char *end, *end2, *end3; - - dX = strtol(&buffer[i + 1], &end, 10); - dY = strtol(end, &end2, 10); - dId = strtol(end2, &end3, 10); - un = strtol(end3, NULL, 10); + if(strncmp(buffer, "door =", i) == 0){ + int dX, dY, dId, un; + char *end, *end2, *end3; + + dX = strtol(&buffer[i + 1], &end, 10); + dY = strtol(end, &end2, 10); + dId = strtol(end2, &end3, 10); + un = strtol(end3, NULL, 10); - (*objArr)[*nObj].type = DOOR; - (*objArr)[*nObj].x = dX; - (*objArr)[*nObj].y = dY; - (*objArr)[*nObj].id = dId; - (*objArr)[*nObj].unlocked = un; + (*objArr)[*nObj].type = DOOR; + (*objArr)[*nObj].x = dX; + (*objArr)[*nObj].y = dY; + (*objArr)[*nObj].id = dId; + (*objArr)[*nObj].unlocked = un; - *nObj += 1; + *nObj += 1; - }else{ - fprintf(stderr, "\t%s.readMapObjects(): Skipped invalid data in DOORS key in map file %s.\n", __FILE__, file); - fprintf(stderr, "\t%s.readMapObjects(): The invalid line is %s.\n", __FILE__, buffer); - continue; - } - } - }while(buffer[0] != '['); + }else{ + fprintf(stderr, "\t%s.readMapObjects(): Skipped invalid data in DOORS key in map file %s.\n", __FILE__, file); + fprintf(stderr, "\t%s.readMapObjects(): The invalid line is %s.\n", __FILE__, buffer); + continue; + } + } + }while(buffer[0] != '['); - }else if(strcmp(buffer, "[KEYS]\n") == 0){ - do{ - rc = getline(&buffer, &n, f); - if(rc == -1) break; + }else if(strcmp(buffer, "[KEYS]\n") == 0){ + do{ + rc = getline(&buffer, &n, f); + if(rc == -1) break; - if(buffer[0] == '%') continue; - else if(buffer[0] == 'k'){ - int i; + if(buffer[0] == '%') continue; + else if(buffer[0] == 'k'){ + int i; - for(i = 0; buffer[i] && buffer[i] != '='; ++i); + for(i = 0; buffer[i] && buffer[i] != '='; ++i); - if(strncmp(buffer, "key =", i) == 0){ - int kX, kY, kId; - char *end, *end2; - - kX = strtol(&buffer[i + 1], &end, 10); - kY = strtol(end, &end2, 10); - kId = strtol(end2, NULL, 10); + if(strncmp(buffer, "key =", i) == 0){ + int kX, kY, kId; + char *end, *end2; + + kX = strtol(&buffer[i + 1], &end, 10); + kY = strtol(end, &end2, 10); + kId = strtol(end2, NULL, 10); - (*objArr)[*nObj].type = KEY; - (*objArr)[*nObj].x = kX; - (*objArr)[*nObj].y = kY; - (*objArr)[*nObj].id = kId; + (*objArr)[*nObj].type = KEY; + (*objArr)[*nObj].x = kX; + (*objArr)[*nObj].y = kY; + (*objArr)[*nObj].id = kId; - *nObj += 1; + *nObj += 1; - }else{ - fprintf(stderr, "\t%s.readMapObjects(): Skipped invalid data in KEYS key in map file %s.\n", __FILE__, file); - fprintf(stderr, "\t%s.readMapObjects(): The invalid line is %s.\n", __FILE__, buffer); - continue; - } - } - }while(buffer[0] != '['); + }else{ + fprintf(stderr, "\t%s.readMapObjects(): Skipped invalid data in KEYS key in map file %s.\n", __FILE__, file); + fprintf(stderr, "\t%s.readMapObjects(): The invalid line is %s.\n", __FILE__, buffer); + continue; + } + } + }while(buffer[0] != '['); - }else if(strcmp(buffer, "[PERSONS]\n") == 0){ - do{ - rc = getline(&buffer, &n, f); - if(rc == -1) break; + }else if(strcmp(buffer, "[PERSONS]\n") == 0){ + do{ + rc = getline(&buffer, &n, f); + if(rc == -1) break; - if(buffer[0] == '%') continue; - else if(buffer[0] == 'p'){ - int i; + if(buffer[0] == '%') continue; + else if(buffer[0] == 'p'){ + int i; - for(i = 0; buffer[i] && buffer[i] != '='; ++i); + for(i = 0; buffer[i] && buffer[i] != '='; ++i); - if(strncmp(buffer, "person =", i) == 0){ - int pX, pY, pDId; - char *end, *end2; - - pX = strtol(&buffer[i + 1], &end, 10); - pY = strtol(end, &end2, 10); - end2++; - - (*objArr)[*nObj].type = PERSON; - (*objArr)[*nObj].x = pX; - (*objArr)[*nObj].y = pY; - - for(i = 0; end2[i] && end2[i] != ' '; ++i); - - strncpy((*objArr)[*nObj].name, end2, i); - (*objArr)[*nObj].name[i] = '\0'; - - pDId = strtol(&end2[i], NULL, 10); - (*objArr)[*nObj].dId = pDId; - - *nObj += 1; + if(strncmp(buffer, "person =", i) == 0){ + int pX, pY, pDId; + char *end, *end2; + + pX = strtol(&buffer[i + 1], &end, 10); + pY = strtol(end, &end2, 10); + end2++; + + (*objArr)[*nObj].type = PERSON; + (*objArr)[*nObj].x = pX; + (*objArr)[*nObj].y = pY; + + for(i = 0; end2[i] && end2[i] != ' '; ++i); + + strncpy((*objArr)[*nObj].name, end2, i); + (*objArr)[*nObj].name[i] = '\0'; + + pDId = strtol(&end2[i], NULL, 10); + (*objArr)[*nObj].dId = pDId; + + *nObj += 1; - }else{ - fprintf(stderr, "\t%s.readMapObjects(): Skipped invalid data in PERSONS key in map file %s.\n", __FILE__, file); - fprintf(stderr, "\t%s.readMapObjects(): The invalid line is %s.\n", __FILE__, buffer); - continue; - } - } - }while(buffer[0] != '['); + }else{ + fprintf(stderr, "\t%s.readMapObjects(): Skipped invalid data in PERSONS key in map file %s.\n", __FILE__, file); + fprintf(stderr, "\t%s.readMapObjects(): The invalid line is %s.\n", __FILE__, buffer); + continue; + } + } + }while(buffer[0] != '['); - }else if(strcmp(buffer, "[DIALOGS]\n") == 0){ - do{ - rc = getline(&buffer, &n, f); - if(rc == -1) break; - - if(buffer[0] == '%') continue; - else if(buffer[0] == 'd'){ - int i; + }else if(strcmp(buffer, "[DIALOGS]\n") == 0){ + do{ + rc = getline(&buffer, &n, f); + if(rc == -1) break; + + if(buffer[0] == '%') continue; + else if(buffer[0] == 'd'){ + int i; - for(i = 0; buffer[i] && buffer[i] != '='; ++i); - - if(strncmp(buffer, "dialog =", i) == 0){ - int dId; - char *end; + for(i = 0; buffer[i] && buffer[i] != '='; ++i); + + if(strncmp(buffer, "dialog =", i) == 0){ + int dId; + char *end; - dId = strtol(&buffer[i + 1], &end, 10); - end++; - - (*objArr)[*nObj].type = DIALOG; - (*objArr)[*nObj].id = dId; + dId = strtol(&buffer[i + 1], &end, 10); + end++; + + (*objArr)[*nObj].type = DIALOG; + (*objArr)[*nObj].id = dId; - strcpy((*objArr)[*nObj].dialog, end); - for(i = 0; (*objArr)[*nObj].dialog[i] && (*objArr)[*nObj].dialog[i] != '\n'; ++i); - (*objArr)[*nObj].dialog[i] = '\0'; + strcpy((*objArr)[*nObj].dialog, end); + for(i = 0; (*objArr)[*nObj].dialog[i] && (*objArr)[*nObj].dialog[i] != '\n'; ++i); + (*objArr)[*nObj].dialog[i] = '\0'; - *nObj += 1; + *nObj += 1; - }else{ - fprintf(stderr, "\t%s.readMapObjects(): Skipped invalid data in DIALOGS key in map file %s.\n", __FILE__, file); - fprintf(stderr, "\t%s.readMapObjects(): The invalid line is %s.\n", __FILE__, buffer); - continue; - } - } - }while(buffer[0] != '['); + }else{ + fprintf(stderr, "\t%s.readMapObjects(): Skipped invalid data in DIALOGS key in map file %s.\n", __FILE__, file); + fprintf(stderr, "\t%s.readMapObjects(): The invalid line is %s.\n", __FILE__, buffer); + continue; + } + } + }while(buffer[0] != '['); - }else{ - fprintf(stderr, "\t%s.readMapObjects(): Found invalid key in map file %s. Key is %s\n", __FILE__, file, buffer); - free(buffer); - return INVALID_KEY; - } - } + }else{ + fprintf(stderr, "\t%s.readMapObjects(): Found invalid key in map file %s. Key is %s\n", __FILE__, file, buffer); + free(buffer); + return INVALID_KEY; + } + } - fclose(f); - free(buffer); + fclose(f); + free(buffer); - return NO_ERROR; + return NO_ERROR; }