/******************************* 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; }
/***************************************************** return template name of resource Returned string MUST BE FREED return NULL if item is unique (i.e. not a resource) *****************************************************/ char * item_is_resource(const char * item_id) { char * my_template = NULL; entry_read_string(ITEM_TABLE,item_id,&my_template,ITEM_TEMPLATE, NULL); return my_template; }
/********************************************************* Get character portrait. must be freed *********************************************************/ char * character_get_portrait(const char * id) { char * portrait; if(entry_read_string(CHARACTER_TABLE,id,&portrait,CHARACTER_KEY_PORTRAIT,NULL) == RET_NOK ) { return NULL; } return portrait; }
/***************************** Return the name of an item return NULL on error *****************************/ char * item_get_name(const char * item_id) { char * my_template; char * name; if( (my_template=item_is_resource(item_id)) != NULL ) { if(entry_read_string(ITEM_TEMPLATE_TABLE,my_template,&name,ITEM_NAME,NULL) == RET_OK ) { free(my_template); return name; } free(my_template); } else { if(entry_read_string(ITEM_TABLE,item_id,&name,ITEM_NAME,NULL) == RET_OK ) { return name; } } return NULL; }
/**************************************** get the specified attribute tag's value return NULL if fails returned value MUST be freed ****************************************/ char * attribute_tag_get(const char * table, const char *id, const char * attribute) { char * tag = NULL; SDL_LockMutex(attribute_mutex); entry_read_string(table,id,&tag,ATTRIBUTE_GROUP,attribute, ATTRIBUTE_CURRENT, NULL); SDL_UnlockMutex(attribute_mutex); return tag; }
void character_user_send(context_t * p_pCtx, const char * p_pCharacterId) { char * l_pType = nullptr; char * l_pName = nullptr; if (entry_read_string(CHARACTER_TABLE, p_pCharacterId, &l_pType, CHARACTER_KEY_TYPE, nullptr) == RET_NOK) { return; } if (entry_read_string(CHARACTER_TABLE, p_pCharacterId, &l_pName, CHARACTER_KEY_NAME, nullptr) == RET_NOK) { free(l_pType); return; } network_send_user_character(p_pCtx, p_pCharacterId, l_pType, l_pName); free(l_pType); free(l_pName); }
/********************************** 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); }
/*********************************** 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; }
/********************************** 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 ); }
/****************************************************** 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; }
/********************************************* Send playable character templates *********************************************/ void character_playable_send_list(context_t * context) { char * marquee; DIR * dir; char * dirname; struct dirent * ent; // Read all files in character template directory dirname = strconcat(base_directory, "/", CHARACTER_TEMPLATE_TABLE, nullptr); dir = opendir(dirname); if (dir == nullptr) { return; } free(dirname); std::vector<std::string> l_Array; while ((ent = readdir(dir)) != nullptr) { // skip hidden file if (ent->d_name[0] == '.') { continue; } if (entry_read_string(CHARACTER_TEMPLATE_TABLE, ent->d_name, &marquee, CHARACTER_KEY_MARQUEE, nullptr) == RET_OK) { if (marquee[0] == '\0') { free(marquee); continue; } free(marquee); } else { char ** marquee_list = nullptr; if (entry_read_list(CHARACTER_TEMPLATE_TABLE, ent->d_name, &marquee_list, CHARACTER_KEY_MARQUEE, nullptr) == RET_NOK) { wlog(LOGDESIGNER, "%s has no marquee", ent->d_name); continue; } if (marquee_list[0][0] == '\0') { deep_free(marquee_list); continue; } deep_free(marquee_list); } // add file name to network frame l_Array.push_back(std::string(ent->d_name)); } closedir(dir); NetworkFrame l_Frame; l_Frame.push(l_Array); network_send_command(context, CMD_SEND_PLAYABLE_CHARACTER, l_Frame, false); }
/*********************************************************************** 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); }
/*************************************************************************** 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; }
/************************************** Return RET_NOK on error **************************************/ ret_code_t parse_incoming_data(context_t * context, Uint32 command, Uint32 command_size, char * data) { char * value = NULL; char * fullname; char * elements[512]; char * cksum; int i; char * user_name; char * password; if( !context_get_connected(context) && ( command != CMD_REQ_LOGIN && command != CMD_REQ_FILE) ) { werr(LOGUSER,"Request from not authenticated client, close connection"); return RET_NOK; } switch(command) { case CMD_REQ_LOGIN: wlog(LOGDEBUG,"Received CMD_REQ_LOGIN"); user_name = _strsep(&data,NETWORK_DELIMITER); password = _strsep(&data,NETWORK_DELIMITER); if(entry_read_string(PASSWD_TABLE, user_name, &value, PASSWD_KEY_PASSWORD,NULL) == RET_NOK) { return RET_NOK; } if( strcmp(value, password) != 0) { free(value); werr(LOGUSER,"Wrong login for %s",user_name); // send answer network_send_command(context, CMD_SEND_LOGIN_NOK, 0, NULL, false); // force client disconnection return RET_NOK; } else { free(value); if( context_set_username(context, user_name) == RET_NOK ) { return RET_NOK; } context_set_connected(context, true); // send answer network_send_command(context, CMD_SEND_LOGIN_OK, 0, NULL, false); wlog(LOGUSER,"Login successful for user %s",context->user_name); } break; case CMD_REQ_CHARACTER_LIST : wlog(LOGDEBUG,"Received CMD_REQ_CHARACTER_LIST"); character_send_list(context); wlog(LOGDEBUG,"character list sent"); break; case CMD_REQ_FILE : i = 0; elements[i] = _strsep(&data,NETWORK_DELIMITER); while(elements[i]) { i++; elements[i] = _strsep(&data,NETWORK_DELIMITER); } if(elements[0]==NULL || elements[1]==NULL) { werr(LOGDEV,"Received erroneous CMD_REQ_FILE"); break; } wlog(LOGDEBUG,"Received CMD_REQ_FILE for %s",elements[0]); /* compare checksum */ fullname = strconcat(base_directory,"/",elements[0],NULL); cksum = checksum_file(fullname); free(fullname); if( cksum == NULL) { werr(LOGUSER,"Required file %s doesn't exists",elements[0]); break; } if( strcmp(elements[1],cksum) == 0 ) { wlog(LOGDEBUG,"Client has already newest %s file",elements[0]); free(cksum); break; } free(cksum); network_send_file(context,elements[0]); wlog(LOGDEBUG,"File %s sent",elements[0]); break; case CMD_REQ_USER_CHARACTER_LIST : wlog(LOGDEBUG,"Received CMD_REQ_USER_CHARACTER_LIST"); character_user_send_list(context); wlog(LOGDEBUG,"user %s's character list sent",context->user_name); break; case CMD_REQ_START : if( context->in_game == false ) { context->id = strdup(data); context->in_game = true; context_update_from_file(context); context_spread(context); context_request_other_context(context); } wlog(LOGDEBUG,"Received CMD_REQ_START for %s /%s",context->user_name,context->id); break; case CMD_REQ_STOP : wlog(LOGDEBUG,"Received CMD_REQ_STOP for %s /%s",context->user_name,context->id); if( context->in_game == true ) { context->in_game = false; if( context->map ) { free(context->map); } context->map = NULL; if( context->prev_map ) { free(context->prev_map); } context->prev_map = NULL; if( context->id ) { free(context->id); } context->id = NULL; context_spread(context); } break; case CMD_REQ_ACTION : i = 0; elements[i] = NULL; elements[i] = _strsep(&data,NETWORK_DELIMITER); while(elements[i]) { i++; elements[i] = _strsep(&data,NETWORK_DELIMITER); } elements[i+1] = NULL; wlog(LOGDEBUG,"Received CMD_REQ_ACTION %s from %s /%s",elements[0],context->user_name,context->character_name); action_execute(context,elements[0],&elements[1]); break; default: werr(LOGDEV,"Unknown request %d from client",command); return RET_NOK; } return RET_OK; }
void character_user_send_list(context_t * context) { char * data = NULL; Uint32 data_size = 0; Uint32 string_size = 0; char ** character_list; char * type; char * name; int i; if(entry_read_list(USERS_TABLE, context->user_name,&character_list,USERS_CHARACTER_LIST,NULL) == RET_NOK ) { return; } i = 0; data = strdup(""); while( character_list[i] != NULL ) { if(entry_read_string(CHARACTER_TABLE, character_list[i], &type, CHARACTER_KEY_TYPE,NULL) == RET_NOK ) { i++; continue; } if(entry_read_string(CHARACTER_TABLE, character_list[i], &name, CHARACTER_KEY_NAME,NULL) == RET_NOK ) { free(type); i++; continue; } // add the name of the character to the network frame string_size = strlen(character_list[i])+1; data = (char*)realloc(data, data_size + string_size); memcpy(data+data_size,character_list[i], string_size); data_size += string_size; // add the type of the character to the network frame string_size = strlen(type)+1; data = (char*)realloc(data, data_size + string_size); memcpy(data+data_size,type, string_size); data_size += string_size; // add the type of the character to the network frame string_size = strlen(name)+1; data = (char*)realloc(data, data_size + string_size); memcpy(data+data_size,name, string_size); data_size += string_size; free(type); free(name); i++; } deep_free(character_list); // Mark the end of the list data = (char*)realloc(data, data_size + 1); data[data_size] = 0; data_size ++; network_send_command(context, CMD_SEND_USER_CHARACTER, data_size, data,false); free(data); }
/********************************** 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; }
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; }
/********************************************** 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; }