/****************************************** Add a scenery on map at given coordinate return nullptr if fails return the scenery id is success the return scenery id must be freed by caller ***********************************************/ char * map_add_scenery(const char * map, int layer, int x, int y, const char * image_name) { char layer_name[SMALL_BUF]; char * id; if (x < 0 || y < 0) { return nullptr; } sprintf(layer_name, "%s%d", MAP_KEY_LAYER, layer); /* Make sure the MAP_KEY_SCENERY group exists */ entry_group_create(MAP_TABLE, map, layer_name, MAP_KEY_SCENERY, nullptr); id = entry_get_unused_group(MAP_TABLE, map, layer_name, MAP_KEY_SCENERY, nullptr); if (id == nullptr) { return nullptr; } SDL_LockMutex(map_mutex); if (entry_write_int(MAP_TABLE, map, x, layer_name, MAP_KEY_SCENERY, id, MAP_KEY_SCENERY_X, nullptr) == RET_NOK) { entry_remove_group(MAP_TABLE, map, id, layer_name, MAP_KEY_SCENERY, nullptr); SDL_UnlockMutex(map_mutex); free(id); return nullptr; } if (entry_write_int(MAP_TABLE, map, y, layer_name, MAP_KEY_SCENERY, id, MAP_KEY_SCENERY_Y, nullptr) == RET_NOK) { entry_remove_group(MAP_TABLE, map, id, layer_name, MAP_KEY_SCENERY, nullptr); SDL_UnlockMutex(map_mutex); free(id); return nullptr; } if (entry_write_string(MAP_TABLE, map, image_name, layer_name, MAP_KEY_SCENERY, id, MAP_KEY_SCENERY_IMAGE, nullptr) == RET_NOK) { entry_remove_group(MAP_TABLE, map, id, layer_name, MAP_KEY_SCENERY, nullptr); SDL_UnlockMutex(map_mutex); free(id); return nullptr; } SDL_UnlockMutex(map_mutex); // Send network notifications context_broadcast_map(map); return id; }
/****************************************************** Create a new character based on the specified template return the id of the newly created character the returned string MUST BE FREED by caller return nullptr if fails *******************************************************/ char * character_create_from_template(context_t * ctx, const char * my_template, const char * map, int layer, int x, int y) { char * new_id; new_id = file_new(CHARACTER_TABLE, nullptr); if (file_copy(CHARACTER_TEMPLATE_TABLE, my_template, CHARACTER_TABLE, new_id) == false) { file_delete(CHARACTER_TABLE, new_id); return nullptr; } // Check if new character is allowed to be created here if (map_check_tile(ctx, new_id, map, layer, x, y) == 0) { entry_destroy(CHARACTER_TABLE, new_id); file_delete(CHARACTER_TABLE, new_id); free(new_id); return nullptr; } // Write position if (entry_write_string(CHARACTER_TABLE, new_id, map, CHARACTER_KEY_MAP, nullptr) == RET_NOK) { entry_destroy(CHARACTER_TABLE, new_id); file_delete(CHARACTER_TABLE, new_id); free(new_id); return nullptr; } if (entry_write_int(CHARACTER_TABLE, new_id, x, CHARACTER_KEY_POS_X, nullptr) == RET_NOK) { entry_destroy(CHARACTER_TABLE, new_id); file_delete(CHARACTER_TABLE, new_id); free(new_id); return nullptr; } if (entry_write_int(CHARACTER_TABLE, new_id, y, CHARACTER_KEY_POS_Y, nullptr) == RET_NOK) { entry_destroy(CHARACTER_TABLE, new_id); file_delete(CHARACTER_TABLE, new_id); free(new_id); return nullptr; } return new_id; }
/*********************************** Set custom tiling of a map's layer if layer == -1, set the map's grid custom rows return RET_NOK if fails ***********************************/ ret_code_t map_set_custom_row(const char * map, int layer, int num, int width, int height) { char layer_name[SMALL_BUF]; char width_name[SMALL_BUF]; char height_name[SMALL_BUF]; ret_code_t res; if (map == nullptr) { return RET_NOK; } /* Manage concurrent access to map files */ SDL_LockMutex(map_mutex); if (num == 0) { sprintf(width_name, "%s", MAP_KEY_ROW_WIDTH); sprintf(height_name, "%s", MAP_KEY_ROW_HEIGHT); } else { sprintf(width_name, "%s%d", MAP_KEY_ROW_WIDTH, num); sprintf(height_name, "%s%d", MAP_KEY_ROW_HEIGHT, num); } if (layer == -1) { res = entry_write_int(MAP_TABLE, map, width, width_name, nullptr); if (res == RET_OK) { res = entry_write_int(MAP_TABLE, map, height, height_name, nullptr); } } else { sprintf(layer_name, "%s%d", MAP_KEY_LAYER, layer); res = entry_write_int(MAP_TABLE, map, width, layer_name, width_name, nullptr); if (res == RET_OK) { res = entry_write_int(MAP_TABLE, map, height, layer_name, height_name, nullptr); } } SDL_UnlockMutex(map_mutex); return res; }
static void do_set_pos(context_t * ctx,const char * map, int x, int y, bool change_map) { context_set_map(ctx,map); context_set_pos_tx(ctx,x); context_set_pos_ty(ctx,y); entry_write_string(CHARACTER_TABLE,ctx->id,map,CHARACTER_KEY_MAP,NULL); entry_write_int(CHARACTER_TABLE,ctx->id,x,CHARACTER_KEY_POS_X,NULL); entry_write_int(CHARACTER_TABLE,ctx->id,y,CHARACTER_KEY_POS_Y,NULL); context_spread(ctx); if( change_map == true ) { context_request_other_context(ctx); } }
/****************************************************** Create a new character based on the specified template return the id of the newly created character the returned string MUST BE FREED by caller return NULL if fails *******************************************************/ char * character_create_from_template(context_t * ctx,const char * my_template,const char * map, int layer, int x, int y) { char * new_id; char * templatename; char * fullname; new_id = file_new(CHARACTER_TABLE,NULL); templatename = strconcat(base_directory,"/",CHARACTER_TEMPLATE_TABLE,"/",my_template,NULL); fullname = strconcat(base_directory,"/",CHARACTER_TABLE,"/",new_id,NULL); file_copy(templatename,fullname); free(templatename); free(fullname); /* Check if new character is allowed to be created here */ if(map_check_tile(ctx,new_id,map,layer,x,y) == 0) { entry_destroy(CHARACTER_TABLE,new_id); file_delete(CHARACTER_TABLE,new_id); free(new_id); return NULL; } /* Write position */ if(entry_write_string(CHARACTER_TABLE,new_id,map,CHARACTER_KEY_MAP,NULL) == RET_NOK ) { entry_destroy(CHARACTER_TABLE,new_id); file_delete(CHARACTER_TABLE,new_id); free(new_id); return NULL; } if(entry_write_int(CHARACTER_TABLE,new_id,x,CHARACTER_KEY_POS_X,NULL) == RET_NOK ) { entry_destroy(CHARACTER_TABLE,new_id); file_delete(CHARACTER_TABLE,new_id); free(new_id); return NULL; } if(entry_write_int(CHARACTER_TABLE,new_id,y,CHARACTER_KEY_POS_Y,NULL) == RET_NOK ) { entry_destroy(CHARACTER_TABLE,new_id); file_delete(CHARACTER_TABLE,new_id); free(new_id); return NULL; } return new_id; }
/*********************************** Set custom tiling of a map's layer if layer == -1, set the map's grid custom columns return RET_NOK if fails ***********************************/ ret_code_t map_set_custom_column(const char * map, int layer, int num, int width, int height) { char layer_name[SMALL_BUF]; char width_name[SMALL_BUF]; char height_name[SMALL_BUF]; ret_code_t res; if (map == nullptr) { return RET_NOK; } // Manage concurrent access to map files SDL_LockMutex(map_mutex); sprintf(width_name, "%s%d", MAP_KEY_COL_WIDTH, num); sprintf(height_name, "%s%d", MAP_KEY_COL_HEIGHT, num); // Map grid settings if (layer == -1) { res = entry_write_int(MAP_TABLE, map, width, width_name, nullptr); if (res == RET_OK) { res = entry_write_int(MAP_TABLE, map, height, height_name, nullptr); } } // Layer specific setting else { sprintf(layer_name, "%s%d", MAP_KEY_LAYER, layer); res = entry_write_int(MAP_TABLE, map, width, layer_name, width_name, nullptr); if (res == RET_OK) { res = entry_write_int(MAP_TABLE, map, height, layer_name, height_name, nullptr); } } SDL_UnlockMutex(map_mutex); return res; }
/*********************************** Create a new map or add a map layer. Return the name of the new map Return string must be freed by caller *************************************/ char * map_new(const char *name, int w, int h, int tile_w, int tile_h) { char * map_name; if (w < 0 || h < 0) { return nullptr; } map_name = file_new(MAP_TABLE, name); if (map_name == nullptr) { return nullptr; } if (entry_write_int(MAP_TABLE, map_name, w, MAP_KEY_HEIGHT, nullptr) == RET_NOK) { free(map_name); return nullptr; } if (entry_write_int(MAP_TABLE, map_name, h, MAP_KEY_WIDTH, nullptr) == RET_NOK) { free(map_name); return nullptr; } if (entry_write_int(MAP_TABLE, map_name, tile_w, MAP_KEY_TILE_WIDTH, nullptr) == RET_NOK) { free(map_name); return nullptr; } if (entry_write_int(MAP_TABLE, map_name, tile_h, MAP_KEY_TILE_HEIGHT, nullptr) == RET_NOK) { free(map_name); return nullptr; } return map_name; }
/******************************* Write a context to server's disk return RET_NOK on error *******************************/ ret_code_t context_write_to_file(context_t * context) { context_lock_list(); if( context->id == NULL ) { context_unlock_list(); return RET_NOK; } entry_write_string(CHARACTER_TABLE, context->id,context->type,CHARACTER_KEY_TYPE,NULL); entry_write_string(CHARACTER_TABLE, context->id,context->map,CHARACTER_KEY_MAP, NULL); entry_write_int(CHARACTER_TABLE, context->id,context->pos_tx,CHARACTER_KEY_POS_X, NULL); entry_write_int(CHARACTER_TABLE, context->id,context->pos_ty,CHARACTER_KEY_POS_Y, NULL); context_unlock_list(); return RET_OK; }
/********************************************************* Set NPC to the value passed. If the value is != 0 , the NPC is instanciated return -1 on error *********************************************************/ int character_set_npc(const char * id, int npc) { if(entry_write_int(CHARACTER_TABLE,id,npc,CHARACTER_KEY_NPC,NULL) == RET_NOK ) { return -1; } if(npc) { instantiate_npc(id); } return 0; }
/********************************************************************* set the specified attribute's value without check of min and max return -1 if fails *********************************************************************/ int attribute_set(const char * table, const char * id, const char * attribute, int value) { SDL_LockMutex(attribute_mutex); if(entry_write_int(table,id,value,ATTRIBUTE_GROUP,attribute, ATTRIBUTE_CURRENT, NULL) == RET_NOK ) { SDL_UnlockMutex(attribute_mutex); return -1; } SDL_UnlockMutex(attribute_mutex); return 0; }
/****************************************** Add an item on map at given coordinate return RET_NOK if fails ******************************************/ ret_code_t map_add_item(const char * map, int layer, const char * id, int x, int y) { char layer_name[SMALL_BUF]; if (x < 0 || y < 0) { return RET_NOK; } sprintf(layer_name, "%s%d", MAP_KEY_LAYER, layer); SDL_LockMutex(map_mutex); if (entry_write_int(MAP_TABLE, map, x, layer_name, MAP_ENTRY_ITEM_LIST, id, MAP_ITEM_POS_X, nullptr) == RET_NOK) { entry_remove_group(MAP_TABLE, map, id, layer_name, MAP_ENTRY_ITEM_LIST, nullptr); SDL_UnlockMutex(map_mutex); return RET_NOK; } if (entry_write_int(MAP_TABLE, map, y, layer_name, MAP_ENTRY_ITEM_LIST, id, MAP_ITEM_POS_Y, nullptr) == RET_NOK) { entry_remove_group(MAP_TABLE, map, id, layer_name, MAP_ENTRY_ITEM_LIST, nullptr); SDL_UnlockMutex(map_mutex); return RET_NOK; } SDL_UnlockMutex(map_mutex); // Send network notifications context_broadcast_map(map); return RET_OK; }
/***************************** set the quantity of a resource return -1 on error *****************************/ int resource_set_quantity(context_t * context, const char * item_id, int quantity) { char * my_template; /* unique item */ if((my_template=item_is_resource(item_id))==NULL) { return -1; } free(my_template); if(entry_write_int(ITEM_TABLE,item_id,quantity,ITEM_QUANTITY, NULL) == RET_NOK ) { return -1; } network_send_table_file(context,ITEM_TABLE,item_id); return 0; }
/*********************************************************** Create a new resource with the specified quantity return the id of the newly created resource the returned string must be freed by caller return NULL if fails ***********************************************************/ char * resource_new(const char * my_template, int quantity) { char * new_id; new_id = item_create_empty(); if( new_id == NULL ) { return NULL; } if(entry_write_string(ITEM_TABLE,new_id,my_template,ITEM_TEMPLATE, NULL) == RET_NOK ) { entry_destroy(ITEM_TABLE,new_id); return NULL; } if(entry_write_int(ITEM_TABLE,new_id,quantity,ITEM_QUANTITY, NULL) == RET_NOK ) { entry_destroy(ITEM_TABLE,new_id); return NULL; } return new_id; }
/****************************************** Add an event on map at given coordinate return nullptr if fails return the event id is success the return event id must be freed by caller ***********************************************/ char * map_add_event(const char * map, int layer, const char * script, int x, int y) { char * id; char layer_name[SMALL_BUF]; if (x < 0 || y < 0) { return nullptr; } sprintf(layer_name, "%s%d", MAP_KEY_LAYER, layer); // Make sure the MAP_ENTRY_EVENT_LIST group exists entry_group_create(MAP_TABLE, map, layer_name, MAP_ENTRY_EVENT_LIST, nullptr); id = entry_get_unused_group(MAP_TABLE, map, layer_name, MAP_ENTRY_EVENT_LIST, nullptr); if (id == nullptr) { return nullptr; } SDL_LockMutex(map_mutex); if (entry_write_int(MAP_TABLE, map, x, layer_name, MAP_ENTRY_EVENT_LIST, id, MAP_EVENT_POS_X, nullptr) == RET_NOK) { entry_remove_group(MAP_TABLE, map, id, layer_name, MAP_ENTRY_EVENT_LIST, nullptr); free(id); SDL_UnlockMutex(map_mutex); return nullptr; } if (entry_write_int(MAP_TABLE, map, y, layer_name, MAP_ENTRY_EVENT_LIST, id, MAP_EVENT_POS_Y, nullptr) == RET_NOK) { entry_remove_group(MAP_TABLE, map, id, layer_name, MAP_ENTRY_EVENT_LIST, nullptr); free(id); SDL_UnlockMutex(map_mutex); return nullptr; } if (entry_write_string(MAP_TABLE, map, script, layer_name, MAP_ENTRY_EVENT_LIST, id, MAP_EVENT_SCRIPT, nullptr) == RET_NOK) { entry_remove_group(MAP_TABLE, map, id, layer_name, MAP_ENTRY_EVENT_LIST, nullptr); free(id); SDL_UnlockMutex(map_mutex); return nullptr; } SDL_UnlockMutex(map_mutex); // Send network notifications context_broadcast_map(map); return id; }
/****************************************** 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; }
/*************************************************************************** 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; }