// Pages in all the texutures for the currently // loaded mission. Call game_busy() occasionally... void level_page_in() { // Most important ones first game_busy( NOX("*** paging in ships ***") ); ship_page_in(); //Must be called after paging in ships game_busy( NOX("*** paging in weapons ***") ); weapons_page_in(); game_busy( NOX("*** paging in various effects ***") ); fireballs_page_in(); particle_page_in(); debris_page_in(); hud_page_in(); stars_page_in(); shockwave_page_in(); shield_hit_page_in(); asteroid_page_in(); neb2_page_in(); mflash_page_in(false); // just so long as it happens after weapons_page_in() // preload mission messages if NOT running low-memory (greater than 48MB) if (game_using_low_mem() == false) { message_pagein_mission_messages(); } if(!(Game_mode & GM_STANDALONE_SERVER)){ model_page_in_stop(); // free any loaded models that aren't used bm_page_in_stop(); } mprintf(( "Ending level bitmap paging...\n" )); }
// processes a new training message to get hilighting information and store it in internal structures. void training_process_msg(char *msg) { int count; char *src, *dest, buf[8192]; message_translate_tokens(buf, msg); count = 0; src = buf; dest = Training_buf; while (*src) { if (!strnicmp(src, NOX("<b>"), 3)) { Assert(count < MAX_TRAINING_MSG_MODS); src += 3; Training_msg_mods[count].pos = dest; Training_msg_mods[count].mode = TMMOD_BOLD; count++; } if (!strnicmp(src, NOX("</b>"), 4)) { Assert(count < MAX_TRAINING_MSG_MODS); src += 4; Training_msg_mods[count].pos = dest; Training_msg_mods[count].mode = TMMOD_NORMAL; count++; } *dest++ = *src++; } *dest = 0; if (count < MAX_TRAINING_MSG_MODS) Training_msg_mods[count].pos = NULL; }
/** * CommanderDJ: initialise alpha colors based on colors.tbl * Made modular and given a wider range of features by MageKing17 */ void alpha_colors_init() { // Set our default colors. int i; for (i = 0; i < TOTAL_COLORS; i++) { gr_init_alphacolor(COLOR_LIST[i], rgba_defaults[i][0], rgba_defaults[i][1], rgba_defaults[i][2], rgba_defaults[i][3]); } if (cf_exists_full("colors.tbl", CF_TYPE_TABLES)) { mprintf(("TABLES => Starting parse of 'colors.tbl' (checking '#Start Colors' section only)...\n")); parse_colors("colors.tbl"); } parse_modular_table(NOX("*-clr.tbm"), parse_colors); // Set defaults for interface colors and color tags (must be done after the above because they're generally just copies of above-defined colors). for (i = 0; i < INTERFACE_COLORS; i++) { memcpy(interface_colors[i], COLOR_LIST[interface_defaults[i]], sizeof(color)); } for (i = 0; i < DEFAULT_TAGS; i++) { Tagged_Colors[DEFAULT_TAG_LIST[i]] = DEFAULT_TAG_COLORS[i]; Color_Tags.push_back(DEFAULT_TAG_LIST[i]); } if (cf_exists_full("colors.tbl", CF_TYPE_TABLES)) { mprintf(("TABLES => Starting parse of 'colors.tbl' (skipping '#Start Colors' section)...\n")); parse_everything_else("colors.tbl"); } parse_modular_table(NOX("*-clr.tbm"), parse_everything_else); }
// exiting screen without canceling, so load in the new pilot selected here int pilot_manage_pilot_accepted() { char str[CALLSIGN_LEN + 1]; // check if pilot active. If not, don't allow accept. if (!Cur_pilot->callsign[0]){ return -1; } // set his image player_set_squad_bitmap(Cur_pilot, Cur_pilot->squad_filename); // Skill_level = get_default_skill_level(); // MWA -- I think that we should be writing Cur_pilot here. //write_pilot_file(!is_pilot_multi(Cur_pilot)); write_pilot_file( Cur_pilot ); // when we store the LastPlayer key, we have to mark it as being single or multiplayer, so we know where to look for him // (since we could have a single and a multiplayer pilot with the same callsign) // we'll distinguish them by putting an M and the end of the multiplayer callsign and a P at the end of a single player strcpy(str, Cur_pilot->callsign); strcat(str, is_pilot_multi(Cur_pilot) ? NOX("M") : NOX("S")); os_config_write_string( NULL, "LastPlayer", str ); return 0; }
/** * Page in debris bitmaps at level load */ void debris_page_in() { uint i; Debris_model = model_load( NOX("debris01.pof"), 0, NULL ); if (Debris_model >= 0) { polymodel * pm; pm = model_get(Debris_model); Debris_num_submodels = pm->n_models; } Debris_vaporize_model = model_load( NOX("debris02.pof"), 0, NULL ); for (i=0; i<Species_info.size(); i++ ) { species_info *species = &Species_info[i]; nprintf(( "Paging", "Paging in debris texture '%s'\n", species->debris_texture.filename)); species->debris_texture.bitmap_id = bm_load(species->debris_texture.filename); if (species->debris_texture.bitmap_id < 0) { Warning( LOCATION, "Couldn't load species %s debris\ntexture, '%s'\n", species->species_name, species->debris_texture.filename); } bm_page_in_texture(species->debris_texture.bitmap_id); } }
static void profile_save(Profile *profile, const char *file) { FILE *fp = NULL; char tmp[MAX_PATH] = ""; char tmp2[MAX_PATH] = ""; if (profile == NULL) return; fp = fopen(os_get_config_path(file).c_str(), "wt"); if (fp == NULL) return; Section *sp = profile->sections; while (sp != NULL) { sprintf(tmp, NOX("[%s]\n"), sp->name); fputs(tmp, fp); KeyValue *kvp = sp->pairs; while (kvp != NULL) { sprintf(tmp2, NOX("%s=%s\n"), kvp->key, kvp->value); fputs(tmp2, fp); kvp = kvp->next; } fprintf(fp, "\n"); sp = sp->next; } fclose(fp); }
/** * Render the ETS retail gauge to the screen (weapon+shield+engine) */ void HudGaugeEtsRetail::render(float frametime) { int i; int initial_position; ship* ship_p = &Ships[Player_obj->instance]; if ( Ets_bar.first_frame < 0 ) { return; } // if at least two gauges are not shown, don't show any i = 0; if (!ship_has_energy_weapons(ship_p)) i++; if (Player_obj->flags & OF_NO_SHIELDS) i++; if (!ship_has_engine_power(ship_p)) i++; if (i >= 2) return; setGaugeColor(); // draw the letters for the gauges first, before any clipping occurs // skip letter for any missing gauges (max one, see check above) initial_position = 0; if (ship_has_energy_weapons(ship_p)) { Letter = Letters[0]; position[0] = Gauge_positions[initial_position++]; renderPrintf(position[0] + Letter_offsets[0], position[1] + Letter_offsets[1], NOX("%c"), Letter); } if (!(Player_obj->flags & OF_NO_SHIELDS)) { Letter = Letters[1]; position[0] = Gauge_positions[initial_position++]; renderPrintf(position[0] + Letter_offsets[0], position[1] + Letter_offsets[1], NOX("%c"), Letter); } if (ship_has_engine_power(ship_p)) { Letter = Letters[2]; position[0] = Gauge_positions[initial_position++]; renderPrintf(position[0] + Letter_offsets[0], position[1] + Letter_offsets[1], NOX("%c"), Letter); } // draw gauges, skipping any gauge that is missing initial_position = 0; if (ship_has_energy_weapons(ship_p)) { Letter = Letters[0]; position[0] = Gauge_positions[initial_position++]; blitGauge(ship_p->weapon_recharge_index); } if (!(Player_obj->flags & OF_NO_SHIELDS)) { Letter = Letters[1]; position[0] = Gauge_positions[initial_position++]; blitGauge(ship_p->shield_recharge_index); } if (ship_has_engine_power(ship_p)) { Letter = Letters[2]; position[0] = Gauge_positions[initial_position++]; blitGauge(ship_p->engine_recharge_index); } }
void cmd_brief_ani_wave_init(int index) { char *name; // this is the first instance of the given anim filename name = Cur_cmd_brief->stage[index].ani_filename; if (!name[0] || !stricmp(name, NOX("<default>")) || !stricmp(name, NOX("none.ani"))) { name = NOX("CB_default"); strcpy_s(Cur_cmd_brief->stage[index].ani_filename, name); } }
/** * Load the ingame sounds into memory */ void gamesnd_load_gameplay_sounds() { if ( !Sound_enabled ) return; Assert( Snds.size() <= INT_MAX ); for (SCP_vector<game_snd>::iterator gs = Snds.begin(); gs != Snds.end(); ++gs) { if ( gs->filename[0] != 0 && strnicmp(gs->filename, NOX("none.wav"), 4) ) { if ( !gs->preload ) { // don't try to load anything that's already preloaded game_busy( NOX("** preloading gameplay sounds **") ); // Animate loading cursor... does nothing if loading screen not active. gs->id = snd_load(&(*gs)); } } } }
void hud_add_msg_to_scrollback(const char *text, int source, int t) { char buf[HUD_MSG_LENGTH_MAX], *ptr, *str; int msg_len, w, max_width, x, offset = 0; max_width = Hud_mission_log_list2_coords[gr_screen.res][2]; msg_len = strlen(text); if (msg_len == 0) return; w = 0; Assert(msg_len < HUD_MSG_LENGTH_MAX); strcpy(buf, text); ptr = strstr(buf, NOX(": ")); if (ptr) { gr_get_string_size(&w, NULL, buf, ptr - buf); } // if (ptr) { // gr_get_string_size(&w, NULL, buf, ptr - buf + 2); // if (w < max_width - 20) // offset = w; // } x = 0; str = buf; while ((ptr = split_str_once(str, max_width - x)) != NULL) { hud_add_line_to_scrollback(str, source, t, x, 1, w); str = ptr; x = offset; t = w = 0; } hud_add_line_to_scrollback(str, source, t, x, 3, w); }
// check the training message que to see if we should play a new message yet or not. // Goober5000: removed stipulation of instructor being present void message_training_que_check() { int i, j, iship_num; // get the instructor's ship. iship_num = ship_name_lookup(NOX("instructor")); // if ( iship_num == -1 ) // commented out by Goober5000 // return; // if the instructor is dying or departing, do nothing if ( iship_num != -1 ) // added by Goober5000 if (Ships[iship_num].flags & (SF_DYING | SF_DEPARTING)) return; if (Training_failure) return; for (i=0; i<Training_msg_que_count; i++) { if (timestamp_elapsed(Training_msg_que[i].timestamp)) { message_training_setup(Training_msg_que[i].num, Training_msg_que[i].length); // remove this message from the que now. for (j=i+1; j<Training_msg_que_count; j++) Training_msg_que[j - 1] = Training_msg_que[j]; i--; Training_msg_que_count--; } } }
// add a message to the que to be sent later. void message_training_que(char *text, int timestamp, int length) { int m; Assert(Training_msg_que_count < TRAINING_MSG_QUE_MAX); if (Training_msg_que_count < TRAINING_MSG_QUE_MAX) { if (!stricmp(text, NOX("none"))) m = -1; else { for (m=0; m<Num_messages; m++) if (!stricmp(text, Messages[m].name)) break; Assert(m < Num_messages); if (m >= Num_messages) return; } Training_msg_que[Training_msg_que_count].num = m; Training_msg_que[Training_msg_que_count].timestamp = timestamp; Training_msg_que[Training_msg_que_count].length = length; Training_msg_que_count++; } }
void HudGaugeEtsWeapons::render(float frametime) { int i; ship* ship_p = &Ships[Player_obj->instance]; if ( Ets_bar.first_frame < 0 ) { return; } // if at least two gauges are not shown, don't show any i = 0; if (!ship_has_energy_weapons(ship_p)) i++; if (Player_obj->flags & OF_NO_SHIELDS) i++; if (!ship_has_engine_power(ship_p)) i++; if (i >= 2) return; // no weapon energy, no weapon gauge if (!ship_has_energy_weapons(ship_p)) { return; } setGaugeColor(); // draw the letters for the gauge first, before any clipping occurs renderPrintf(position[0] + Letter_offsets[0], position[1] + Letter_offsets[1], NOX("%c"), Letter); // draw the gauges for the weapon system blitGauge(ship_p->weapon_recharge_index); }
// open and pre-load the stream buffers for the different voice streams void red_alert_voice_load() { Assert( Briefing != NULL ); if ( strnicmp(Briefing->stages[0].voice, NOX("none"), 4) && (Briefing->stages[0].voice[0] != '\0') ) { Red_alert_voice = audiostream_open( Briefing->stages[0].voice, ASF_VOICE ); } }
// Draw the button text nicely formatted in the popup void popup_draw_button_text(popup_info *pi, int flags) { int w, h, i, sx, sy; gr_set_color_fast(&Color_bright_blue); for ( i=0; i < pi->nchoices; i++ ) { gr_get_string_size(&w, &h, pi->button_text[i]); if ( (pi->nchoices == 1) && (flags&PF_USE_AFFIRMATIVE_ICON) ) { sx = Button_regions[gr_screen.res][i+1][0]-w; sy = Button_regions[gr_screen.res][i+1][1]+4; } else { sx = Button_regions[gr_screen.res][i][0]-w; sy = Button_regions[gr_screen.res][i][1]+4; } gr_string(sx, sy, pi->button_text[i], GR_RESIZE_MENU); // figure out where to draw underline char if ( pi->shortcut_index[i] > 0 ) { int cut=pi->shortcut_index[i]; char save_char=pi->button_text[i][cut]; pi->button_text[i][cut] = 0; gr_get_string_size(&w, &h, pi->button_text[i]); pi->button_text[i][cut] = save_char; sx += w; } if ( pi->shortcut_index[i] >= 0 ) { gr_printf_menu(sx, sy, NOX("%c"), 95); } } }
void hud_sourced_print(int source, char *msg) { char *ptr, *str; //char *src_str, *msg_str; int sw, t, x, offset = 0; //int fudge = (gr_screen.res == GR_640) ? 15 : 50; // prevents string from running off screen if ( !strlen(msg) ) { nprintf(("Warning", "HUD ==> attempt to print a 0 length string in msg window\n")); return; } // add message to the scrollback log first hud_add_msg_to_scrollback(msg, source, timestamp()); ptr = strstr(msg, NOX(": ")) + 2; if (ptr) { gr_get_string_size(&sw, NULL, msg, ptr - msg); // get width of the speaker field //if (sw < MSG_WINDOW_WIDTH - 20) offset = sw; } x = 0; t = timestamp(); str = msg; while ((ptr = split_str_once(str, MSG_WINDOW_WIDTH - x - 7)) != NULL) { // the 7 is a fudge hack HUD_printf_line(str, source, t, x); str = ptr; x = offset; t = 0; } HUD_printf_line(str, source, t, x); }
// is the give file xfer handle for a "multi data" file (pcx, wav, etc) int multi_data_is_data(char *filename) { size_t len,idx; Assert(filename != NULL); // some kind of error if(filename == NULL){ return 0; } // convert to lowercase len = strlen(filename); for(idx=0;idx<len;idx++){ filename[idx] = (char)tolower(filename[idx]); } // check to see if the extension is .pcx if(strstr(filename, NOX(".pcx"))){ return 1; } // not a data file return 0; }
/** * Check the training message queue to see if we should play a new message yet or not. */ void message_training_queue_check() { int i, iship_num; // get the instructor's ship. iship_num = ship_name_lookup(NOX("instructor")); // if the instructor is dying or departing, do nothing if ( iship_num != -1 ) // added by Goober5000 if (Ships[iship_num].flags & (SF_DYING | SF_DEPARTING)) return; if (Training_failure) return; for (i=0; i<Training_message_queue_count; i++) { if (timestamp_elapsed(Training_message_queue[i].timestamp)) { message_training_setup(Training_message_queue[i].num, Training_message_queue[i].length, Training_message_queue[i].special_message); // remove this message from the queue now. message_training_remove_from_queue(i); i--; } } }
char *GetTrackerIdByUser(char *nickname) { char szWhoisCmd[100]; if(GettingUserTID) { if(Getting_user_tracker_error) { Getting_user_tracker_error = 0; GettingUserTID = 0; return (char *)-1; } if(*User_req_tracker_id) { GettingUserTID = 0; return User_req_tracker_id; } } else { strncpy(Getting_user_tracker_info_for, nickname, sizeof(Getting_user_tracker_info_for)-1); snprintf(szWhoisCmd, SSIZE(szWhoisCmd), NOX("/WHOIS %s"), nickname); User_req_tracker_id[0] = '\0'; SendChatString(szWhoisCmd,1); GettingUserTID = 1; } return NULL; }
// ------------------------------------------------------------------------------------------------- // gamesnd_parse_line() // // Parse a sound effect line // void gamesnd_parse_line(game_snd* gs, char* tag) { int is_3d; required_string(tag); stuff_int(&gs->sig); stuff_string(gs->filename, F_NAME, MAX_FILENAME_LEN, ","); if (!stricmp(gs->filename, NOX("empty"))) { gs->filename[0] = 0; advance_to_eoln(NULL); return; } Mp++; stuff_int(&gs->preload); stuff_float(&gs->default_volume); stuff_int(&is_3d); if (is_3d) { gs->flags |= GAME_SND_USE_DS3D; stuff_int(&gs->min); stuff_int(&gs->max); } else { gs->min = 0; gs->max = 0; } advance_to_eoln(NULL); }
char *GetChannelByUser(char *nickname) { char szWhoisCmd[100]; if(GettingUserChannel) { if(Getting_user_channel_error) { Getting_user_channel_error = 0; GettingUserChannel = 0; return (char *)-1; } if(*User_req_channel) { GettingUserChannel = 0; return User_req_channel; } } else { strncpy(Getting_user_channel_info_for, nickname, sizeof(Getting_user_channel_info_for)-1); User_req_channel[0] = '\0'; snprintf(szWhoisCmd, SSIZE(szWhoisCmd), NOX("/WHOIS %s"), nickname); SendChatString(szWhoisCmd,1); GettingUserChannel = 1; } return NULL; }
/** * Call it to close the connection. It returns immediately */ void DisconnectFromChatServer() { if(!Socket_connected) return; SendChatString(NOX("/QUIT"),1); shutdown(Chatsock,2); closesocket(Chatsock); Socket_connecting = 0; Socket_connected = 0; Input_chat_buffer[0] = '\0'; if(User_list) { vm_free(User_list); User_list = NULL; } if(Chan_list) { vm_free(Chan_list); Chan_list = NULL; } Chat_server_connected = 0; Joining_channel = 0; Joined_channel = 0; RemoveAllChatUsers(); FlushChatCommandQueue(); return; }
void training_menu_init() { char background_img_filename[MAX_FILENAME_LEN]; char background_mask_filename[MAX_FILENAME_LEN]; snazzy_menu_init(); read_menu_tbl(NOX("TRAINING MENU"), background_img_filename, background_mask_filename, region, &num_training); // load in the background bitmap (filenames are hard-coded temporarily) trainingMenuBitmap = bm_load(background_img_filename); if (trainingMenuBitmap < 0) { Error(LOCATION, "Could not load in %s!", background_img_filename); } trainingMenuMask = bm_load(background_mask_filename); Training_mask_w = -1; Training_mask_h = -1; if (trainingMenuMask < 0) { Error(LOCATION, "Could not load in %s!", background_mask_filename); } else { // get a pointer to bitmap by using bm_lock() trainingMenuMaskPtr = bm_lock(trainingMenuMask, 8, BMP_AABITMAP); mask_data = (ubyte*)trainingMenuMaskPtr->data; bm_get_info(trainingMenuMask, &Training_mask_w, &Training_mask_h); } }
const char *os_config_read_string(const char *section, const char *name, const char *default_value) { Profile *p = profile_read(Osreg_config_file_name); #ifdef WIN32 if (p == nullptr) { // No config file, fall back to registy return registry_read_string(section, name, default_value); } #endif nprintf(("Registry", "os_config_read_string(): section = \"%s\", name = \"%s\", default value: \"%s\"\n", (section) ? section : DEFAULT_SECTION, name, (default_value) ? default_value : NOX("NULL"))); if (section == NULL) section = DEFAULT_SECTION; char *ptr = profile_get_value(p, section, name); if (ptr != NULL) { strncpy(tmp_string_data, ptr, 1023); default_value = tmp_string_data; } profile_free(p); return default_value; }
void HudGaugeRadar::drawRange() { char buf[32]; // hud_set_bright_color(); setGaugeColor(HUD_C_BRIGHT); switch ( HUD_config.rp_dist ) { case RR_SHORT: renderPrintf(position[0] + Radar_dist_offsets[RR_SHORT][0], position[1] + Radar_dist_offsets[RR_SHORT][1], XSTR( "2k", 467)); break; case RR_LONG: renderPrintf(position[0] + Radar_dist_offsets[RR_LONG][0], position[1] + Radar_dist_offsets[RR_LONG][1], XSTR( "10k", 468)); break; case RR_INFINITY: sprintf(buf, NOX("%c"), Lcl_special_chars); renderPrintf(position[0] + Radar_dist_offsets[RR_INFINITY][0], position[1] + Radar_dist_offsets[RR_INFINITY][1], buf); break; default: Int3(); // can't happen (get Alan if it does) break; } }
void radar_draw_range() { char buf[32]; // hud_set_bright_color(); hud_set_gauge_color(HUD_RADAR, HUD_C_BRIGHT); switch ( HUD_config.rp_dist ) { case RR_SHORT: gr_printf(Radar_dist_coords[gr_screen.res][RR_SHORT][0], Radar_dist_coords[gr_screen.res][RR_SHORT][1], XSTR( "2k", 467)); break; case RR_LONG: gr_printf(Radar_dist_coords[gr_screen.res][RR_LONG][0], Radar_dist_coords[gr_screen.res][RR_LONG][1], XSTR( "10k", 468)); break; case RR_INFINITY: sprintf(buf, NOX("%c"), Lcl_special_chars); gr_printf(Radar_dist_coords[gr_screen.res][RR_INFINITY][0], Radar_dist_coords[gr_screen.res][RR_INFINITY][1], buf); break; default: Int3(); // can't happen (get Alan if it does) break; } hud_set_default_color(); }
// process an entered line of text and maybe perform a command on it (return 1 if an action was performed, 0 if not) int multi_msg_check_command(char *str) { int idx; char *prefix = NULL, *predicate = NULL, param[MULTI_MSG_MAX_TEXT_LEN+1]; char temp_str[MULTI_MSG_MAX_TEXT_LEN+1]; // look for a colon if(strstr(str,":") == NULL){ return 0; } // we don't want to modify the original string, which strtok() does strcpy_s(temp_str, str); // try and find a command prefix prefix = strtok(temp_str, ":"); if (prefix == NULL) return 0; // get all the text after the message predicate = strtok(NULL, NOX("\n\0")); if (predicate == NULL) return 0; // store the text as the actual parameter strcpy_s(param, predicate); drop_leading_white_space(param); // go through all existing commands and see what we can do for(idx=0;idx<MULTI_MSG_CMD_COUNT;idx++){ if(!stricmp(prefix,Multi_msg_commands[idx])){ // perform the command multi_msg_perform_command(idx,param); // return true return 1; } } // apply the results as a general expression, if we're in message all mode if(Multi_msg_mode == MULTI_MSG_ALL){ strcpy_s(Multi_msg_text,param); // send the chat packet send_game_chat_packet(Net_player, Multi_msg_text, MULTI_MSG_EXPR,NULL, prefix); // echo the message locally multi_msg_display_mission_text(Multi_msg_text, MY_NET_PLAYER_NUM); // return true return 1; } // no commands performed return 0; }
// translates special tokens. Handles one token only. char *translate_msg_token(char *str) { if (!stricmp(str, NOX("wp"))) { sprintf(str, "%d", Training_context_goal_waypoint + 1); return str; } return NULL; }
// game init void ssm_init() { if (cf_exists_full("ssm.tbl", CF_TYPE_TABLES)) { mprintf(("TABLES => Starting parse of 'ssm.tbl'...\n")); parse_ssm("ssm.tbl"); } parse_modular_table(NOX("*-ssm.tbm"), parse_ssm); // Now that we've populated Ssm_info, let's validate weapon $SSM: entries. validate_SSM_entries(); }
// If app_name is NULL or ommited, then TITLE is used // for the app name, which is where registry keys are stored. void os_init(const char * wclass, const char * title, const char *app_name, const char *version_string ) { // create default ini entries for the user if (os_config_read_string(NULL, NOX("VideocardFs2open"), NULL) == NULL) os_config_write_string(NULL, NOX("VideocardFs2open"), NOX("OGL -(640x480)x16 bit")); os_init_registry_stuff(Osreg_company_name, title, version_string); strcpy_s( szWinTitle, title ); strcpy_s( szWinClass, wclass ); INITIALIZE_CRITICAL_SECTION( Os_lock ); unix_process(0); // initialized Os_inited = 1; atexit(os_deinit); }