/******************************************** return the type of the tile on map layer at x,y Returned string MUST BE FREED ********************************************/ char * map_get_tile_type(const char * map, int layer, int x, int y) { char * map_type = nullptr; int width; int height; char layer_name[SMALL_BUF]; if (entry_read_int(MAP_TABLE, map, &width, MAP_KEY_WIDTH, nullptr) == RET_NOK) { return nullptr; } if (entry_read_int(MAP_TABLE, map, &height, MAP_KEY_HEIGHT, nullptr) == RET_NOK) { return nullptr; } if (x < 0 || y < 0 || x >= width || y >= height) { return nullptr; } sprintf(layer_name, "%s%d", MAP_KEY_LAYER, layer); entry_read_list_index(MAP_TABLE, map, &map_type, (width * y) + x, layer_name, MAP_KEY_TYPE, nullptr); if (map_type != nullptr) { return map_type; } return map_type; }
/******************************* Update the memory context by reading the character's data file on disk Return RET_NOK if there is an error *******************************/ ret_code_t context_update_from_file(context_t * context) { /* Don't call context_set_* functions here to avoid inter-blocking */ char * result; ret_code_t ret = RET_OK; context_lock_list(); if( context->id == NULL ) { context_unlock_list(); return RET_NOK; } if(entry_read_string(CHARACTER_TABLE,context->id,&result, CHARACTER_KEY_NAME,NULL) == RET_OK ) { free( context->character_name ); context->character_name = result; } else { ret = RET_NOK; } if(entry_read_string(CHARACTER_TABLE,context->id,&result, CHARACTER_KEY_TYPE,NULL) == RET_OK ) { free( context->type ); context->type = result; } else { ret = RET_NOK; } if(entry_read_string(CHARACTER_TABLE,context->id,&result, CHARACTER_KEY_MAP,NULL) == RET_OK ) { free( context->map ); ret = _context_set_map(context, result); free(result); } else { ret = RET_NOK; } int pos_tx; if(entry_read_int(CHARACTER_TABLE,context->id,&pos_tx, CHARACTER_KEY_POS_X,NULL) == RET_NOK ) { ret = RET_NOK; } _context_set_pos_tx(context,pos_tx); int pos_ty; if(entry_read_int(CHARACTER_TABLE,context->id,&pos_ty, CHARACTER_KEY_POS_Y,NULL) == RET_NOK ) { ret = RET_NOK; } _context_set_pos_ty(context,pos_ty); context_unlock_list(); return ret; }
/************************************************************* Move every context on the same coordinate as platform context *************************************************************/ static void platform_move(context_t * platform, const char * map, int x, int y, bool change_map) { context_t * current = context_get_first(); int is_platform; if (entry_read_int(CHARACTER_TABLE, platform->id, &is_platform, CHARACTER_KEY_PLATFORM, nullptr) == RET_NOK) { return; } if (!is_platform) { return; } while (current) { if (current == platform) { current = current->next; continue; } if (platform->pos_tx == current->pos_tx && platform->pos_ty == current->pos_ty && !strcmp(platform->map, current->map)) { do_set_pos(current, map, x, y, change_map); } current = current->next; } }
static void parse_client_conf() { int version; if( already_parsed ) { return; } if (entry_read_int(NULL,CLIENT_CONF_FILE,&version,CLIENT_KEY_VERSION,NULL) == RET_NOK ) { return; } entry_read_string(NULL,CLIENT_CONF_FILE,&option.cursor_over_tile,CLIENT_KEY_CURSOR_OVER_TILE,NULL); entry_read_string(NULL,CLIENT_CONF_FILE,&option.cursor_sprite,CLIENT_KEY_CURSOR_SPRITE,NULL); entry_read_string(NULL,CLIENT_CONF_FILE,&option.cursor_tile,CLIENT_KEY_CURSOR_TILE,NULL); entry_read_string(NULL,CLIENT_CONF_FILE,&option.cursor_equipment,CLIENT_KEY_CURSOR_EQUIPMENT,NULL); entry_read_string(NULL,CLIENT_CONF_FILE,&option.cursor_inventory,CLIENT_KEY_CURSOR_INVENTORY,NULL); entry_read_string(NULL,CLIENT_CONF_FILE,&option.action_move_up,CLIENT_KEY_ACTION_MOVE_UP,NULL); entry_read_string(NULL,CLIENT_CONF_FILE,&option.action_move_down,CLIENT_KEY_ACTION_MOVE_DOWN,NULL); entry_read_string(NULL,CLIENT_CONF_FILE,&option.action_move_left,CLIENT_KEY_ACTION_MOVE_LEFT,NULL); entry_read_string(NULL,CLIENT_CONF_FILE,&option.action_move_right,CLIENT_KEY_ACTION_MOVE_RIGHT,NULL); entry_read_string(NULL,CLIENT_CONF_FILE,&option.action_move_up_left,CLIENT_KEY_ACTION_MOVE_UP_LEFT,NULL); entry_read_string(NULL,CLIENT_CONF_FILE,&option.action_move_up_right,CLIENT_KEY_ACTION_MOVE_UP_RIGHT,NULL); entry_read_string(NULL,CLIENT_CONF_FILE,&option.action_move_down_left,CLIENT_KEY_ACTION_MOVE_DOWN_LEFT,NULL); entry_read_string(NULL,CLIENT_CONF_FILE,&option.action_move_down_right,CLIENT_KEY_ACTION_MOVE_DOWN_RIGHT,NULL); entry_read_string(NULL,CLIENT_CONF_FILE,&option.action_select_character,CLIENT_KEY_ACTION_SELECT_CHARACTER,NULL); entry_read_string(NULL,CLIENT_CONF_FILE,&option.action_select_tile,CLIENT_KEY_ACTION_SELECT_TILE,NULL); entry_read_string(NULL,CLIENT_CONF_FILE,&option.action_select_equipment,CLIENT_KEY_ACTION_SELECT_EQUIPMENT,NULL); entry_read_string(NULL,CLIENT_CONF_FILE,&option.action_select_inventory,CLIENT_KEY_ACTION_SELECT_INVENTORY,NULL); already_parsed = 1; }
/********************************************************* Get NPC value. return 0 if not NPC return 1 if NPC *********************************************************/ int character_get_npc(const char * id) { int npc; if(entry_read_int(CHARACTER_TABLE,id,&npc,CHARACTER_KEY_NPC,NULL) == RET_NOK ) { return 0; } return npc; }
/********************************** Draw the "list" keyword of a layer **********************************/ static void compose_map_scenery(context_t * ctx, int layer_index) { int i = 0; int x = 0; int y = 0; char * image_name = NULL; anim_t * anim; item_t * item; char ** scenery_list = NULL; char layer_name[SMALL_BUF]; sprintf(layer_name,"%s%d",MAP_KEY_LAYER,layer_index); if(entry_get_group_list(MAP_TABLE, ctx->map, &scenery_list,layer_name,MAP_KEY_SCENERY,NULL) == RET_NOK ) { return; } while(scenery_list[i] != NULL ) { if(entry_read_int(MAP_TABLE, ctx->map, &x,layer_name,MAP_KEY_SCENERY,scenery_list[i],MAP_KEY_SCENERY_X,NULL) == RET_NOK ) { i++; continue; } if(entry_read_int(MAP_TABLE, ctx->map, &y,layer_name,MAP_KEY_SCENERY,scenery_list[i],MAP_KEY_SCENERY_Y,NULL) == RET_NOK ) { i++; continue; } if(entry_read_string(MAP_TABLE, ctx->map, &image_name,layer_name,MAP_KEY_SCENERY,scenery_list[i],MAP_KEY_SCENERY_IMAGE,NULL) == RET_NOK ) { i++; continue; } anim = imageDB_get_anim(ctx,image_name); item = item_list_add(&item_list); item_set_pos(item, x, y); item_set_anim(item,anim,0); //item_set_anim(item, x*ctx->tile_width, y*ctx->tile_height, anim,0); i++; } deep_free(scenery_list); }
/**************************************** get the specified attribute's value return -1 if fails ****************************************/ int attribute_get(const char * table, const char *id, const char * attribute) { int current = -1; SDL_LockMutex(attribute_mutex); entry_read_int(table,id,¤t,ATTRIBUTE_GROUP,attribute, ATTRIBUTE_CURRENT, NULL); SDL_UnlockMutex(attribute_mutex); return current; }
/***************************** return the quantity of a resource return -1 on error *****************************/ int resource_get_quantity(const char * item_id) { int quantity; char * my_template; if((my_template=item_is_resource(item_id))==NULL) { return 1; /* unique item */ } free(my_template); if(entry_read_int(ITEM_TABLE,item_id,&quantity,ITEM_QUANTITY, NULL) == RET_NOK ) { return -1; } return quantity; }
/********************************** Compose sprites **********************************/ static void compose_sprite(context_t * ctx,int layer_index) { int layer; context_lock_list(); while(ctx != NULL ) { layer = 0; entry_read_int(CHARACTER_TABLE,ctx->id,&layer,CHARACTER_LAYER,NULL); if( layer == layer_index ) { set_up_sprite(ctx,NULL); } ctx = ctx->next; } context_unlock_list(); }
/*********************************** Write a new tile type into a map file return RET_NOK if fails ***********************************/ ret_code_t map_set_tile_type(const char * map, int layer, const char * type, int x, int y, int network_broadcast) { char * previous_type = nullptr; int width = -1; int index; char layer_name[SMALL_BUF]; if (map == nullptr || type == nullptr) { return RET_NOK; } if (x < 0 || y < 0) { return RET_NOK; } sprintf(layer_name, "%s%d", MAP_KEY_LAYER, layer); // Manage concurrent access to map files SDL_LockMutex(map_mutex); // read size of map grid if (entry_read_int(MAP_TABLE, map, &width, MAP_KEY_WIDTH, nullptr) == RET_NOK) { SDL_UnlockMutex(map_mutex); return RET_NOK; } index = width * y + x; // read previous map type if (entry_read_list_index(MAP_TABLE, map, &previous_type, index, layer_name, MAP_KEY_TYPE, nullptr) == RET_OK) { /* Do not change the type if it already the requested type Avoid calling useless context_broadcast_file */ if (strcmp(previous_type, type) == 0) { free(previous_type); SDL_UnlockMutex(map_mutex); return RET_OK; } free(previous_type); } if (entry_write_list_index(MAP_TABLE, map, type, index, layer_name, MAP_KEY_TYPE, nullptr) == RET_OK) { if (network_broadcast) { context_broadcast_map(map); } } SDL_UnlockMutex(map_mutex); return RET_OK; }
/****************************************************** return 0 if new position OK or if position has not changed. return -1 if the position was not set (because tile not allowed or out of bound) ******************************************************/ int character_set_pos(context_t * ctx, const char * map, int x, int y) { char ** event_id; char * script; char ** param = nullptr; int i; bool change_map = false; int width = x + 1; int height = y + 1; int warpx = 0; int warpy = 0; int ctx_layer = 0; char layer_name[SMALL_BUF]; char buf[SMALL_BUF]; char * coord[3]; int ret_value; int layer; if (ctx == nullptr) { return -1; } // Do nothing if no move if (!strcmp(ctx->map, map) && ctx->pos_tx == x && ctx->pos_ty == y) { return 0; } ctx_layer = 0; entry_read_int(CHARACTER_TABLE, ctx->id, &ctx_layer, CHARACTER_LAYER, nullptr); sprintf(layer_name, "%s%d", MAP_KEY_LAYER, ctx_layer); entry_read_int(MAP_TABLE, map, &width, MAP_KEY_WIDTH, nullptr); entry_read_int(MAP_TABLE, map, &height, MAP_KEY_HEIGHT, nullptr); entry_read_int(MAP_TABLE, map, &warpx, MAP_KEY_WARP_X, nullptr); entry_read_int(MAP_TABLE, map, &warpy, MAP_KEY_WARP_Y, nullptr); // Offscreen script entry_read_string(MAP_TABLE, map, &script, MAP_OFFSCREEN, nullptr); if (script != nullptr && (x < 0 || y < 0 || x >= width || y >= height)) { snprintf(buf, SMALL_BUF, "%d", x); coord[0] = strdup(buf); snprintf(buf, SMALL_BUF, "%d", y); coord[1] = strdup(buf); coord[2] = nullptr; ret_value = action_execute_script(ctx, script, (const char **) coord); free(coord[0]); free(coord[1]); free(script); return ret_value; } if (script) { free(script); } // Coordinates warping if (x < 0) { if (warpy == 0) { return -1; } x = width - 1; } if (y < 0) { if (warpy == 0) { return -1; } y = height - 1; } if (x >= width) { if (warpx == 0) { return -1; } x = 0; } if (y >= height) { if (warpy == 0) { return -1; } y = 0; } // Check if this character is allowed to go to the target tile layer = ctx_layer; while (layer >= 0) { ret_value = map_check_tile(ctx, ctx->id, map, layer, x, y); /* not allowed */ if (ret_value == 0) { return -1; } /* allowed */ if (ret_value == 1) { break; } layer--; } if (layer < 0) { return -1; } if (strcmp(ctx->map, map)) { change_map = true; } /* If this character is a platform, move all characters on it */ platform_move(ctx, map, x, y, change_map); do_set_pos(ctx, map, x, y, change_map); event_id = map_get_event(map, ctx_layer, x, y); if (event_id) { i = 0; while (event_id[i]) { script = nullptr; if (entry_read_string(MAP_TABLE, map, &script, layer_name, MAP_ENTRY_EVENT_LIST, event_id[i], MAP_EVENT_SCRIPT, nullptr) == RET_OK) { entry_read_list(MAP_TABLE, map, ¶m, layer_name, MAP_ENTRY_EVENT_LIST, event_id[i], MAP_EVENT_PARAM, nullptr); } else if (entry_read_string(MAP_TABLE, map, &script, MAP_ENTRY_EVENT_LIST, event_id[i], MAP_EVENT_SCRIPT, nullptr) == RET_OK) { entry_read_list(MAP_TABLE, map, ¶m, MAP_ENTRY_EVENT_LIST, event_id[i], MAP_EVENT_PARAM, nullptr); } if (script == nullptr) { i++; continue; } action_execute_script(ctx, script, (const char **) param); free(script); deep_free(param); param = nullptr; i++; } deep_free(event_id); } character_update_aggro(ctx); return 0; }
/********************************** Draw a single sprite if image_file_name is not NULL, this file is used as an image rather than the normal sprite image **********************************/ static void set_up_sprite(context_t * ctx, const char * image_file_name) { anim_t ** sprite_list; anim_t ** sprite_move_list; item_t * item; int px; int py; int opx; int opy; Uint32 current_time; int angle; int flip; int force_flip; int move_status; char * zoom_str = NULL; double zoom = 1.0; int sprite_align = ALIGN_CENTER; int sprite_offset_y = 0; bool force_position = false; context_t * player_context = context_get_player(); if( ctx->map == NULL ) { return; } if( ctx->in_game == false ) { return; } if( strcmp(ctx->map,player_context->map)) { return; } item = item_list_add(&item_list); current_time = sdl_get_global_time(); // Force position when the player has changed map if( change_map == true ) { ctx->move_start_tick = current_time; ctx->animation_tick = current_time; force_position = true; } // Force position when this context has changed map if( ctx->change_map == true ) { ctx->move_start_tick = current_time; ctx->animation_tick = current_time; ctx->change_map = false; force_position = true; } if( ctx->animation_tick == 0 ) { ctx->animation_tick = current_time; } if( ctx->cur_pos_px == INT_MAX || ctx->cur_pos_py == INT_MAX ) { force_position = true; } // Detect sprite movement, initiate animation if( ctx->pos_changed && force_position == false ) { ctx->pos_changed = false; ctx->move_start_tick = current_time; ctx->start_pos_px = ctx->cur_pos_px; ctx->start_pos_py = ctx->cur_pos_py; /* flip need to remember previous direction to avoid resetting a east -> west flip when a sprite goes to north for instance. On the contrary rotation must not remember previous state, or the rotation will be wrong. Hence the distinction between orientation (no memory) and direction (memory). */ ctx->orientation = 0; // Compute direction if( ctx->pos_tx > ctx->prev_pos_tx ) { ctx->direction &= ~WEST; ctx->direction |= EAST; ctx->orientation |= EAST; } if( ctx->pos_tx < ctx->prev_pos_tx ) { ctx->direction &= ~EAST; ctx->direction |= WEST; ctx->orientation |= WEST; } if( ctx->pos_ty > ctx->prev_pos_ty ) { ctx->direction &= ~NORTH; ctx->direction |= SOUTH; ctx->orientation |= SOUTH; } if( ctx->pos_ty < ctx->prev_pos_ty ) { ctx->direction &= ~SOUTH; ctx->direction |= NORTH; ctx->orientation |= NORTH; } } // Select sprite to display sprite_list = select_sprite(ctx,image_file_name); if( sprite_list == NULL ) { return; } if( sprite_list[0] == NULL ) { free(sprite_list); return; } sprite_move_list = select_sprite_move(ctx,image_file_name); // Get position in pixel px = map_t2p_x(ctx->pos_tx,ctx->pos_ty,default_layer); py = map_t2p_y(ctx->pos_tx,ctx->pos_ty,default_layer); // Get per sprite zoom if(entry_read_string(CHARACTER_TABLE,ctx->id,&zoom_str,CHARACTER_KEY_ZOOM,NULL) == RET_OK ) { zoom = atof(zoom_str); free(zoom_str); } // Align sprite on tile entry_read_int(CHARACTER_TABLE,ctx->id,&sprite_align,CHARACTER_KEY_ALIGN,NULL); if( sprite_align == ALIGN_CENTER ) { px -= ((sprite_list[0]->w*default_layer->map_zoom*zoom)-default_layer->tile_width)/2; py -= ((sprite_list[0]->h*default_layer->map_zoom*zoom)-default_layer->tile_height)/2; } if( sprite_align == ALIGN_LOWER ) { px -= ((sprite_list[0]->w*default_layer->map_zoom*zoom)-default_layer->tile_width)/2; py -= (sprite_list[0]->h*default_layer->map_zoom*zoom)-default_layer->tile_height ; } // Add Y offset entry_read_int(CHARACTER_TABLE,ctx->id,&sprite_offset_y,CHARACTER_KEY_OFFSET_Y,NULL); py += sprite_offset_y; // Set sprite to item item_set_anim_start_tick(item,ctx->animation_tick); if( force_position == true ) { ctx->start_pos_px = px; ctx->cur_pos_px = px; ctx->start_pos_py = py; ctx->cur_pos_py = py; } opx = ctx->start_pos_px; opy = ctx->start_pos_py; item_set_move(item,opx,opy,px,py,ctx->move_start_tick,VIRTUAL_ANIM_DURATION); item_set_save_coordinate(item,&ctx->cur_pos_px,&ctx->cur_pos_py); item_set_anim_array(item,sprite_list); free(sprite_list); item_set_anim_move_array(item,sprite_move_list); free(sprite_move_list); // Get rotation configuration angle = 0; if( ctx->orientation & NORTH && ctx->orientation & EAST ) { entry_read_int(CHARACTER_TABLE,ctx->id,&angle,CHARACTER_KEY_DIR_NE_ROT,NULL); item_set_angle(item,(double)angle); } else if ( ctx->orientation & SOUTH && ctx->orientation & EAST ) { entry_read_int(CHARACTER_TABLE,ctx->id,&angle,CHARACTER_KEY_DIR_SE_ROT,NULL); item_set_angle(item,(double)angle); } else if ( ctx->orientation & SOUTH && ctx->orientation & WEST ) { entry_read_int(CHARACTER_TABLE,ctx->id,&angle,CHARACTER_KEY_DIR_SW_ROT,NULL); item_set_angle(item,(double)angle); } else if ( ctx->orientation & NORTH && ctx->orientation & WEST ) { entry_read_int(CHARACTER_TABLE,ctx->id,&angle,CHARACTER_KEY_DIR_NW_ROT,NULL); item_set_angle(item,(double)angle); } else if ( ctx->orientation & NORTH ) { entry_read_int(CHARACTER_TABLE,ctx->id,&angle,CHARACTER_KEY_DIR_N_ROT,NULL); item_set_angle(item,(double)angle); } else if ( ctx->orientation & SOUTH ) { entry_read_int(CHARACTER_TABLE,ctx->id,&angle,CHARACTER_KEY_DIR_S_ROT,NULL); item_set_angle(item,(double)angle); } else if ( ctx->orientation & WEST ) { entry_read_int(CHARACTER_TABLE,ctx->id,&angle,CHARACTER_KEY_DIR_W_ROT,NULL); item_set_angle(item,(double)angle); } else if ( ctx->orientation & EAST ) { entry_read_int(CHARACTER_TABLE,ctx->id,&angle,CHARACTER_KEY_DIR_E_ROT,NULL); item_set_angle(item,(double)angle); } // Get flip configuration force_flip = 0; entry_read_int(CHARACTER_TABLE,ctx->id,&force_flip,CHARACTER_KEY_FORCE_FLIP,NULL); move_status = ctx->direction; if( force_flip == true ) { move_status = ctx->orientation; } flip = 0; if( angle == 0 ) { if( move_status & NORTH ) { entry_read_int(CHARACTER_TABLE,ctx->id,&flip,CHARACTER_KEY_DIR_N_FLIP,NULL); } if( move_status & SOUTH ) { entry_read_int(CHARACTER_TABLE,ctx->id,&flip,CHARACTER_KEY_DIR_S_FLIP,NULL); } if( move_status & WEST ) { entry_read_int(CHARACTER_TABLE,ctx->id,&flip,CHARACTER_KEY_DIR_W_FLIP,NULL); } if( move_status & EAST ) { entry_read_int(CHARACTER_TABLE,ctx->id,&flip,CHARACTER_KEY_DIR_E_FLIP,NULL); } switch(flip) { case 1: item_set_flip(item,SDL_FLIP_HORIZONTAL); break; case 2: item_set_flip(item,SDL_FLIP_VERTICAL); break; case 3: item_set_flip(item,SDL_FLIP_HORIZONTAL|SDL_FLIP_VERTICAL); break; default: item_set_flip(item,SDL_FLIP_NONE); } } item_set_click_left(item,cb_select_sprite,ctx->id,NULL); item_set_click_right(item,cb_redo_sprite,item,NULL); item_set_zoom_x(item,zoom * default_layer->map_zoom ); item_set_zoom_y(item,zoom * default_layer->map_zoom ); }
/*********************************************************************** Call aggro script for each context in every npc context aggro dist ***********************************************************************/ void character_update_aggro(context_t * agressor) { context_t * target = nullptr; context_t * npc = nullptr; int aggro_dist; char * aggro_script; if (agressor == nullptr) { return; } if (agressor->map == nullptr) { return; } if (agressor->id == nullptr) { return; } /* If the current context is an NPC it might be an aggressor: compute its aggro */ if (character_get_npc(agressor->id) && agressor->luaVM != nullptr) { if (entry_read_int(CHARACTER_TABLE, agressor->id, &aggro_dist, CHARACTER_KEY_AGGRO_DIST, nullptr) == RET_OK) { if (entry_read_string(CHARACTER_TABLE, agressor->id, &aggro_script, CHARACTER_KEY_AGGRO_SCRIPT, nullptr) == RET_OK) { target = context_get_first(); while (target != nullptr) { /* Skip current context */ if (agressor == target) { target = target->next; continue; } if (target->id == nullptr) { target = target->next; continue; } if (target->map == nullptr) { target = target->next; continue; } /* Skip if not on the same map */ if (strcmp(agressor->map, target->map) != 0) { target = target->next; continue; } execute_aggro(agressor, target, aggro_script, aggro_dist); target = target->next; } free(aggro_script); } } } /* Compute aggro of all other NPC to the current context */ target = agressor; npc = context_get_first(); while (npc != nullptr) { /* Skip current context */ if (target == npc) { npc = npc->next; continue; } if (npc->id == nullptr) { npc = npc->next; continue; } if (npc->map == nullptr) { npc = npc->next; continue; } if (npc->luaVM == nullptr) { npc = npc->next; continue; } /* Skip if not on the same map */ if (strcmp(npc->map, target->map) != 0) { npc = npc->next; continue; } if (entry_read_int(CHARACTER_TABLE, npc->id, &aggro_dist, CHARACTER_KEY_AGGRO_DIST, nullptr) == RET_NOK) { npc = npc->next; continue; } if (entry_read_string(CHARACTER_TABLE, npc->id, &aggro_script, CHARACTER_KEY_AGGRO_SCRIPT, nullptr) == RET_NOK) { npc = npc->next; continue; } execute_aggro(npc, target, aggro_script, aggro_dist); free(aggro_script); npc = npc->next; } }
/********************************** Compose item on map **********************************/ static void compose_item(context_t * ctx,int layer_index) { char * sprite_name = NULL; int sprite_align = ALIGN_CENTER; int sprite_offset_y = 0; anim_t * anim; item_t * item; int x; int y; int temp_x; int temp_y; char ** item_id; int i; static TTF_Font * font = NULL; char * mytemplate; int quantity; char buf[SMALL_BUF]; char layer_name[SMALL_BUF]; sprintf(layer_name,"%s%d",MAP_KEY_LAYER,layer_index); if(entry_get_group_list(MAP_TABLE,ctx->map,&item_id,layer_name,MAP_ENTRY_ITEM_LIST,NULL) == RET_NOK ) { return; } font = font_get(ctx,ITEM_FONT, ITEM_FONT_SIZE); i=0; while( item_id[i] != NULL ) { sprite_align = ALIGN_CENTER; if(entry_read_int(MAP_TABLE,ctx->map,&x,layer_name,MAP_ENTRY_ITEM_LIST,item_id[i],MAP_ITEM_POS_X,NULL) == RET_NOK ) { i++; continue; } if(entry_read_int(MAP_TABLE,ctx->map,&y,layer_name,MAP_ENTRY_ITEM_LIST,item_id[i],MAP_ITEM_POS_Y,NULL) == RET_NOK ) { i++; continue; } mytemplate = item_is_resource(item_id[i]); if ( mytemplate == NULL ) { if(entry_read_string(ITEM_TABLE,item_id[i],&sprite_name,ITEM_SPRITE,NULL) == RET_NOK ) { i++; continue; } entry_read_int(ITEM_TABLE,item_id[i],&sprite_align,ITEM_ALIGN,NULL); entry_read_int(ITEM_TABLE,item_id[i],&sprite_offset_y,ITEM_OFFSET_Y,NULL); } else { if(entry_read_string(ITEM_TEMPLATE_TABLE,mytemplate,&sprite_name,ITEM_SPRITE,NULL) == RET_NOK ) { free(mytemplate); i++; continue; } entry_read_int(ITEM_TEMPLATE_TABLE,mytemplate,&sprite_align,ITEM_ALIGN,NULL); entry_read_int(ITEM_TEMPLATE_TABLE,mytemplate,&sprite_offset_y,ITEM_OFFSET_Y,NULL); free(mytemplate); } item = item_list_add(&item_list); anim = imageDB_get_anim(ctx,sprite_name); free(sprite_name); temp_x = map_t2p_x(x,y,default_layer); temp_y = map_t2p_y(x,y,default_layer); x = temp_x; y = temp_y; /* Align on tile */ if( sprite_align == ALIGN_CENTER ) { x -= ((anim->w*default_layer->map_zoom)-default_layer->tile_width)/2; y -= ((anim->h*default_layer->map_zoom)-default_layer->tile_height)/2; } if( sprite_align == ALIGN_LOWER ) { x -= ((anim->w*default_layer->map_zoom)-default_layer->tile_width)/2; y -= (anim->h*default_layer->map_zoom)-default_layer->tile_height; } y += sprite_offset_y; item_set_pos(item,x,y); item_set_anim(item,anim,0); item_set_zoom_x(item, default_layer->map_zoom ); item_set_zoom_y(item, default_layer->map_zoom ); if(font) { quantity = resource_get_quantity(item_id[i]); sprintf(buf,"%d",quantity); item_set_string(item,buf); item_set_font(item,font); } i++; } deep_free(item_id); }
/********************************************** Delete an event on map at given coordinate return RET_NOK if fails **********************************************/ ret_code_t map_delete_event(const char * map, int layer, const char * script, int x, int y) { char ** eventlist; int i = 0; int mapx; int mapy; char * map_script = nullptr; const char * id = nullptr; char layer_name[SMALL_BUF]; if (x < 0 || y < 0) { return RET_NOK; } sprintf(layer_name, "%s%d", MAP_KEY_LAYER, layer); /* Manage concurrent acces to map files */ SDL_LockMutex(map_mutex); /* Search events on the specified tile */ if (entry_get_group_list(MAP_TABLE, map, &eventlist, layer_name, MAP_ENTRY_EVENT_LIST, nullptr) == RET_NOK) { SDL_UnlockMutex(map_mutex); return RET_NOK; } while (eventlist[i] != nullptr) { if (entry_read_int(MAP_TABLE, map, &mapx, layer_name, MAP_ENTRY_EVENT_LIST, eventlist[i], MAP_EVENT_POS_X, nullptr) == RET_NOK) { i++; continue; } if (entry_read_int(MAP_TABLE, map, &mapy, layer_name, MAP_ENTRY_EVENT_LIST, eventlist[i], MAP_EVENT_POS_Y, nullptr) == RET_NOK) { i++; continue; } if (entry_read_string(MAP_TABLE, map, &map_script, layer_name, MAP_ENTRY_EVENT_LIST, eventlist[i], MAP_EVENT_SCRIPT, nullptr) == RET_NOK) { i++; continue; } if (x == mapx && y == mapy && !strcmp(map_script, script)) { id = eventlist[i]; free(map_script); break; } free(map_script); i++; } if (id == nullptr) { SDL_UnlockMutex(map_mutex); return RET_NOK; } /* remove the event from the events list of the map */ if (entry_remove_group(MAP_TABLE, map, id, layer_name, MAP_ENTRY_EVENT_LIST, nullptr) == RET_NOK) { SDL_UnlockMutex(map_mutex); return RET_NOK; } deep_free(eventlist); SDL_UnlockMutex(map_mutex); /* Send network notifications */ context_broadcast_map(map); return RET_OK; }
/*********************************** check if id is allowed to go on a tile return 1 if the context is allowed to go to the tile at coord x,y return 0 if the context is NOT allowed to go to the tile at coord x,y return RET_NOK on error or no data found *************************************/ ret_code_t map_check_tile(context_t * ctx, char * id, const char * map, int layer, int x, int y) { char * script; char sx[64]; char sy[64]; char * param[5]; int res; char * tile_type; char ** allowed_tile; int i = 0; int width = 0; int height = 0; if (entry_read_int(MAP_TABLE, map, &width, MAP_KEY_WIDTH, nullptr) == RET_NOK) { return RET_NOK; } if (entry_read_int(MAP_TABLE, map, &height, MAP_KEY_HEIGHT, nullptr) == RET_NOK) { return RET_NOK; } if (x < 0 || y < 0 || x >= width || y >= height) { return 0; } // If there is an allowed_tile_script, run it if (entry_read_string(CHARACTER_TABLE, id, &script, CHARACTER_KEY_ALLOWED_TILE_SCRIPT, nullptr) == RET_OK) { param[0] = id; param[1] = (char *) map; sprintf(sx, "%d", x); sprintf(sy, "%d", y); param[2] = sx; param[3] = sy; param[4] = nullptr; res = action_execute_script(ctx, script, (const char**) param); free(script); return res; } // Read tile at given index on this map entry_read_int(CHARACTER_TABLE, id, &layer, CHARACTER_LAYER, nullptr); tile_type = get_tile_type_through_layer(map, layer, x, y); // Allow tile if no type defined if (tile_type == nullptr) { return 1; } // Allow tile if its type is empty (i.e. "") if (tile_type[0] == 0) { free(tile_type); return 1; } // If there is allowed_tile list, check it if (entry_read_list(CHARACTER_TABLE, id, &allowed_tile, CHARACTER_KEY_ALLOWED_TILE, nullptr) == RET_OK) { i = 0; while (allowed_tile[i] != nullptr) { if (strcmp(allowed_tile[i], tile_type) == 0) { deep_free(allowed_tile); free(tile_type); return 1; } i++; } deep_free(allowed_tile); free(tile_type); return 0; } free(tile_type); // Allow all tiles by default return 1; }
/*************************************************************************** Add the specified value to the specified attribute Check on max and min are done and call to on_* scripts are done if set ctx is the context of the source of the attribute change request id is the id of the target of the change return -1 if fails ***************************************************************************/ int attribute_change(context_t * context, const char * table, const char * id, const char * attribute, int value) { int current; int old; int min; int max; char buf[SMALL_BUF]; bool do_min_action = false; bool do_down_action = false; bool do_max_action = false; bool do_up_action = false; char * action; char * min_action = NULL; char * down_action = NULL; char * max_action = NULL; char * up_action = NULL; SDL_LockMutex(attribute_mutex); if(entry_read_int(table,id,¤t,ATTRIBUTE_GROUP,attribute, ATTRIBUTE_CURRENT, NULL) == RET_NOK) { SDL_UnlockMutex(attribute_mutex); return -1; } if(entry_read_int(table,id,&min,ATTRIBUTE_GROUP,attribute, ATTRIBUTE_MIN, NULL) == RET_NOK) { min = -1; } if(entry_read_int(table,id,&max,ATTRIBUTE_GROUP,attribute, ATTRIBUTE_MAX, NULL) == RET_NOK) { max = -1; } old = current; current = current + value; if( min != -1 ) { if(current <= min) { do_min_action = true; current = min; } } if( max != -1 ) { if(current >= max) { do_max_action = true; current = max; } } if(entry_write_int(table,id,current,ATTRIBUTE_GROUP,attribute, ATTRIBUTE_CURRENT, NULL) == RET_NOK ) { SDL_UnlockMutex(attribute_mutex); return -1; } if(entry_write_int(table,id,old,ATTRIBUTE_GROUP,attribute, ATTRIBUTE_PREVIOUS, NULL) == RET_NOK ) { SDL_UnlockMutex(attribute_mutex); return -1; } // Check automatic actions if( value < 0 ) { if( do_min_action == true ) { if(entry_read_string(table,id,&action,ATTRIBUTE_GROUP,attribute, ATTRIBUTE_ON_MIN, NULL) == RET_NOK ) { do_min_action = false; } else { min_action = action; } } if(entry_read_string(table,id,&action,ATTRIBUTE_GROUP,attribute, ATTRIBUTE_ON_DOWN, NULL) == RET_OK ) { do_down_action = true; down_action = action; } } if( value > 0 ) { if( do_max_action == true ) { if(entry_read_string(table,id,&action,ATTRIBUTE_GROUP,attribute, ATTRIBUTE_ON_MAX, NULL) == RET_NOK ) { do_max_action = false; } else { max_action = action; } } if(entry_read_string(table,id,&action,ATTRIBUTE_GROUP,attribute, ATTRIBUTE_ON_UP, NULL) == RET_OK ) { do_up_action = true; up_action = action; } } SDL_UnlockMutex(attribute_mutex); // do automatic actions if( do_down_action == true && down_action != NULL ) { action_execute_script(context,down_action,NULL); } if( down_action ) { free(down_action); } if( do_min_action == true && min_action != NULL ) { action_execute_script(context,min_action,NULL); } if( min_action ) { free(min_action); } if( do_up_action == true && up_action != NULL ) { action_execute_script(context,up_action,NULL); } if( min_action ) { free(up_action); } if( do_max_action == true && max_action != NULL ) { action_execute_script(context,max_action,NULL); free(max_action); } if( max_action ) { free(max_action); } sprintf(buf,"%s.%s.%s",ATTRIBUTE_GROUP,attribute,ATTRIBUTE_CURRENT); network_broadcast_entry_int(table,id,buf,current,true); sprintf(buf,"%s.%s.%s",ATTRIBUTE_GROUP,attribute,ATTRIBUTE_PREVIOUS); network_broadcast_entry_int(table,id,buf,old,true); return 0; }
/************************************** delete an item on context's map **************************************/ char * map_delete_item(const char * map, int layer, int x, int y) { char ** itemlist; int i = 0; int mapx; int mapy; const char * id = nullptr; char * saved_item = nullptr; char layer_name[SMALL_BUF]; if (x < 0 || y < 0) { return nullptr; } sprintf(layer_name, "%s%d", MAP_KEY_LAYER, layer); /* Manage concurrent acces to map files */ SDL_LockMutex(map_mutex); /* Search the items on the specified tile */ if (entry_get_group_list(MAP_TABLE, map, &itemlist, layer_name, MAP_ENTRY_ITEM_LIST, nullptr) == RET_NOK) { SDL_UnlockMutex(map_mutex); return nullptr; } while (itemlist[i] != nullptr) { if (entry_read_int(MAP_TABLE, map, &mapx, layer_name, MAP_ENTRY_ITEM_LIST, itemlist[i], MAP_ITEM_POS_X, nullptr) == RET_NOK) { SDL_UnlockMutex(map_mutex); deep_free(itemlist); return nullptr; } if (entry_read_int(MAP_TABLE, map, &mapy, layer_name, MAP_ENTRY_ITEM_LIST, itemlist[i], MAP_ITEM_POS_Y, nullptr) == RET_NOK) { SDL_UnlockMutex(map_mutex); deep_free(itemlist); return nullptr; } if (x == mapx && y == mapy) { id = itemlist[i]; saved_item = strdup(itemlist[i]); break; } i++; } if (id == nullptr) { deep_free(itemlist); if (saved_item) { free(saved_item); } SDL_UnlockMutex(map_mutex); return nullptr; } /* remove the item from the item list of the map */ if (entry_remove_group(MAP_TABLE, map, id, layer_name, MAP_ENTRY_ITEM_LIST, nullptr) == RET_NOK) { deep_free(itemlist); free(saved_item); SDL_UnlockMutex(map_mutex); return nullptr; } deep_free(itemlist); SDL_UnlockMutex(map_mutex); /* Send network notifications */ context_broadcast_map(map); return saved_item; }
/****************************************** Add a layer filled with image_name on map return RET_NOK on failure ***********************************************/ ret_code_t map_add_layer(const char * map_name, int layer, int w, int h, int tile_w, int tile_h, const char * default_tile, const char * default_type) { char layer_name[SMALL_BUF]; sprintf(layer_name, "%s%d", MAP_KEY_LAYER, layer); if (w > 0) { if (entry_write_int(MAP_TABLE, map_name, w, layer_name, MAP_KEY_WIDTH, nullptr) == RET_NOK) { return RET_NOK; } } else { // No specific dimension, take the map's global one if (entry_read_int(MAP_TABLE, map_name, &w, MAP_KEY_WIDTH, nullptr) == RET_NOK) { return RET_NOK; } } if (h > 0) { if (entry_write_int(MAP_TABLE, map_name, h, layer_name, MAP_KEY_HEIGHT, nullptr) == RET_NOK) { return RET_NOK; } } else { // No specific dimension, take the map's global one if (entry_read_int(MAP_TABLE, map_name, &h, MAP_KEY_HEIGHT, nullptr) == RET_NOK) { return RET_NOK; } } if (tile_w > 0) { if (entry_write_int(MAP_TABLE, map_name, tile_w, layer_name, MAP_KEY_TILE_WIDTH, nullptr) == RET_NOK) { return RET_NOK; } } if (tile_h > 0) { if (entry_write_int(MAP_TABLE, map_name, tile_h, layer_name, MAP_KEY_TILE_HEIGHT, nullptr) == RET_NOK) { return RET_NOK; } } int i; char ** tile_array = (char**) malloc(((w * h) + 1) * sizeof(char *)); // Write default tile for (i = 0; i < (w * h); i++) { tile_array[i] = (char *) default_tile; } tile_array[i] = nullptr; // End of list if (entry_write_list(MAP_TABLE, map_name, tile_array, layer_name, MAP_KEY_SET, nullptr) == RET_NOK) { free(tile_array); return RET_NOK; } // Write default type for (i = 0; i < (w * h); i++) { tile_array[i] = (char *) default_type; } tile_array[i] = nullptr; // End of list if (entry_write_list(MAP_TABLE, map_name, tile_array, layer_name, MAP_KEY_TYPE, nullptr) == RET_NOK) { free(tile_array); return RET_NOK; } free(tile_array); return RET_OK; }
/********************************** Compose the character select screen **********************************/ item_t * scr_play_compose(context_t * ctx) { int bg_red = 0; int bg_blue = 0; int bg_green = 0; char * map_filename; int layer_index = 0; char * old_sfx = NULL; option = option_get(); if(item_list) { item_list_free(item_list); item_list = NULL; } if(ctx->map == NULL ) { if(context_update_from_file(ctx) == RET_NOK) { return NULL; } } if(init) { /* Register this character to receive server notifications */ network_request_start(ctx,ctx->id); ui_play_init(); init = false; } sdl_free_keycb(); sdl_free_mousecb(); sdl_add_mousecb(MOUSE_WHEEL_UP,cb_zoom); sdl_add_mousecb(MOUSE_WHEEL_DOWN,cb_unzoom); change_map = ctx->change_map; if( change_map == true ) { map_filename = strconcat( MAP_TABLE,"/",ctx->map,NULL); network_send_req_file(ctx,map_filename); free(map_filename); if(default_layer) { map_layer_delete(default_layer); } default_layer = map_layer_new(ctx->map,DEFAULT_LAYER,NULL); } if( default_layer && default_layer->active ) { // Make sure map data are available for(layer_index = 0; layer_index < MAX_LAYER; layer_index++) { compose_map_set(ctx,layer_index); compose_map_scenery(ctx,layer_index); compose_item(ctx,layer_index); compose_sprite(ctx,layer_index); compose_type(ctx,layer_index); } compose_map_button(ctx); compose_select(ctx); ui_play_compose(ctx,item_list); // force virtual coordinate on map change if( change_map == true ) { sdl_force_virtual_x(map_t2p_x(ctx->pos_tx,ctx->pos_ty,default_layer) + default_layer->col_width[ctx->pos_tx%default_layer->col_num]/2 + default_layer->row_width[ctx->pos_ty%default_layer->row_num]/2 ); sdl_force_virtual_y(map_t2p_y(ctx->pos_tx,ctx->pos_ty,default_layer) + default_layer->col_height[ctx->pos_tx%default_layer->col_num]/2 + default_layer->row_height[ctx->pos_ty%default_layer->row_num]/2 ); } // set virtual coordinate on the same map else { sdl_set_virtual_x(map_t2p_x(ctx->pos_tx,ctx->pos_ty,default_layer) + default_layer->col_width[ctx->pos_tx%default_layer->col_num]/2 + default_layer->row_width[ctx->pos_ty%default_layer->row_num]/2 ); sdl_set_virtual_y(map_t2p_y(ctx->pos_tx,ctx->pos_ty,default_layer) + default_layer->col_height[ctx->pos_tx%default_layer->col_num]/2 + default_layer->row_height[ctx->pos_ty%default_layer->row_num]/2 ); } } entry_read_int(MAP_TABLE,ctx->map,&bg_red,MAP_KEY_BG_RED,NULL); entry_read_int(MAP_TABLE,ctx->map,&bg_blue,MAP_KEY_BG_BLUE,NULL); entry_read_int(MAP_TABLE,ctx->map,&bg_green,MAP_KEY_BG_GREEN,NULL); SDL_SetRenderDrawColor(ctx->render, bg_red, bg_blue, bg_green, 255); old_sfx = sfx; sfx = NULL; entry_read_string(MAP_TABLE,ctx->map,&sfx,MAP_SFX,NULL); if(old_sfx) { if( sfx ) { if( strcmp(old_sfx,sfx) ) { sfx_stop(ctx,old_sfx); } } else { // sfx == NULL sfx_stop(ctx,old_sfx); } free(old_sfx); } if( sfx && sfx[0]!=0 ) { sfx_play(ctx,sfx,NO_RESTART); } return item_list; }