code:
/* MegaZeux
 *
 * Copyright (C) 1996 Greg Janson
 * Copyright (C) 1999 Charles Goetzman
 * Copyright (C) 2004 Gilead Kutnick <exophase@adelphia.net>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/stat.h>

#ifndef _MSC_VER
#include <unistd.h>
#endif

#include "configure.h"
#include "helpsys.h"
#include "sfx.h"
#include "scrdisp.h"
#include "error.h"
#include "window.h"
#include "const.h"
#include "counter.h"
#include "sprite.h"
#include "counter.h"
#include "graphics.h"
#include "event.h"
#include "world.h"
#include "data.h"
#include "idput.h"
#include "fsafeopen.h"
#include "game.h"
#include "audio.h"
#include "extmem.h"
#include "util.h"
#include "validation.h"

static const char magic_code[16] =
 "\xE6\x52\xEB\xF2\x6D\x4D\x4A\xB7\x87\xB2\x92\x88\xDE\x91\x24";

#ifdef CONFIG_LOADSAVE_METER

static void meter_update_screen(int *curr, int target)
{
  (*curr)++;
  meter_interior(*curr, target);
  update_screen();
}

static void meter_restore_screen(void)
{
  restore_screen();
  update_screen();
}

static void meter_initial_draw(int curr, int target, const char *title)
{
  save_screen();
  meter(title, curr, target);
  update_screen();
}

#else // !CONFIG_LOADSAVE_METER

static inline void meter_update_screen(int *curr, int target) {}
static inline void meter_restore_screen(void) {}
static inline void meter_initial_draw(int curr, int target,
 const char *title) {}

#endif // CONFIG_LOADSAVE_METER

// Get 2 bytes

int fgetw(FILE *fp)
{
  int a = fgetc(fp), b = fgetc(fp);
  if((a == EOF) || (b == EOF))
    return EOF;

  return (b << 8) | a;
}

// Get 4 bytes

int fgetd(FILE *fp)
{
  int a = fgetc(fp), b = fgetc(fp), c = fgetc(fp), d = fgetc(fp);
  if((a == EOF) || (b == EOF) || (c == EOF) || (d == EOF))
    return EOF;

  return (d << 24) | (c << 16) | (b << 8) | a;
}

// Put 2 bytes

void fputw(int src, FILE *fp)
{
  fputc(src & 0xFF, fp);
  fputc(src >> 8, fp);
}

// Put 4 bytes

void fputd(int src, FILE *fp)
{
  fputc(src & 0xFF, fp);
  fputc((src >> 8) & 0xFF, fp);
  fputc((src >> 16) & 0xFF, fp);
  fputc((src >> 24) & 0xFF, fp);
}

static int get_pw_xor_code(char *password, int pro_method)
{
  int work = 85; // Start with 85... (01010101)
  size_t i;
  // Clear pw after first null

  for(i = strlen(password); i < 16; i++)
  {
    password[i] = 0;
  }

  for(i = 0; i < 15; i++)
  {
    //For each byte, roll once to the left and xor in pw byte if it
    //is an odd character, or add in pw byte if it is an even character.
    work <<= 1;
    if(work > 255)
      work ^= 257; // Wraparound from roll

    if(i & 1)
    {
      work += (signed char)password[i]; // Add (even byte)
      if(work > 255)
        work ^= 257; // Wraparound from add
    }
    else
    {
      work ^= (signed char)password[i]; // XOR (odd byte);
    }
  }
  // To factor in protection method, add it in and roll one last time
  work += pro_method;
  if(work > 255)
    work ^= 257;

  work <<= 1;
  if(work > 255)
    work ^= 257;

  // Can't be 0-
  if(work == 0)
    work = 86; // (01010110)
  // Done!
  return work;
}

static void decrypt(const char *file_name)
{
  FILE *source;
  FILE *backup;
  FILE *dest;
  int file_length;
  int pro_method;
  int i;
  int len;
  char num_boards;
  char offset_low_byte;
  char xor_val;
  char password[15];
  char *file_buffer;
  char *src_ptr;
  char backup_name[MAX_PATH];

  int meter_target, meter_curr = 0;

  source = fopen_unsafe(file_name, "rb");
  file_length = ftell_and_rewind(source);

  meter_target = file_length + (file_length - 15) + 4;

  meter_initial_draw(meter_curr, meter_target, "Decrypting...");

  file_buffer = cmalloc(file_length);
  src_ptr = file_buffer;
  fread(file_buffer, file_length, 1, source);
  fclose(source);

  meter_curr = file_length - 1;
  meter_update_screen(&meter_curr, meter_target);

  src_ptr += 25;

  strncpy(backup_name, file_name, MAX_PATH - 8);
  strcat(backup_name, ".locked");
  backup = fopen_unsafe(backup_name, "wb");
  fwrite(file_buffer, file_length, 1, backup);
  fclose(backup);

  dest = fopen_unsafe(file_name, "wb");
  if(!dest)
  {
    error("Cannot decrypt write-protected world.", 1, 8, 0x0DD5);
    return;
  }
  pro_method = *src_ptr;
  src_ptr++;

  // Get password
  memcpy(password, src_ptr, 15);
  src_ptr += 18;
  // First, normalize password...
  for(i = 0; i < 15; i++)
  {
    password[i] ^= magic_code[i];
    password[i] -= 0x12 + pro_method;
    password[i] ^= 0x8D;
  }

  // Xor code
  xor_val = get_pw_xor_code(password, pro_method);

  // Copy title
  fwrite(file_buffer, 25, 1, dest);
  fputc(0, dest);
  fputs("M\x02\x11", dest);

  meter_curr += 25 + 1 + 3 - 1;
  meter_update_screen(&meter_curr, meter_target);

  len = file_length - 44;
  for(; len > 0; len--)
  {
    fputc((*src_ptr) ^ xor_val, dest);
    src_ptr++;

    if((len % 1000) == 0)
    {
      meter_curr += 999;
      meter_update_screen(&meter_curr, meter_target);
    }
  }

  meter_curr = file_length + (file_length - 15) - 1;
  meter_update_screen(&meter_curr, meter_target);

  // Must fix all the absolute file positions so that they're 15
  // less now
  src_ptr = file_buffer + 4245;
  fseek(dest, 4230, SEEK_SET);
  offset_low_byte = src_ptr[0] ^ xor_val;
  fputc(offset_low_byte - 15, dest);
  if(offset_low_byte < 15)
  {
    fputc((src_ptr[1] ^ xor_val) - 1, dest);
  }
  else
  {
    fputc(src_ptr[1] ^ xor_val, dest);
  }

  fputc(src_ptr[2] ^ xor_val, dest);
  fputc(src_ptr[3] ^ xor_val, dest);

  meter_curr += 4 - 1;
  meter_update_screen(&meter_curr, meter_target);

  src_ptr += 4;

  num_boards = ((*src_ptr) ^ xor_val);
  src_ptr++;

  // If custom SFX is there, run through and skip it
  if(!num_boards)
  {
    int sfx_length = (char)(src_ptr[0] ^ xor_val);
    sfx_length |= ((char)(src_ptr[1] ^ xor_val)) << 8;
    src_ptr += sfx_length + 2;
    num_boards = (*src_ptr) ^ xor_val;
    src_ptr++;
  }

  meter_target += num_boards * 4;
  meter_curr--;
  meter_update_screen(&meter_curr, meter_target);

  // Skip titles
  src_ptr += (25 * num_boards);
  // Synchronize source and dest positions
  fseek(dest, (long)(src_ptr - file_buffer - 15), SEEK_SET);

  // Offset boards
  for(i = 0; i < num_boards; i++)
  {
    // Skip length
    src_ptr += 4;
    fseek(dest, 4, SEEK_CUR);

    // Get offset
    offset_low_byte = src_ptr[0] ^ xor_val;
    fputc(offset_low_byte - 15, dest);
    if(offset_low_byte < 15)
    {
      fputc((src_ptr[1] ^ xor_val) - 1, dest);
    }
    else
    {
      fputc(src_ptr[1] ^ xor_val, dest);
    }
    fputc(src_ptr[2] ^ xor_val, dest);
    fputc(src_ptr[3] ^ xor_val, dest);
    src_ptr += 4;

    meter_target += 4 - 1;
    meter_update_screen(&meter_curr, meter_target);
  }

  free(file_buffer);
  fclose(dest);

  meter_restore_screen();
}

int world_magic(const char magic_string[3])
{
  if(magic_string[0] == 'M')
  {
    if(magic_string[1] == 'Z')
    {
      switch(magic_string[2])
      {
        case 'X':
          return 0x0100;
        case '2':
          return 0x0205;
        case 'A':
          return 0x0208;
      }
    }
    else
    {
      // I hope to God that MZX doesn't last beyond 9.x
      if((magic_string[1] > 1) && (magic_string[1] < 10))
        return ((int)magic_string[1] << 8) + (int)magic_string[2];
    }
  }

  return 0;
}

int save_world(struct world *mzx_world, const char *file, int savegame)
{
  int i, num_boards;
  int gl_rob_position, gl_rob_save_position;
  int board_offsets_position, board_begin_position;
  int board_size;
  unsigned int *size_offset_list;
  unsigned char *charset_mem;
  unsigned char r, g, b;
  struct board *cur_board;
  FILE *fp;

  int meter_target = 2 + mzx_world->num_boards, meter_curr = 0;

#ifdef CONFIG_DEBYTECODE
  if(!savegame)
  {
    fp = fopen_unsafe(file, "rb");
    if(fp)
    {
      if(!fseek(fp, 0x1A, SEEK_SET))
      {
        char tmp[3];
        if(fread(tmp, 1, 3, fp) == 3)
        {
          // If it's not a 2.90 world, abort the save
          if(world_magic(tmp) < 0x025A)
          {
            error("Save would overwrite older world. Aborted.", 0, 1, 1337);
            goto exit_close;
          }
        }
      }
      fclose(fp);
    }
  }
#endif

  fp = fopen_unsafe(file, "wb");
  if(!fp)
  {
    error("Error saving world", 1, 8, 0x0D01);
    return -1;
  }

  meter_initial_draw(meter_curr, meter_target, "Saving...");

  if(savegame)
  {
    // Write this MZX's version string
    fputs("MZS", fp);
    fputc((WORLD_VERSION >> 8) & 0xff, fp);
    fputc(WORLD_VERSION & 0xff, fp);

    // Write the version of the loaded world for this SAV
    fputw(mzx_world->version, fp);

    fputc(mzx_world->current_board_id, fp);
  }
  else
  {
    fwrite(mzx_world->name, BOARD_NAME_SIZE, 1, fp);

    // No protection
    fputc(0, fp);

    // Write this MZX's version string
    fputc('M', fp);
    fputc((WORLD_VERSION >> 8) & 0xff, fp);
    fputc(WORLD_VERSION & 0xff, fp);
  }

  // Save charset
  charset_mem = cmalloc(3584);
  ec_mem_save_set(charset_mem);
  fwrite(charset_mem, 3584, 1, fp);
  free(charset_mem);

  // Save idchars array.
  fwrite(id_chars, 323, 1, fp);
  fputc(missile_color, fp);
  fwrite(bullet_color, 3, 1, fp);
  fwrite(id_dmg, 128, 1, fp);

  // Save status counters.
  fwrite((char *)mzx_world->status_counters_shown, COUNTER_NAME_SIZE,
   NUM_STATUS_COUNTERS, fp);

  /* Older MZX sources refer to SAVE_INDIVIDUAL, but it has always been
   * defined. Exo eventually removed the conditional code in 2.80.
   * We don't need to think about it.
   */

  if(savegame)
  {
    fwrite(mzx_world->keys, NUM_KEYS, 1, fp);
    fputc(mzx_world->blind_dur, fp);
    fputc(mzx_world->firewalker_dur, fp);
    fputc(mzx_world->freeze_time_dur, fp);
    fputc(mzx_world->slow_time_dur, fp);
    fputc(mzx_world->wind_dur, fp);

    for(i = 0; i < 8; i++)
    {
      fputw(mzx_world->pl_saved_x[i], fp);
    }

    for(i = 0; i < 8; i++)
    {
      fputw(mzx_world->pl_saved_y[i], fp);
    }

    fwrite(mzx_world->pl_saved_board, 8, 1, fp);
    fputc(mzx_world->saved_pl_color, fp);
    fputc(mzx_world->under_player_id, fp);
    fputc(mzx_world->under_player_color, fp);
    fputc(mzx_world->under_player_param, fp);
    fputc(mzx_world->mesg_edges, fp);
    fputc(mzx_world->scroll_base_color, fp);
    fputc(mzx_world->scroll_corner_color, fp);
    fputc(mzx_world->scroll_pointer_color, fp);
    fputc(mzx_world->scroll_title_color, fp);
    fputc(mzx_world->scroll_arrow_color, fp);

    {
      size_t len = strlen(mzx_world->real_mod_playing);
      fputw((int)len, fp);
      if(len)
        fwrite(mzx_world->real_mod_playing, len, 1, fp);
    }
  }

  fputc(mzx_world->edge_color, fp);
  fputc(mzx_world->first_board, fp);
  fputc(mzx_world->endgame_board, fp);
  fputc(mzx_world->death_board, fp);
  fputw(mzx_world->endgame_x, fp);
  fputw(mzx_world->endgame_y, fp);
  fputc(mzx_world->game_over_sfx, fp);
  fputw(mzx_world->death_x, fp);
  fputw(mzx_world->death_y, fp);
  fputw(mzx_world->starting_lives, fp);
  fputw(mzx_world->lives_limit, fp);
  fputw(mzx_world->starting_health, fp);
  fputw(mzx_world->health_limit, fp);
  fputc(mzx_world->enemy_hurt_enemy, fp);
  fputc(mzx_world->clear_on_exit, fp);
  fputc(mzx_world->only_from_swap, fp);

  // Palette...
  for(i = 0; i < 16; i++)
  {
    get_rgb(i, &r, &g, &b);
    fputc(r, fp);
    fputc(g, fp);
    fputc(b, fp);
  }

  if(savegame)
  {
    int vlayer_size;

    for(i = 0; i < 16; i++)
    {
      fputc(get_color_intensity(i), fp);
    }
    fputc(get_fade_status(), fp);

    fputw(mzx_world->player_restart_x, fp);
    fputw(mzx_world->player_restart_y, fp);
    fputc(mzx_world->under_player_id, fp);
    fputc(mzx_world->under_player_color, fp);
    fputc(mzx_world->under_player_param, fp);

    // Write counters
    fputd(mzx_world->num_counters, fp);
    for(i = 0; i < mzx_world->num_counters; i++)
    {
      save_counter(fp, mzx_world->counter_list[i]);
    }

    // Write strings
    fputd(mzx_world->num_strings, fp);

    for(i = 0; i < mzx_world->num_strings; i++)
    {
      save_string(fp, mzx_world->string_list[i]);
    }

    // Sprite data
    for(i = 0; i < MAX_SPRITES; i++)
    {
      fputw((mzx_world->sprite_list[i])->x, fp);
      fputw((mzx_world->sprite_list[i])->y, fp);
      fputw((mzx_world->sprite_list[i])->ref_x, fp);
      fputw((mzx_world->sprite_list[i])->ref_y, fp);
      fputc((mzx_world->sprite_list[i])->color, fp);
      fputc((mzx_world->sprite_list[i])->flags, fp);
      fputc((mzx_world->sprite_list[i])->width, fp);
      fputc((mzx_world->sprite_list[i])->height, fp);
      fputc((mzx_world->sprite_list[i])->col_x, fp);
      fputc((mzx_world->sprite_list[i])->col_y, fp);
      fputc((mzx_world->sprite_list[i])->col_width, fp);
      fputc((mzx_world->sprite_list[i])->col_height, fp);
    }
    // total sprites
    fputc(mzx_world->active_sprites, fp);
    // y order flag
    fputc(mzx_world->sprite_y_order, fp);
    // collision info
    fputw(mzx_world->collision_count, fp);

    for(i = 0; i < MAX_SPRITES; i++)
    {
      fputw(mzx_world->collision_list[i], fp);
    }

    // Multiplier
    fputw(mzx_world->multiplier, fp);
    // Divider
    fputw(mzx_world->divider, fp);
    // Circle divisions
    fputw(mzx_world->c_divisions, fp);
    // String FREAD and FWRITE Delimiters
    fputw(mzx_world->fread_delimiter, fp);
    fputw(mzx_world->fwrite_delimiter, fp);
    // Builtin shooting/message status
    fputc(mzx_world->bi_shoot_status, fp);
    fputc(mzx_world->bi_mesg_status, fp);

    // Write input file name and if open, position
    {
      size_t len = strlen(mzx_world->input_file_name);
      fputw((int)len, fp);
      if(len)
        fwrite(mzx_world->input_file_name, len, 1, fp);
    }

    if(!mzx_world->input_is_dir && mzx_world->input_file)
    {
      fputd(ftell(mzx_world->input_file), fp);
    }
    else if(mzx_world->input_is_dir)
    {
      fputd(dir_tell(&mzx_world->input_directory), fp);
    }
    else
    {
      fputd(0, fp);
    }

    // Write output file name and if open, position
    {
      size_t len = strlen(mzx_world->output_file_name);
      fputw((int)len, fp);
      if(len)
        fwrite(mzx_world->output_file_name, len, 1, fp);
    }

    if(mzx_world->output_file)
    {
      fputd(ftell(mzx_world->output_file), fp);
    }
    else
    {
      fputd(0, fp);
    }

    fputw(get_screen_mode(), fp);

    if(get_screen_mode() > 1)
    {
      // Put SMZX mode 2 palette
      for(i = 0; i < 256; i++)
      {
        get_rgb(i, &r, &g, &b);
        fputc(r, fp);
        fputc(g, fp);
        fputc(b, fp);
      }
    }

    fputd(mzx_world->commands, fp);

    vlayer_size = mzx_world->vlayer_size;
    fputd(vlayer_size, fp);
    fputw(mzx_world->vlayer_width, fp);
    fputw(mzx_world->vlayer_height, fp);

    fwrite(mzx_world->vlayer_chars, 1, vlayer_size, fp);
    fwrite(mzx_world->vlayer_colors, 1, vlayer_size, fp);
  }

  // Put position of global robot later
  gl_rob_save_position = ftell(fp);
  // Put some 0's
  fputd(0, fp);

  // Put custom fx?
  if(mzx_world->custom_sfx_on == 1)
  {
    int offset = 0;
    size_t sfx_len;
    int length_slot_pos, next_pos, total_len;
    fputc(0, fp);
    length_slot_pos = ftell(fp);
    fputw(0, fp);
    for(i = 0; i < NUM_SFX; i++, offset += 69)
    {
      sfx_len = strlen(mzx_world->custom_sfx + offset);
      fputc((int)sfx_len, fp);
      fwrite(mzx_world->custom_sfx + offset, sfx_len, 1, fp);
    }
    // Get size of the block
    next_pos = ftell(fp);
    total_len = (next_pos - length_slot_pos) - 2;
    fseek(fp, length_slot_pos, SEEK_SET);
    fputw(total_len, fp);
    fseek(fp, next_pos, SEEK_SET);
  }

  meter_update_screen(&meter_curr, meter_target);

  num_boards = mzx_world->num_boards;
  fputc(num_boards, fp);

  // Put the names
  for(i = 0; i < num_boards; i++)
  {
    fwrite((mzx_world->board_list[i])->board_name, 25, 1, fp);
  }

  /* Due to some bugs in the NDS's libfat library, seeking backwards
   * from the end results in data corruption. To prevent this, waste
   * a little bit of memory caching the offsets of the board data so
   * we can rewrite the size/offset list with less seeking later.
   */
  size_offset_list = cmalloc(8 * num_boards);
  board_offsets_position = ftell(fp);
  fseek(fp, 8 * num_boards, SEEK_CUR);

  for(i = 0; i < num_boards; i++)
  {
    cur_board = mzx_world->board_list[i];

    // Before messing with the board, make sure the board is
    // rid of any gaps in the object lists...
    optimize_null_objects(cur_board);

    // First save the offset of where the board will be placed
    board_begin_position = ftell(fp);
    // Now save the board and get the size
    board_size = save_board(cur_board, fp, savegame, WORLD_VERSION);
    // board_end_position, unused
    ftell(fp);
    // Record size/offset information.
    size_offset_list[2 * i] = board_size;
    size_offset_list[2 * i + 1] = board_begin_position;

    meter_update_screen(&meter_curr, meter_target);
  }

  // Save for global robot position
  gl_rob_position = ftell(fp);
  save_robot(&mzx_world->global_robot, fp, savegame, WORLD_VERSION);

  meter_update_screen(&meter_curr, meter_target);

  // Go back to where the global robot position should be saved
  fseek(fp, gl_rob_save_position, SEEK_SET);
  fputd(gl_rob_position, fp);

  // Go back to offsets/size list
  fseek(fp, board_offsets_position, SEEK_SET);
  for(i = 0; i < num_boards; i++)
  {
    fputd(size_offset_list[2 * i  ], fp);
    fputd(size_offset_list[2 * i + 1], fp);
  }
  free(size_offset_list);

  meter_restore_screen();

#ifdef CONFIG_DEBYTECODE
exit_close:
#endif
  fclose(fp);
  return 0;
}

int save_magic(const char magic_string[5])
{
  if((magic_string[0] == 'M') && (magic_string[1] == 'Z'))
  {
    switch(magic_string[2])
    {
      case 'S':
        if((magic_string[3] == 'V') && (magic_string[4] == '2'))
        {
          return 0x0205;
        }
        else if((magic_string[3] >= 2) && (magic_string[3] <= 10))
        {
          return((int)magic_string[3] << 8 ) + magic_string[4];
        }
        else
        {
          return 0;
        }
      case 'X':
        if((magic_string[3] == 'S') && (magic_string[4] == 'A'))
        {
          return 0x0208;
        }
        else
        {
          return 0;
        }
      default:
        return 0;
    }
  }
  else
  {
    return 0;
  }
}

__editor_maybe_static void set_update_done(struct world *mzx_world)
{
  struct board **board_list = mzx_world->board_list;
  struct board *cur_board;
  int max_size = 0;
  int cur_size;
  int i;

  for(i = 0; i < mzx_world->num_boards; i++)
  {
    cur_board = board_list[i];
    cur_size = cur_board->board_width * cur_board->board_height;

    if(cur_size > max_size)
      max_size = cur_size;
  }

  if(max_size > mzx_world->update_done_size)
  {
    if(mzx_world->update_done == NULL)
    {
      mzx_world->update_done = cmalloc(max_size);
    }
    else
    {
      mzx_world->update_done =
       crealloc(mzx_world->update_done, max_size);
    }

    mzx_world->update_done_size = max_size;
  }
}

__editor_maybe_static void optimize_null_boards(struct world *mzx_world)
{
  // Optimize out null objects while keeping a translation list mapping
  // board numbers from the old list to the new list.
  int num_boards = mzx_world->num_boards;
  struct board **board_list = mzx_world->board_list;
  struct board **optimized_board_list =
   ccalloc(num_boards, sizeof(struct board *));
  int *board_id_translation_list = ccalloc(num_boards, sizeof(int));

  struct board *cur_board;
  int i, i2;

  for(i = 0, i2 = 0; i < num_boards; i++)
  {
    cur_board = board_list[i];
    if(cur_board != NULL)
    {
      optimized_board_list[i2] = cur_board;
      board_id_translation_list[i] = i2;
      i2++;
    }
    else
    {
      board_id_translation_list[i] = NO_BOARD;
    }
  }

  // Might need to fix these first, to correct old MZX games.
  if(mzx_world->first_board >= num_boards)
    mzx_world->first_board = 0;

  if((mzx_world->death_board >= num_boards) &&
   (mzx_world->death_board < DEATH_SAME_POS))
    mzx_world->death_board = NO_BOARD;

  if(mzx_world->endgame_board >= num_boards)
    mzx_world->endgame_board = NO_BOARD;

  if(i2 < num_boards)
  {
    int offset;
    char *level_id;
    char *level_param;
    int d_param, d_flag;
    int board_width;
    int board_height;
    int relocate_current = 1;
    int i3;

    if(board_list[mzx_world->current_board_id] == NULL)
      relocate_current = 0;

    free(board_list);
    board_list =
     crealloc(optimized_board_list, sizeof(struct board *) * i2);

    mzx_world->num_boards = i2;
    mzx_world->num_boards_allocated = i2;

    // Fix all entrances and exits in each board
    for(i = 0; i < i2; i++)
    {
      cur_board = board_list[i];
      board_width = cur_board->board_width;
      board_height = cur_board->board_height;
      level_id = cur_board->level_id;
      level_param = cur_board->level_param;

      // Fix entrances
      for(offset = 0; offset < board_width * board_height; offset++)
      {
        d_flag = flags[(int)level_id[offset]];

        if(d_flag & A_ENTRANCE)
        {
          d_param = level_param[offset];
          if(d_param < num_boards)
            level_param[offset] = board_id_translation_list[d_param];
          else
            level_param[offset] = NO_BOARD;
        }
      }

      // Fix exits
      for(i3 = 0; i3 < 4; i3++)
      {
        d_param = cur_board->board_dir[i3];

        if(d_param < i2)
          cur_board->board_dir[i3] = board_id_translation_list[d_param];
        else
          cur_board->board_dir[i3] = NO_BOARD;
      }
    }

    // Fix current board
    if(relocate_current)
    {
      d_param = mzx_world->current_board_id;
      d_param = board_id_translation_list[d_param];
      mzx_world->current_board_id = d_param;
      mzx_world->current_board = board_list[d_param];
    }

    d_param = mzx_world->first_board;
    if(d_param >= num_boards)
      d_param = num_boards - 1;

    d_param = board_id_translation_list[d_param];
    mzx_world->first_board = d_param;

    d_param = mzx_world->endgame_board;

    if(d_param != NO_BOARD)
    {
      if(d_param >= num_boards)
        d_param = num_boards - 1;

      d_param = board_id_translation_list[d_param];
      mzx_world->endgame_board = d_param;
    }

    d_param = mzx_world->death_board;

    if((d_param != NO_BOARD) && (d_param != DEATH_SAME_POS))
    {
      if(d_param >= num_boards)
        d_param = num_boards - 1;

      d_param = board_id_translation_list[d_param];
      mzx_world->death_board = d_param;
    }

    mzx_world->board_list = board_list;
  }
  else
  {
    free(optimized_board_list);
  }

  free(board_id_translation_list);
}

__editor_maybe_static FILE *try_load_world(const char *file,
 bool savegame, int *version, char *name)
{
  FILE *fp;
  char magic[5];
  int v;

  enum val_result status = validate_world_file(file, savegame, NULL, 0);

  if(VAL_NEED_UNLOCK == status)
  {
    decrypt(file);
    status = validate_world_file(file, savegame, NULL, 1);
  }
  if(VAL_SUCCESS != status)
    goto err_out;

  // Validation succeeded so this should be a breeze.
  fp = fopen_unsafe(file, "rb");
  if(!fp)
  {
    error("Post validation IO error occurred", 1, 8, 0x0D01);
    goto err_out;
  }

  if(savegame)
  {
    fread(magic, 5, 1, fp);

    v = save_magic(magic);
  }
  else
  {
    if(name)
      fread(name, BOARD_NAME_SIZE, 1, fp);
    else
      fseek(fp, BOARD_NAME_SIZE, SEEK_CUR);

    fseek(fp, 1, SEEK_CUR); // Skip protection byte.

    fread(magic, 1, 3, fp);

    v = world_magic(magic);
  }

  if(version)
    *version = v;
  return fp;

err_out:
  return NULL;
}

#ifdef CONFIG_DEBYTECODE

static void convert_sfx_strs(char *sfx_buf)
{
  char *start, *end = sfx_buf - 1, str_buf_len = strlen(sfx_buf);

  while(true)
  {
    // no starting & was found
    start = strchr(end + 1, '&');
    if(!start || start - sfx_buf + 1 > str_buf_len)
      break;

    // no ending & was found
    end = strchr(start + 1, '&');
    if(!end || end - sfx_buf + 1 > str_buf_len)
      break;

    // Wipe out the &s to get a token
    *start = '(';
    *end = ')';
  }
}

#endif /* CONFIG_DEBYTECODE */

// Loads a world into a struct world

static void load_world(struct world *mzx_world, FILE *fp, const char *file,
 bool savegame, int version, char *name, int *faded)
{
  int i;
  int num_boards;
  int gl_rob, last_pos;
  unsigned char *charset_mem;
  unsigned char r, g, b;
  struct board *cur_board;
  char *config_file_name;
  size_t file_name_len = strlen(file) - 4;
  struct stat file_info;
  char *file_path;
  char *current_dir;

  int meter_target = 2, meter_curr = 0;

  if(savegame)
  {
    mzx_world->version = fgetw(fp);
    mzx_world->current_board_id = fgetc(fp);
  }
  else
  {
    strcpy(mzx_world->name, name);
    mzx_world->version = version;
    mzx_world->current_board_id = 0;
  }

  meter_initial_draw(meter_curr, meter_target, "Loading...");

  file_path = cmalloc(MAX_PATH);
  current_dir = cmalloc(MAX_PATH);
  config_file_name = cmalloc(MAX_PATH);

  get_path(file, file_path, MAX_PATH);

  if(file_path[0])
  {
    getcwd(current_dir, MAX_PATH);

    if(strcmp(current_dir, file_path))
      chdir(file_path);
  }

  memcpy(config_file_name, file, file_name_len);
  strncpy(config_file_name + file_name_len, ".cnf", 5);

  if(stat(config_file_name, &file_info) >= 0)
  {
    set_config_from_file(&(mzx_world->conf), config_file_name);
  }

  free(config_file_name);
  free(current_dir);
  free(file_path);

  charset_mem = cmalloc(3584);
  fread(charset_mem, 3584, 1, fp);
  ec_mem_load_set(charset_mem);
  free(charset_mem);

  // Idchars array...
  fread(id_chars, 323, 1, fp);
  missile_color = fgetc(fp);
  fread(bullet_color, 3, 1, fp);
  fread(id_dmg, 128, 1, fp);

  // Status counters...
  fread((char *)mzx_world->status_counters_shown, COUNTER_NAME_SIZE,
   NUM_STATUS_COUNTERS, fp);

  if(savegame)
  {
    fread(mzx_world->keys, NUM_KEYS, 1, fp);
    mzx_world->blind_dur = fgetc(fp);
    mzx_world->firewalker_dur = fgetc(fp);
    mzx_world->freeze_time_dur = fgetc(fp);
    mzx_world->slow_time_dur = fgetc(fp);
    mzx_world->wind_dur = fgetc(fp);

    for(i = 0; i < 8; i++)
    {
      mzx_world->pl_saved_x[i] = fgetw(fp);
    }

    for(i = 0; i < 8; i++)
    {
      mzx_world->pl_saved_y[i] = fgetw(fp);
    }

    fread(mzx_world->pl_saved_board, 8, 1, fp);
    mzx_world->saved_pl_color = fgetc(fp);
    mzx_world->under_player_id = fgetc(fp);
    mzx_world->under_player_color = fgetc(fp);
    mzx_world->under_player_param = fgetc(fp);
    mzx_world->mesg_edges = fgetc(fp);
    mzx_world->scroll_base_color = fgetc(fp);
    mzx_world->scroll_corner_color = fgetc(fp);
    mzx_world->scroll_pointer_color = fgetc(fp);
    mzx_world->scroll_title_color = fgetc(fp);
    mzx_world->scroll_arrow_color = fgetc(fp);

    {
      size_t len = fgetw(fp);
      if(len >= MAX_PATH)
        len = MAX_PATH - 1;

      fread(mzx_world->real_mod_playing, len, 1, fp);
      mzx_world->real_mod_playing[len] = 0;
    }
  }

  mzx_world->edge_color = fgetc(fp);
  mzx_world->first_board = fgetc(fp);
  mzx_world->endgame_board = fgetc(fp);
  mzx_world->death_board = fgetc(fp);
  mzx_world->endgame_x = fgetw(fp);
  mzx_world->endgame_y = fgetw(fp);
  mzx_world->game_over_sfx = fgetc(fp);
  mzx_world->death_x = fgetw(fp);
  mzx_world->death_y = fgetw(fp);
  mzx_world->starting_lives = fgetw(fp);
  mzx_world->lives_limit = fgetw(fp);
  mzx_world->starting_health = fgetw(fp);
  mzx_world->health_limit = fgetw(fp);
  mzx_world->enemy_hurt_enemy = fgetc(fp);
  mzx_world->clear_on_exit = fgetc(fp);
  mzx_world->only_from_swap = fgetc(fp);

  // Palette...
  for(i = 0; i < 16; i++)
  {
    r = fgetc(fp);
    g = fgetc(fp);
    b = fgetc(fp);

    set_rgb(i, r, g, b);
  }

  if(savegame)
  {
    int vlayer_size;
    int num_counters, num_strings;
    int screen_mode;

    for(i = 0; i < 16; i++)
    {
      set_color_intensity(i, fgetc(fp));
    }

    *faded = fgetc(fp);

    mzx_world->player_restart_x = fgetw(fp);
    mzx_world->player_restart_y = fgetw(fp);
    mzx_world->under_player_id = fgetc(fp);
    mzx_world->under_player_color = fgetc(fp);
    mzx_world->under_player_param = fgetc(fp);

    // Read counters
    num_counters = fgetd(fp);
    mzx_world->num_counters = num_counters;
    mzx_world->num_counters_allocated = num_counters;
    mzx_world->counter_list = ccalloc(num_counters, sizeof(struct counter *));

    for(i = 0; i < num_counters; i++)
    {
      mzx_world->counter_list[i] = load_counter(fp);
    }

    // Setup gateway functions
    initialize_gateway_functions(mzx_world);

    // Read strings
    num_strings = fgetd(fp);
    mzx_world->num_strings = num_strings;
    mzx_world->num_strings_allocated = num_strings;
    mzx_world->string_list = ccalloc(num_strings, sizeof(struct string *));

    for(i = 0; i < num_strings; i++)
    {
      mzx_world->string_list[i] = load_string(fp);
    }

    // Allocate space for sprites and clist
    mzx_world->num_sprites = MAX_SPRITES;
    mzx_world->sprite_list = ccalloc(MAX_SPRITES, sizeof(struct sprite *));

    for(i = 0; i < MAX_SPRITES; i++)
    {
      mzx_world->sprite_list[i] = ccalloc(1, sizeof(struct sprite));
    }

    mzx_world->collision_list = ccalloc(MAX_SPRITES, sizeof(int));
    mzx_world->sprite_num = 0;

    // Sprite data
    for(i = 0; i < MAX_SPRITES; i++)
    {
      (mzx_world->sprite_list[i])->x = fgetw(fp);
      (mzx_world->sprite_list[i])->y = fgetw(fp);
      (mzx_world->sprite_list[i])->ref_x = fgetw(fp);
      (mzx_world->sprite_list[i])->ref_y = fgetw(fp);
      (mzx_world->sprite_list[i])->color = fgetc(fp);
      (mzx_world->sprite_list[i])->flags = fgetc(fp);
      (mzx_world->sprite_list[i])->width = fgetc(fp);
      (mzx_world->sprite_list[i])->height = fgetc(fp);
      (mzx_world->sprite_list[i])->col_x = fgetc(fp);
      (mzx_world->sprite_list[i])->col_y = fgetc(fp);
      (mzx_world->sprite_list[i])->col_width = fgetc(fp);
      (mzx_world->sprite_list[i])->col_height = fgetc(fp);
    }

    // total sprites
    mzx_world->active_sprites = fgetc(fp);
    // y order flag
    mzx_world->sprite_y_order = fgetc(fp);
    // collision info
    mzx_world->collision_count = fgetw(fp);

    for(i = 0; i < MAX_SPRITES; i++)
    {
      mzx_world->collision_list[i] = fgetw(fp);
    }

    // Multiplier
    mzx_world->multiplier = fgetw(fp);
    // Divider
    mzx_world->divider = fgetw(fp);
    // Circle divisions
    mzx_world->c_divisions = fgetw(fp);
    // String FREAD and FWRITE Delimiters
    mzx_world->fread_delimiter = fgetw(fp);
    mzx_world->fwrite_delimiter = fgetw(fp);
    // Builtin shooting/message status
    mzx_world->bi_shoot_status = fgetc(fp);
    mzx_world->bi_mesg_status = fgetc(fp);

    {
      size_t len = fgetw(fp);
      if(len >= MAX_PATH)
        len = MAX_PATH - 1;

      fread(mzx_world->input_file_name, len, 1, fp);
      mzx_world->input_file_name[len] = 0;
    }

    if(mzx_world->input_file_name[0])
    {
      char *translated_path = cmalloc(MAX_PATH);
      int err;

      mzx_world->input_is_dir = false;

      err = fsafetranslate(mzx_world->input_file_name, translated_path);
      if(err == -FSAFE_MATCHED_DIRECTORY)
      {
        if(dir_open(&mzx_world->input_directory, translated_path))
        {
          dir_seek(&mzx_world->input_directory, fgetd(fp));
          mzx_world->input_is_dir = true;
        }
        else
          fseek(fp, 4, SEEK_CUR);
      }
      else if(err == -FSAFE_SUCCESS)
      {
        mzx_world->input_file = fopen_unsafe(translated_path, "rb");
        if(mzx_world->input_file)
          fseek(mzx_world->input_file, fgetd(fp), SEEK_SET);
        else
          fseek(fp, 4, SEEK_CUR);
      }

      free(translated_path);
    }
    else
    {
      fseek(fp, 4, SEEK_CUR);
    }

    // Load ouput file name, open
    {
      size_t len = fgetw(fp);
      if(len >= MAX_PATH)
        len = MAX_PATH - 1;

      fread(mzx_world->output_file_name, len, 1, fp);
      mzx_world->output_file_name[len] = 0;
    }

    if(mzx_world->output_file_name[0])
    {
      mzx_world->output_file =
       fsafeopen(mzx_world->output_file_name, "ab");

      if(mzx_world->output_file)
      {
        fseek(mzx_world->output_file, fgetd(fp), SEEK_SET);
      }
      else
      {
        fseek(fp, 4, SEEK_CUR);
      }
    }
    else
    {
      fseek(fp, 4, SEEK_CUR);
    }

    screen_mode = fgetw(fp);

    // If it's at SMZX mode 2, set default palette as loaded
    // so the .sav one doesn't get overwritten
    if(screen_mode == 2)
    {
      smzx_palette_loaded(1);
    }
    set_screen_mode(screen_mode);

    // Also get the palette
    if(screen_mode > 1)
    {
      for(i = 0; i < 256; i++)
      {
        r = fgetc(fp);
        g = fgetc(fp);
        b = fgetc(fp);

        set_rgb(i, r, g, b);
      }
    }

    mzx_world->commands = fgetd(fp);

    vlayer_size = fgetd(fp);
    mzx_world->vlayer_width = fgetw(fp);
    mzx_world->vlayer_height = fgetw(fp);
    mzx_world->vlayer_size = vlayer_size;

    mzx_world->vlayer_chars = cmalloc(vlayer_size);
    mzx_world->vlayer_colors = cmalloc(vlayer_size);

    fread(mzx_world->vlayer_chars, 1, vlayer_size, fp);
    fread(mzx_world->vlayer_colors, 1, vlayer_size, fp);
  }

  update_palette();

  // Get position of global robot...
  gl_rob = fgetd(fp);
  // Get number of boards
  num_boards = fgetc(fp);

  if(num_boards == 0)
  {
    int sfx_size;
    char *sfx_offset = mzx_world->custom_sfx;
    // Sfx
    mzx_world->custom_sfx_on = 1;
    fseek(fp, 2, SEEK_CUR);     // Skip word size

    //Read sfx
    for(i = 0; i < NUM_SFX; i++, sfx_offset += 69)
    {
      sfx_size = fgetc(fp);
      fread(sfx_offset, sfx_size, 1, fp);
#ifdef CONFIG_DEBYTECODE
      if(version < 0x025A)
        convert_sfx_strs(sfx_offset);
#endif
    }
    num_boards = fgetc(fp);
  }
  else
  {
    mzx_world->custom_sfx_on = 0;
  }

  meter_target += num_boards;
  meter_update_screen(&meter_curr, meter_target);

  mzx_world->num_boards = num_boards;
  mzx_world->num_boards_allocated = num_boards;
  mzx_world->board_list = cmalloc(sizeof(struct board *) * num_boards);

  // Skip the names for now
  // Gonna wanna come back to here
  last_pos = ftell(fp);
  fseek(fp, num_boards * BOARD_NAME_SIZE, SEEK_CUR);

  for(i = 0; i < num_boards; i++)
  {
    mzx_world->board_list[i] = load_board_allocate(fp, savegame, version);
    store_board_to_extram(mzx_world->board_list[i]);
    meter_update_screen(&meter_curr, meter_target);
  }

  // Read global robot
  fseek(fp, gl_rob, SEEK_SET); //don't worry if this fails
  load_robot(&mzx_world->global_robot, fp, savegame, version);

  // Go back to where the names are
  fseek(fp, last_pos, SEEK_SET);
  for(i = 0; i < num_boards; i++)
  {
    cur_board = mzx_world->board_list[i];
    // Look at the name, width, and height of the just loaded board
    if(cur_board)
    {
      fread(cur_board->board_name, BOARD_NAME_SIZE, 1, fp);

      // Also patch a pointer to the global robot
      if(cur_board->robot_list)
        (mzx_world->board_list[i])->robot_list[0] = &mzx_world->global_robot;

      // Also optimize out null objects
      retrieve_board_from_extram(mzx_world->board_list[i]);
      optimize_null_objects(mzx_world->board_list[i]);
      store_board_to_extram(mzx_world->board_list[i]);
    }
    else
    {
      fseek(fp, BOARD_NAME_SIZE, SEEK_CUR);
    }
  }

  meter_update_screen(&meter_curr, meter_target);

  // This pointer is now invalid. Clear it before we try to
  // send it back to extra RAM.
  mzx_world->current_board = NULL;
  set_current_board_ext(mzx_world,
   mzx_world->board_list[mzx_world->current_board_id]);

  mzx_world->active = 1;

  // Remove any null boards
  optimize_null_boards(mzx_world);

  // Resize this array if necessary
  set_update_done(mzx_world);

  // Find the player
  find_player(mzx_world);

  meter_restore_screen();

  fclose(fp);
}

// After clearing the above, use this to get default values. Use
// for loading of worlds (as opposed to save games).

__editor_maybe_static void default_global_data(struct world *mzx_world)
{
  int i;

  // Allocate space for sprites and give them default values (all 0's)
  mzx_world->num_sprites = MAX_SPRITES;
  mzx_world->sprite_list = ccalloc(MAX_SPRITES, sizeof(struct sprite *));

  for(i = 0; i < MAX_SPRITES; i++)
  {
    mzx_world->sprite_list[i] = ccalloc(1, sizeof(struct sprite));
  }

  mzx_world->collision_list = ccalloc(MAX_SPRITES, sizeof(int));
  mzx_world->sprite_num = 0;

  // Set some default counter values
  // The others have to be here so their gateway functions will stick
  set_counter(mzx_world, "AMMO", 0, 0);
  set_counter(mzx_world, "COINS", 0, 0);
  set_counter(mzx_world, "ENTER_MENU", 1, 0);
  set_counter(mzx_world, "F2_MENU", 1, 0);
  set_counter(mzx_world, "GEMS", 0, 0);
  set_counter(mzx_world, "HEALTH", mzx_world->starting_health, 0);
  set_counter(mzx_world, "HELP_MENU", 1, 0);
  set_counter(mzx_world, "HIBOMBS", 0, 0);
  set_counter(mzx_world, "INVINCO", 0, 0);
  set_counter(mzx_world, "LIVES", mzx_world->starting_lives, 0);
  set_counter(mzx_world, "LOAD_MENU", 1, 0);
  set_counter(mzx_world, "LOBOMBS", 0, 0);
  set_counter(mzx_world, "SCORE", 0, 0);
  set_counter(mzx_world, "TIME", 0, 0);

  // Setup their gateways
  initialize_gateway_functions(mzx_world);

  mzx_world->multiplier = 10000;
  mzx_world->divider = 10000;
  mzx_world->c_divisions = 360;
  mzx_world->fread_delimiter = '*';
  mzx_world->fwrite_delimiter = '*';
  mzx_world->bi_shoot_status = 1;
  mzx_world->bi_mesg_status = 1;

  // And vlayer
  // Allocate space for vlayer.
  mzx_world->vlayer_size = 0x8000;
  mzx_world->vlayer_width = 256;
  mzx_world->vlayer_height = 128;
  mzx_world->vlayer_chars = cmalloc(0x8000);
  mzx_world->vlayer_colors = cmalloc(0x8000);
  memset(mzx_world->vlayer_chars, 32, 0x8000);
  memset(mzx_world->vlayer_colors, 7, 0x8000);

  // Default values for global params
  memset(mzx_world->keys, NO_KEY, NUM_KEYS);
  mzx_world->mesg_edges = 1;
  mzx_world->real_mod_playing[0] = 0;

  mzx_world->blind_dur = 0;
  mzx_world->firewalker_dur = 0;
  mzx_world->freeze_time_dur = 0;
  mzx_world->slow_time_dur = 0;
  mzx_world->wind_dur = 0;

  for(i = 0; i < 8; i++)
  {
    mzx_world->pl_saved_x[i] = 0;
  }

  for(i = 0; i < 8; i++)
  {
    mzx_world->pl_saved_y[i] = 0;
  }
  memset(mzx_world->pl_saved_board, 0, 8);
  mzx_world->saved_pl_color = 27;
  mzx_world->player_restart_x = 0;
  mzx_world->player_restart_y = 0;
  mzx_world->under_player_id = 0;
  mzx_world->under_player_color = 7;
  mzx_world->under_player_param = 0;

  mzx_world->commands = 40;

  default_scroll_values(mzx_world);

  scroll_color = 15;

  mzx_world->lock_speed = 0;
  mzx_world->mzx_speed = mzx_world->default_speed;

  assert(mzx_world->input_file == NULL);
  assert(mzx_world->output_file == NULL);
  assert(mzx_world->input_is_dir == false);

  mzx_world->target_where = TARGET_NONE;
}

bool reload_world(struct world *mzx_world, const char *file, int *faded)
{
  char name[BOARD_NAME_SIZE];
  int version;
  FILE *fp;

  fp = try_load_world(file, false, &version, name);
  if(!fp)
    return false;

  if(mzx_world->active)
  {
    clear_world(mzx_world);
    clear_global_data(mzx_world);
  }

  // Always switch back to regular mode before loading the world,
  // because we want the world's intrinsic palette to be applied.
  set_screen_mode(0);
  smzx_palette_loaded(0);
  set_palette_intensity(100);

  load_world(mzx_world, fp, file, false, version, name, faded);
  default_global_data(mzx_world);
  *faded = 0;

  // Now that the world's loaded, fix the save path.
  {
    char save_name[MAX_PATH];
    char current_dir[MAX_PATH];
    getcwd(current_dir, MAX_PATH);

    split_path_filename(curr_sav, NULL, 0, save_name, MAX_PATH);
    snprintf(curr_sav, MAX_PATH, "%s%s%s",
     current_dir, DIR_SEPARATOR, save_name);
  }

  return true;
}

bool reload_savegame(struct world *mzx_world, const char *file, int *faded)
{
  int version;
  FILE *fp;

  // Check this SAV is actually loadable
  fp = try_load_world(file, true, &version, NULL);
  if(!fp)
    return false;

  // It is, so wipe the old world
  if(mzx_world->active)
  {
    clear_world(mzx_world);
    clear_global_data(mzx_world);
  }

  // And load the new one
  load_world(mzx_world, fp, file, true, version, NULL, faded);
  return true;
}

bool reload_swap(struct world *mzx_world, const char *file, int *faded)
{
  char name[BOARD_NAME_SIZE];
  char full_path[MAX_PATH];
  char file_name[MAX_PATH];
  int version;
  FILE *fp;

  fp = try_load_world(file, false, &version, name);
  if(!fp)
    return false;

  if(mzx_world->active)
    clear_world(mzx_world);

  load_world(mzx_world, fp, file, false, version, name, faded);

  mzx_world->current_board_id = mzx_world->first_board;
  set_current_board_ext(mzx_world,
   mzx_world->board_list[mzx_world->current_board_id]);

  // Give curr_file a full path
  getcwd(full_path, MAX_PATH);
  split_path_filename(file, NULL, 0, file_name, MAX_PATH);
  snprintf(curr_file, MAX_PATH, "%s%s%s",
   full_path, DIR_SEPARATOR, file_name);

  return true;
}

// This only clears boards, no global data. Useful for swap world,
// when you want to maintain counters and sprites and all that.

void clear_world(struct world *mzx_world)
{
  // Do this before loading, when there's a world

  int i;
  int num_boards = mzx_world->num_boards;
  struct board **board_list = mzx_world->board_list;

  for(i = 0; i < num_boards; i++)
  {
    if(mzx_world->current_board_id != i)
      retrieve_board_from_extram(board_list[i]);
    clear_board(board_list[i]);
  }
  free(board_list);

  clear_robot_contents(&mzx_world->global_robot);

  if(!mzx_world->input_is_dir && mzx_world->input_file)
  {
    fclose(mzx_world->input_file);
    mzx_world->input_file = NULL;
  }
  else if(mzx_world->input_is_dir)
  {
    dir_close(&mzx_world->input_directory);
    mzx_world->input_is_dir = false;
  }

  if(mzx_world->output_file)
  {
    fclose(mzx_world->output_file);
    mzx_world->output_file = NULL;
  }

  mzx_world->active = 0;

  end_sample();
}

// This clears the rest of the stuff.

void clear_global_data(struct world *mzx_world)
{
  int i;
  int num_counters = mzx_world->num_counters;
  int num_strings = mzx_world->num_strings;
  struct counter **counter_list = mzx_world->counter_list;
  struct string **string_list = mzx_world->string_list;
  struct sprite **sprite_list = mzx_world->sprite_list;

  free(mzx_world->vlayer_chars);
  free(mzx_world->vlayer_colors);
  mzx_world->vlayer_chars = NULL;
  mzx_world->vlayer_colors = NULL;

  for(i = 0; i < num_counters; i++)
  {
    free(counter_list[i]);
  }
  free(counter_list);
  mzx_world->counter_list = NULL;

  mzx_world->num_counters = 0;
  mzx_world->num_counters_allocated = 0;

  for(i = 0; i < num_strings; i++)
  {
    free(string_list[i]);
  }

  free(string_list);
  mzx_world->string_list = NULL;
  mzx_world->num_strings = 0;
  mzx_world->num_strings_allocated = 0;

  for(i = 0; i < MAX_SPRITES; i++)
  {
    free(sprite_list[i]);
  }

  free(sprite_list);
  mzx_world->sprite_list = NULL;
  mzx_world->num_sprites = 0;

  free(mzx_world->collision_list);
  mzx_world->collision_list = NULL;
  mzx_world->collision_count = 0;

  mzx_world->active_sprites = 0;
  mzx_world->sprite_y_order = 0;

  mzx_world->vlayer_size = 0;
  mzx_world->vlayer_width = 0;
  mzx_world->vlayer_height = 0;

  mzx_world->output_file_name[0] = 0;
  mzx_world->input_file_name[0] = 0;

  memset(mzx_world->custom_sfx, 0, NUM_SFX * 69);

  mzx_world->bomb_type = 1;
  mzx_world->dead = 0;
}

void default_scroll_values(struct world *mzx_world)
{
  mzx_world->scroll_base_color = 143;
  mzx_world->scroll_corner_color = 135;
  mzx_world->scroll_pointer_color = 128;
  mzx_world->scroll_title_color = 143;
  mzx_world->scroll_arrow_color = 142;
}

// FIXME: This function should probably die. It's unsafe.
void add_ext(char *src, const char *ext)
{
  size_t len = strlen(src);

  if((len < 4) || ((src[len - 4] != '.') && (src[len - 3] != '.')
   && (src[len - 2] != '.')))
  {
    strncat(src, ext, 4);
  }
}


code:
/* MegaZeux
 *
 * Copyright (C) 2004 Gilead Kutnick <exophase@adelphia.net>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

#ifndef __WORLD_H
#define __WORLD_H

#include "compat.h"

__M_BEGIN_DECLS

#include "world_struct.h"

#include <stdio.h>

#include "board.h"
#include "const.h"
#include "robot.h"
#include "counter.h"
#include "sprite.h"
#include "sfx.h"
#include "configure.h"

/* When making new versions, change the number below, and
 * change the number in the version strings to follow. From now on,
 * be sure that the last two characters are the hex equivalent of the
 * MINOR version number.
 */

/* READ THIS -- MAGIC INFO
 *
 * World files:
 *
 *  MZX - Ver 1.x MegaZeux             (mzx_world->version == 0x0100)
 *  MZ2 - Ver 2.x MegaZeux             (mzx_world->version == 0x0205)
 *  MZA - Ver 2.51S1 Megazeux          (mzx_world->version == 0x0208)
 *  M\x02\x09 - 2.5.1spider2+
 *  M\x02\x32 - MZX 2.62
 *  M\x02\x3E - MZX 2.62b
 *  M\x02\x41 - MZX 2.65
 *  M\x02\x44 - MZX 2.68
 *  M\x02\x45 - MZX 2.69
 *  M\x02\x46 - MZX 2.69b
 *  M\x02\x48 - MZX 2.69c
 *  M\x02\x49 - MZX 2.70
 *  M\x02\x50 - MZX 2.80 (non-DOS)
 *  M\x02\x51 - MZX 2.81
 *  M\x02\x52 - MZX 2.82
 *  M\x02\x53 - MZX 2.83
 *  M\x02\x54 - MZX 2.84
 *
 * Save files:
 *
 *  MZSV2 - Ver 2.x MegaZeux           (mzx_world->version == 0x0205)
 *  MZXSA - Ver 2.51S1 MegaZeux        (mzx_world->version == 0x0208)
 *  MZS\x02\x09 - 2.5.1spider2+
 *  MZS\x02\x32 - MZX 2.62
 *  MZS\x02\x3E - MZX 2.62b
 *  MZS\x02\x41 - MZX 2.65
 *  MZS\x02\x44 - MZX 2.68
 *  MZS\x02\x45 - MZX 2.69
 *  MZS\x02\x46 - MZX 2.69b
 *  MZS\x02\x48 - MZX 2.69c
 *  MZS\x02\x49 - MZX 2.70
 *  MZS\x02\x50 - MZX 2.80 (non-DOS)
 *  MZS\x02\x51 - MZX 2.81
 *  MZS\x02\x52 - MZX 2.82
 *  MZS\x02\x53 - MZX 2.83
 *  MZS\x02\x54 - MZX 2.84
 *
 * Board files follow a similar pattern to world files. Versions prior to
 * 2.51S1 are "MB2". For versions greater than 2.51S1, they match the
 * world file magic. For all boards, the first byte is always 0xFF.
 *
 * As of 2.80+, all letters after the name denote bug fixes/minor additions
 * and may have different save formats. If a save format change is
 * necessitated, a numerical change must be enacted.
 */

/* The magic stamp for worlds, boards or SAV files created with this version
 * of MegaZeux. If you introduce a counter or any other incompatible change,
 * such as altering semantics or actually changing the binary format, this
 * value MUST be bumped.
 */
#define WORLD_VERSION      0x0254

/* See the downver.c tool for more information. Please, if you bump the
 * WORLD_VERSION, always make sure this is updated with its previous
 * value. Therefore, users can always downgrade their work to an
 * older version (if it at all makes sense to do so).
 */
#define WORLD_VERSION_PREV 0x0253

// FIXME: hack
#ifdef CONFIG_DEBYTECODE
#undef  WORLD_VERSION
#define WORLD_VERSION      0x025A
#undef  WORLD_VERSION_PREV
#endif

// These three are needed by validation.c until I figure out a better way
CORE_LIBSPEC int world_magic(const char magic_string[3]);
CORE_LIBSPEC int save_magic(const char magic_string[5]);

CORE_LIBSPEC int save_world(struct world *mzx_world, const char *file,
 int savegame);
CORE_LIBSPEC bool reload_world(struct world *mzx_world, const char *file,
 int *faded);
CORE_LIBSPEC void clear_world(struct world *mzx_world);
CORE_LIBSPEC void clear_global_data(struct world *mzx_world);
CORE_LIBSPEC void default_scroll_values(struct world *mzx_world);

CORE_LIBSPEC void add_ext(char *src, const char *ext);

bool reload_savegame(struct world *mzx_world, const char *file, int *faded);
bool reload_swap(struct world *mzx_world, const char *file, int *faded);

// Code to load multi-byte ints from little endian file

int fgetw(FILE *fp);
int fgetd(FILE *fp);
void fputw(int src, FILE *fp);
void fputd(int src, FILE *fp);

#ifdef CONFIG_EDITOR
CORE_LIBSPEC FILE *try_load_world(const char *file, bool savegame,
 int *version, char *name);
CORE_LIBSPEC void default_global_data(struct world *mzx_world);
CORE_LIBSPEC void optimize_null_boards(struct world *mzx_world);
CORE_LIBSPEC void set_update_done(struct world *mzx_world);
#endif // CONFIG_EDITOR

__M_END_DECLS

#endif // __WORLD_H

repo_name: pgimeno/megazeux

license: mit


code:
/* MegaZeux
 *
 * Copyright (C) 2004 Gilead Kutnick <exophase@adelphia.net>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

#ifndef __WORLD_STRUCT_H
#define __WORLD_STRUCT_H

#include "compat.h"

__M_BEGIN_DECLS

#include "board_struct.h"
#include "robot_struct.h"
#include "counter_struct.h"
#include "sprite_struct.h"
#include "configure.h"

#ifdef CONFIG_EDITOR
#include "editor/configure.h"
#endif

#include "sfx.h"
#include "util.h"

struct world
{
  // 0 if a world has been loaded, 1 if it hasn't
  int active;
  char name[BOARD_NAME_SIZE];

  int version;
  // Move here eventually
  //char id_chars[455];
  char status_counters_shown[NUM_STATUS_COUNTERS][COUNTER_NAME_SIZE];

  // Save game material, part 1
  char keys[NUM_KEYS];
  int blind_dur;
  int firewalker_dur;
  int freeze_time_dur;
  int slow_time_dur;
  int wind_dur;
  int pl_saved_x[8];
  int pl_saved_y[8];
  int pl_saved_board[8];
  int saved_pl_color;
  int was_zapped;
  int under_player_id;
  int under_player_color;
  int under_player_param;
  int mesg_edges;
  int scroll_base_color;
  int scroll_corner_color;
  int scroll_pointer_color;
  int scroll_title_color;
  int scroll_arrow_color;
  char real_mod_playing[MAX_PATH];

  int edge_color;
  int first_board;
  int endgame_board;
  int death_board;
  int endgame_x;
  int endgame_y;
  int game_over_sfx;
  int death_x;
  int death_y;
  int starting_lives;
  int lives_limit;
  int starting_health;
  int health_limit;
  int enemy_hurt_enemy;
  int clear_on_exit;
  int only_from_swap;

  // Save game material, part 2
  int player_restart_x;
  int player_restart_y;
  int num_counters;
  int num_counters_allocated;
  struct counter **counter_list;
  int num_strings;
  int num_strings_allocated;
  struct string **string_list;
  int num_sprites;
  int num_sprites_allocated;
  int sprite_num;
  struct sprite **sprite_list;
  int active_sprites;
  int sprite_y_order;
  int collision_count;
  int *collision_list;
  int multiplier;
  int divider;
  int c_divisions;
  int fread_delimiter;
  int fwrite_delimiter;
  int bi_shoot_status;
  int bi_mesg_status;
  char output_file_name[MAX_PATH];
  FILE *output_file;
  char input_file_name[MAX_PATH];
  FILE *input_file;
  bool input_is_dir;
  struct mzx_dir input_directory;
  int commands;
  int vlayer_size;
  int vlayer_width;
  int vlayer_height;
  char *vlayer_chars;
  char *vlayer_colors;

  int num_boards;
  int num_boards_allocated;
  struct board **board_list;
  struct board *current_board;
  int current_board_id;

  struct robot global_robot;

  int custom_sfx_on;
  char custom_sfx[NUM_SFX * 69];

  // Not part of world/save files, but runtime globals
  int player_x;
  int player_y;

  // For moving the player between boards
  enum board_target target_where;
  int target_board;
  int target_x;
  int target_y;
  enum thing target_id;
  int target_color;
  enum thing target_d_id;
  int target_d_color;

  // Indiciates if the player is dead
  int dead;

  // Current bomb type
  int bomb_type;

  // Toggle for if the screen is in slow motion
  int slow_down;

  // For use in repeat delays for player movement
  int key_up_delay;
  int key_down_delay;
  int key_right_delay;
  int key_left_delay;

  // 1-3 normal 5-7 is 1-3 but from a REL FIRST cmd
  int first_prefix;
  // Just 1-3
  int mid_prefix;
  // 1-3 normal 5-7 is 1-3 but from a REL LAST cmd
  int last_prefix;

  // Lets the get counter routines indiciate to the caller
  // that the result is not a typical counter but something
  // special. It's there for those horribly hacked file open
  // counters. It should normally be set to FOPEN_NONE.
  enum special_counter_return special_counter_return;

  // Indicates if a robot swapped the world
  int swapped;

  // Current speed of MZX world
  int mzx_speed;
  // Default speed (as loaded by config file)
  int default_speed;
  // If we can change the speed from the F2 menu.
  int lock_speed;

  struct config_info conf;

#ifdef CONFIG_EDITOR
  struct editor_config_info editor_conf;
  bool editing;
#endif

  // Keep this open, just once
  FILE *help_file;

  // An array for game2.cpp
  char *update_done;
  int update_done_size;
};

__M_END_DECLS

#endif // __WORLD_STRUCT_H


code:
{
   leak in SDL_VideoInit
   Memcheck:Leak
   fun:realloc
   obj:/usr/lib/libX11.so*
   obj:/usr/lib/libX11.so*
   obj:/usr/lib/libX11.so*
   fun:_XlcCreateLC
   fun:_XlcDefaultLoader
   fun:_XOpenLC
   fun:_XlcCurrentLC
   fun:XSetLocaleModifiers
   obj:/usr/lib/libSDL*.so*
   obj:/usr/lib/libSDL*.so*
   fun:SDL_VideoInit
}

{
   theme and variation on leak in SDL_VideoInit
   Memcheck:Leak
   fun:realloc
   obj:/usr/lib/libX11.so*
   obj:/usr/lib/libX11.so*
   fun:_XlcCreateLC
   fun:_XlcDefaultLoader
   fun:_XOpenLC
   fun:_XlcCurrentLC
   fun:XSetLocaleModifiers
   fun:XSetLocaleModifiers
   obj:/usr/lib/libSDL*.so*
   obj:/usr/lib/libSDL*.so*
   fun:SDL_VideoInit
}

{
   another leak in SDL_VideoInit
   Memcheck:Leak
   fun:malloc
   obj:/usr/lib/libX11.so*
   fun:_XimSetICValueData
   fun:_XimLocalCreateIC
   fun:XCreateIC
   obj:/usr/lib/libSDL*.so*
   obj:/usr/lib/libSDL*.so*
   fun:SDL_VideoInit
   fun:SDL_InitSubSystem
   fun:SDL_Init
   fun:platform_init
   fun:main
}

{
   variation on another a leak in SDL_VideoInit
   Memcheck:Leak
   fun:malloc
   obj:/usr/lib/libX11.so*
   obj:/usr/lib/libX11.so*
   fun:_XimSetICValueData
   fun:_XimLocalCreateIC
   fun:XCreateIC
   obj:/usr/lib/libSDL*.so*
   obj:/usr/lib/libSDL*.so*
   fun:SDL_VideoInit
   fun:SDL_InitSubSystem
   fun:SDL_Init
   fun:platform_init
}

{
   Leak in SDL_AudioInit
   Memcheck:Leak
   fun:malloc
   obj:*
   obj:*
   fun:Audio_Available
   fun:SDL_AudioInit
   fun:SDL_InitSubSystem
   fun:SDL_Init
   fun:platform_init
   fun:main
}

{
   Another leak in SDL_AudioInit
   Memcheck:Leak
   fun:malloc
   obj:*
   obj:*
   obj:*
   fun:Audio_Available
   fun:SDL_AudioInit
   fun:SDL_InitSubSystem
   fun:SDL_Init
   fun:platform_init
   fun:main
}


code:
#
# MegaZeux version information for building and packaging
#
# NOTE: VERSION must be kept in quotes, in case spaces are used.
# NOTE: TARGET must NOT be kept in quotes, and spaces CANNOT be used.
#

VERSION="2.84b"
TARGET=mzx284b


code:
root = true

[*.cr]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 2
trim_trailing_whitespace = true

path: .editorconfig


code:
/docs/
/lib/
/bin/
/.shards/
*.dwarf

path: .gitignore


code:
# lyristal

a Crystal library for getting lyrics from [AZLyrics](https://www.azlyrics.com)

# Example

an example application is included in test.cr

# Installation

add this to your *shard.yml*:
```
dependencies:
  lyristal:
    git: https://notabug.org/resner/lyristal.git
```


code:
version: 2.0
shards:
  crystagiri:
    git: https://github.com/madeindjs/crystagiri.git
    version: 0.3.5


code:
name: lyristal
version: 0.1.0

authors:
  - resner <resner2resner@morke.org>

targets:
  lyristal:
    main: src/lyristal.cr

crystal: 1.4.1

license: GPLv3

dependencies:
  crystagiri:
    github: madeindjs/crystagiri


code:
require "./spec_helper"

describe Lyristal do
  # TODO: Write tests

  it "works" do
    false.should eq(true)
  end
end


code:
require "spec"
require "../src/lyristal"


code:
require "crystagiri"
require "http/client"
require "uri"

module Lyristal
  VERSION = "0.1.0"

  class AZLyrics
    def getLyricsPage(artist, title)
      cleanedArtist = artist.gsub(/[^A-Za-z0-9]/, "").downcase
      cleanedTitle = title.gsub(/[^A-Za-z]/, "").downcase
      lyricsURL = "https://www.azlyrics.com/lyrics/#{cleanedArtist}/#{cleanedTitle}.html"

      HTTP::Client.get lyricsURL do |response|
        return {
          "code": response.status_code,
          "url": lyricsURL
        }
      end
    end

    def scrapeLyrics(url)
      html = HTTP::Client.get url
      doc = Crystagiri::HTML.new html.body

      doc.where_tag("div") do |tag|
        if !tag.classname && tag.node.to_s.includes? "<!-- Usage of azlyrics.com content by any third-party lyrics provider is prohibited by our licensing agreement. Sorry about that. -->"
          return tag.content.to_s.lstrip
        end
      end
    end
  end
end


code:
require "./src/lyristal.cr"
require "option_parser"

artist = ""
song = ""

OptionParser.parse do |parser|
    parser.banner = "lyristal example usage"
    parser.on("-a ARTIST", "--artist=ARTIST", "specify song artist") { |a| artist = a}
    parser.on("-n NAME", "--name=NAME", "specify song name") { |n| song = n }
    parser.on("-h", "--help", "show this") do
        puts parser
        exit
    end
end

if artist == "" || song == ""
    puts "Artist or song name not specified."
    exit
end

lyristal = Lyristal::AZLyrics.new
lyricsPageResponse = lyristal.getLyricsPage(artist, song)
if lyricsPageResponse[:code] == 200
    puts "Found lyrics URL: #{lyricsPageResponse[:url]}"
else
    puts "Got code #{lyricsPageResponse[:code]} in response, is the artist and song title spelt correctly?"
    exit
end
lyrics = lyristal.scrapeLyrics(lyricsPageResponse[:url])
puts "Fetched lyrics:"
puts lyrics


code:
# /usr/bin/env python
# -*- coding: utf-8 -*-
"""
@author: Eduardo
22 de Maio de 2017
HyperRayleigh Scattering Analysis
"""

import matplotlib.pyplot as plt
from matplotlib.backends.backend_gtk3agg import FigureCanvasGTK3Agg as FigureCanvas
# from matplotlib.backends.backend_gtk3cairo import FigureCanvasGTK3Cairo as FigureCanvas
from matplotlib.widgets import SpanSelector, Cursor
import numpy as np
import sys
import os
from scipy.optimize import curve_fit
import string
# import subprocess

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk

class MyWindow(Gtk.Window):

    def __init__(self):
        Gtk.Window.__init__(self)

        # self.hb = Gtk.HeaderBar()
        # self.hb.set_show_close_button(True)
        # self.hb.props.title = "Linear Absorption Analysis"
        # self.set_titlebar(self.hb)

        self.set_title("Linear Absorption Analysis")
        self.set_wmclass("Linear Absorption Analysis",
                         "Linear Absorption Analysis")

        self.set_border_width(10)
        self.set_default_size(2000, 1000)
        self.set_position(Gtk.WindowPosition.CENTER)

        self.lbEsc = Gtk.Label(label="Select file:")

        self.filepath = Gtk.Entry()

        self.btBrowse = Gtk.Button(label="Browse")
        self.btBrowse.connect("clicked", self.EscolheAqv)

        self.btFile = Gtk.Button(label="Analyse Files")
        self.btFile.set_sensitive(False)
        self.btFile.connect("clicked", self.seleciona)

        self.buttonOK = Gtk.Button(label="     Next    ")
        self.buttonOK.connect("clicked", self.proximo)

        self.btSkip = Gtk.Button(label="     Skip    ")
        self.btSkip.connect("clicked", self.skip)

        self.buttonQuit = Gtk.Button(label="Remove Last")
        self.buttonQuit.connect("clicked", self.removelast)

        self.btConcentra = Gtk.Button(label="Select Concentration File")
        self.btConcentra.connect("clicked", self.EscolheConc)

        self.btSalva = Gtk.Button(label="Save")
        self.btSalva.connect("clicked", self.Salva)

        self.liststore = Gtk.ListStore(str, str, float)
        self.treeview = Gtk.TreeView(model=self.liststore)

        self.sel = self.treeview.get_selection()
        self.sel.set_mode(Gtk.SelectionMode.NONE)

        self.amostra_text = Gtk.CellRendererText()
        self.column_amostra = Gtk.TreeViewColumn("Sample",
                                                 self.amostra_text, text=0)
        self.treeview.append_column(self.column_amostra)

        self.concentra_text = Gtk.CellRendererText()
        self.column_concentra = Gtk.TreeViewColumn("Concentration",
                                                   self.concentra_text, text=1)
        self.treeview.append_column(self.column_concentra)

        self.abs_text = Gtk.CellRendererText()
        self.column_abs = Gtk.TreeViewColumn("Abs (532)",
                                             self.abs_text, text=2)
        self.treeview.append_column(self.column_abs)

        self.bxchose = Gtk.HBox(spacing=6)
        self.boxgraph = Gtk.HBox(spacing=6)
        self.boxsubgraph = Gtk.VBox(spacing=6)
        self.boxV = Gtk.VBox(spacing=6)
        self.bxbutton = Gtk.HBox(spacing=6)
        self.bxTodos = Gtk.HBox(spacing=6)
        self.bxlist = Gtk.VBox(spacing=6)

        self.fg = plt.figure()
        self.ax = self.fg.add_subplot(111)

        self.ax.set_title('Absorption Spectrum')
        self.ax.set_xlabel('$\lambda$ (nm)')
        self.ax.set_ylabel('A (O.D)')

        self.cv1 = FigureCanvas(self.fg)
        # self.cursor = Cursor(self.ax, useblit=True, horizOn=True,
        #                      color='#ff9896', lw=1.5, alpha=0.9)

        self.fg2 = plt.figure()
        self.ax2 = self.fg2.add_subplot(111)
        self.ax2.set_title('Absorption Todas')
        self.ax2.set_xlabel('$\lambda$ (nm)')
        self.ax2.set_ylabel('A (O.D)')

        self.line2, = self.ax2.plot([], [])
        # self.ax2.ticklabel_format(style='sci', scilimits=(-2, 2), axis='both')

        self.cv2 = FigureCanvas(self.fg2)

        self.fg4 = plt.figure()
        self.ax4 = self.fg4.add_subplot(111)
        self.ax4.set_title('Beer-Lambert Law')

        self.line4, = self.ax4.plot([], [], 'ok')
        self.cv4 = FigureCanvas(self.fg4)

        self.bxbutton.pack_end(self.buttonOK, True, True, 0)
        self.bxbutton.pack_end(self.btSkip, True, True, 0)
        self.bxbutton.pack_end(self.buttonQuit, True, True, 0)

        self.bxchose.pack_start(self.lbEsc, False, True, 0)
        self.bxchose.pack_start(self.filepath, True, True, 0)
        self.bxchose.pack_start(self.btBrowse, False, True, 0)
        self.bxchose.pack_start(self.btFile, False, True, 0)

        self.boxsubgraph.pack_start(self.cv2, True, True, 0)
        self.boxsubgraph.pack_start(self.cv4, True, True, 0)

        self.boxgraph.pack_start(self.cv1, True, True, 0)
        self.boxgraph.pack_start(self.boxsubgraph, True, True, 0)

        self.boxV.pack_start(self.bxchose, False, True, 0)
        self.boxV.pack_start(self.boxgraph, True, True, 0)

        self.bxlist.pack_start(self.btConcentra, False, True, 0)
        self.bxlist.pack_start(self.treeview, True, True, 0)
        self.bxlist.pack_start(self.bxbutton, False, False, 0)
        self.bxlist.pack_end(self.btSalva, False, True, 0)

        self.bxTodos.pack_start(self.boxV, True, True, 0)
        self.bxTodos.pack_start(self.bxlist, False, True, 5)
        self.add(self.bxTodos)

    def proximo(self, event):

        self.ax2.plot(self.spect[:, 0], self.corrspect)
        self.fg2.canvas.draw()

        self.filepath.set_sensitive(True)
        self.lbEsc.set_sensitive(True)
        self.btBrowse.set_sensitive(True)
        self.btFile.set_sensitive(True)

        self.liststore[self.listline][2] = self.a532
        self.quad.append((
            float(self.liststore[self.listline][1]),
            self.liststore[self.listline][2],
            np.sqrt(self.pcov[0, 0])))

        self.listline += 1

    def quit(self, event):
        print('Exit')
        sys.exit()

    def removelast(self, event):
        self.quad.pop()
        self.listline -= 1
        self.liststore[self.listline][2] = 0.0

        self.filepath.set_sensitive(True)
        self.lbEsc.set_sensitive(True)
        self.btBrowse.set_sensitive(True)
        self.btFile.set_sensitive(True)

    def seleciona(self, event):
        if self.filepath.get_text() == "":
            self.alertempty()
        else:
            self.set_title(self.filepath.get_text())
            self.filepath.set_sensitive(False)
            self.lbEsc.set_sensitive(False)
            self.btBrowse.set_sensitive(False)
            self.btFile.set_sensitive(False)
            self.direc = self.filepath.get_text()
            self.ax.cla()
            self.plota()

    def EscolheAqv(self, event):
        dialog = Gtk.FileChooserDialog(
            "Selecione o arquivo", None, Gtk.FileChooserAction.OPEN, (
                Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
                Gtk.STOCK_OPEN, Gtk.ResponseType.OK))
        dialog.set_transient_for(self)

        response = dialog.run()
        if response == Gtk.ResponseType.OK:
            self.filepath.set_text(dialog.get_filename())
        elif response == Gtk.ResponseType.CANCEL:
            print("Cancel clicked")

        dialog.destroy()

    def EscolheConc(self, event):
        dialog = Gtk.FileChooserDialog(
            "Select Concentration File", None, Gtk.FileChooserAction.OPEN, (
                Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
                Gtk.STOCK_OPEN, Gtk.ResponseType.OK))

        dialog.set_transient_for(self)
        response = dialog.run()

        if response == Gtk.ResponseType.OK:
            self.liststore.clear()
            self.btFile.set_sensitive(True)
            self.quad = []
            self.listline = 0

            self.conc = open(dialog.get_filename(), 'r')

            try:
                for line in self.conc:
                    (self.smp, self.phi) = line.split()
                    # self.phi = float(self.phi)
                    self.liststore.append([self.smp, self.phi, 0.0])
                    # self.liststore.append([
                    #     self.smp, format(self.phi, '.2e'), 0.0])
            except:
                self.alertconc()

        elif response == Gtk.ResponseType.CANCEL:
            print("Cancel clicked")

        dialog.destroy()

    def onselect(self, xmin, xmax):
        self.imin = np.searchsorted(self.spect[:, 0], xmin)
        self.imax = np.searchsorted(self.spect[:, 0], xmax)

        self.i532 = np.searchsorted(self.spect[:, 0], 532)
        self.tempdata = []

        try:
            self.param_bounds=(0, np.inf)
            self.p, self.pcov = curve_fit(
                self.Baseline,
                self.spect[self.imin:self.imax, 0],
                self.spect[self.imin:self.imax, 1])

            self.x = np.arange(300, 1100, 10)
            self.y = self.Baseline(self.x, *self.p)

            self.line.set_data(self.x, self.y)
            self.fg.canvas.draw()

            self.corrspect = self.spect[:, 1] - self.Baseline(self.spect[:, 0],
                                                          *self.p)
            self.a532 = self.corrspect[self.i532]

            self.plotaax2()

            self.line4.set_data([], [])
            self.fg4.canvas.draw()

            for linha in self.quad:
                self.tempdata.append(linha)

            self.tempdata.append((
                float(self.liststore[self.listline][1]),
                self.a532, np.sqrt(self.pcov[0, 0])))

            self.tempdata = np.array(self.tempdata)

            print(self.tempdata)

            self.line4.set_data(self.tempdata[:, 0], self.tempdata[:, 1])

            # recompute the ax.dataLim
            self.ax4.relim()
            # update ax.viewLim using the new dataLim
            self.ax4.autoscale_view()

            self.fg4.canvas.draw()

        except:
            print('intervalo')

    def plota(self):
        print('Analising sample: %s' % self.filepath.get_text())

        self.ax.set_title('Absorption Spectrum')
        self.ax.set_xlabel('$\lambda$ (nm)')
        self.ax.set_ylabel('A (O.D)')
        self.ax.set_xlim(350, 950)
        self.ax.set_ylim(-0.1, 3)

        self.ax.ticklabel_format(style='sci', scilimits=(-2, 2), axis='both')

        self.span = SpanSelector(self.ax, self.onselect, 'horizontal',
                                 useblit=False, rectprops=dict(
                                     alpha=0.7, facecolor='#aec7e8'))

        self.spect = np.genfromtxt(self.filepath.get_text(), skip_header=2)

        self.ax.plot(self.spect[:, 0], self.spect[:, 1], '-', alpha=0.85)

        self.line, = self.ax.plot(self.spect[:, 0], self.spect[:, 0],
                                  lw=2, zorder=9)

        self.line.set_data([], [])
        # recompute the ax.dataLim
        self.ax.relim()
        # update ax.viewLim using the new dataLim
        self.ax.autoscale_view()

        self.fg.canvas.draw()

    def plotaax2(self):
        self.line2.set_data(self.spect[:, 0], self.corrspect)
        self.ax2.set_xlim(350, 950)
        self.ax2.set_ylim(-0.1, 3)
        # # recompute the ax.dataLim
        # self.ax2.relim()
        # # update ax.viewLim using the new dataLim
        # self.ax2.autoscale_view()
        self.fg2.canvas.draw()

    def plotavarios(self):
        self.files = [file for file in sorted(os.listdir(
            self.filepath.get_text())) if file.endswith('s.dat')]

        for aqv in self.files:
            print(aqv)
            dados = np.genfromtxt(self.filepath.get_text() +
                                  '/' + aqv)

            self.line, = self.ax.plot(dados)
            self.ax.draw()
            # print(self.files)

    def alertempty(self):
        dialog = Gtk.MessageDialog(self, 0, Gtk.MessageType.INFO,
                                   Gtk.ButtonsType.OK, "Empy filepath")
        dialog.format_secondary_text(
            "Please select a file to analyse")
        dialog.run()

        dialog.destroy()

    def alertconc(self):
        dialog = Gtk.MessageDialog(self, 0, Gtk.MessageType.INFO,
                                   Gtk.ButtonsType.OK, "Unable to import file")
        dialog.format_secondary_text(
            "Please check if the file has two columns: sample, concentration")
        dialog.run()

        dialog.destroy()

    def Salva(self, event):

        self.filename = string.split(self.filepath.get_text(), '/')[-1]
        self.samplename = string.split(self.filename, '_')[0]

        dialog = Gtk.FileChooserDialog(
            "Save file", None, Gtk.FileChooserAction.SAVE, (
                Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
                Gtk.STOCK_SAVE, Gtk.ResponseType.OK))

        dialog.set_transient_for(self)
        dialog.set_current_name(self.samplename + '.blb')
        dialog.set_do_overwrite_confirmation(True)

        response = dialog.run()
        if response == Gtk.ResponseType.OK:
            self.path = dialog.get_filename()
            print('Saving file: ' + self.path)
            self.salva = np.array(self.quad)
            np.savetxt(self.path, self.salva, delimiter='\t')
            print('Done')
        elif response == Gtk.ResponseType.CANCEL:
            print("Cancel clicked")

        dialog.destroy()

    def skip(self, event):
        self.listline += 1

    def Scat(self, x, a):
        return a/(x**4)

    def Baseline(self, x, a):
        return a

    def Parabola(self, x, a, b):
        return a*x**2 + b

    def Afin(self, x, a, b):
        return a*x + b

win = MyWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()

repo_name: selleduardo/HRS

license: unknown


code:
#/usr/bin/env python
# -*- coding: utf-8 -*-
"""
@author: Eduardo
22 de Maio de 2017
HyperRayleigh Scattering Analysis
"""

import matplotlib.pyplot as plt
from matplotlib.backends.backend_gtk3agg import FigureCanvasGTK3Agg as FigureCanvas
# from matplotlib.backends.backend_gtk3cairo import FigureCanvasGTK3Cairo as FigureCanvas
from matplotlib.widgets import SpanSelector, Cursor
import numpy as np
import sys
import os
from scipy.optimize import curve_fit
import string
# import subprocess

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk

class MyWindow(Gtk.Window):

    def __init__(self):
        Gtk.Window.__init__(self)

        self.set_title("Baseline")
        self.set_wmclass("Baseline", "Baseline")

        self.set_border_width(10)
        self.set_default_size(2000, 1000)
        self.set_position(Gtk.WindowPosition.CENTER)

        self.lbEsc = Gtk.Label(label="Select file:")

        self.filepath = Gtk.Entry()

        self.btBrowse = Gtk.Button(label="Browse")
        self.btBrowse.connect("clicked", self.EscolheAqv)

        self.btFile = Gtk.Button(label="Analyse Files")
        self.btFile.connect("clicked", self.seleciona)

        self.buttonOK = Gtk.Button(label="OK")
        self.buttonOK.connect("clicked", self.proximo)

        self.btSalva = Gtk.Button(label="Save")
        self.btSalva.connect("clicked", self.Salva)

        self.bxchose = Gtk.HBox(spacing=6)
        self.boxplot = Gtk.VBox(spacing=6)
        self.boxV = Gtk.VBox(spacing=6)
        self.bxbutton = Gtk.HBox(spacing=6)

        self.fg = plt.figure()
        self.ax = self.fg.add_subplot(111)

        self.ax.set_title('Signal')

        self.ax.ticklabel_format(style='sci', scilimits=(-2, 2), axis='both')

        self.cv1 = FigureCanvas(self.fg)
        # self.cursor = Cursor(self.ax, useblit=True, horizOn=True,
        #                      color='#ff9896', lw=1.5, alpha=0.9)

        self.bxchose.pack_start(self.lbEsc, False, True, 0)
        self.bxchose.pack_start(self.filepath, True, True, 0)
        self.bxchose.pack_start(self.btBrowse, False, True, 0)
        self.bxchose.pack_start(self.btFile, False, True, 0)

        self.bxbutton.pack_start(self.buttonOK, True, True, 0)
        self.bxbutton.pack_start(self.btSalva, True, True, 0)

        self.boxplot.pack_start(self.cv1, True, True, 0)

        self.boxV.pack_start(self.bxchose, False, True, 0)
        self.boxV.pack_start(self.boxplot, True, True, 0)
        self.boxV.pack_start(self.bxbutton, False, True, 0)

        self.add(self.boxV)

    def proximo(self, event):

        self.sgn[:, 1] = self.sgn[:, 1] - self.Baseline(self.sgn[:, 0], *self.p)

        self.ax.cla()
        self.ax.plot(self.sgn[:, 0], self.sgn[:, 1])
        self.fg.canvas.draw()

        self.boxplot.set_sensitive(False)

        self.filepath.set_sensitive(True)
        self.lbEsc.set_sensitive(True)
        self.btBrowse.set_sensitive(True)
        self.btFile.set_sensitive(True)

    def seleciona(self, event):
        if self.filepath.get_text() == "":
            self.alertempty()
        else:
            self.boxplot.set_sensitive(True)
            self.set_title(self.filepath.get_text())
            self.ax.cla()
            self.plota()

    def EscolheAqv(self, event):
        dialog = Gtk.FileChooserDialog(
            "Selecione o arquivo", None, Gtk.FileChooserAction.OPEN, (
                Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
                Gtk.STOCK_OPEN, Gtk.ResponseType.OK))
        dialog.set_transient_for(self)

        response = dialog.run()
        if response == Gtk.ResponseType.OK:
            self.filepath.set_text(dialog.get_filename())
        elif response == Gtk.ResponseType.CANCEL:
            print("Cancel clicked")

        dialog.destroy()

    def onselect(self, xmin, xmax):
        self.imin = np.searchsorted(self.sgn[:, 0], xmin)
        self.imax = np.searchsorted(self.sgn[:, 0], xmax)

        try:
            self.p, self.pcov = curve_fit(
                self.Baseline,
                self.sgn[self.imin:self.imax, 0],
                self.sgn[self.imin:self.imax, 1])

            self.lims = self.ax.get_xlim()
            self.x = np.arange(self.lims[0], self.lims[1], self.lims[1]/11.0)
            self.y = self.Baseline(self.x, *self.p)

            self.line.set_data(self.x, self.y)
            self.fg.canvas.draw()

        except:
            print('Not able to fit. Try again')

    def plota(self):
        print('Analising sample: %s' % self.filepath.get_text())
        self.ax.cla()

        self.span = SpanSelector(self.ax, self.onselect, 'horizontal',
                                 useblit=False, rectprops=dict(
                                     alpha=0.7, facecolor='#aec7e8'))

        self.Imps = np.genfromtxt(self.filepath.get_text())

        self.sgn = np.column_stack((
            np.arange(0, np.shape(self.Imps)[0]),
            np.average(self.Imps, axis=1)))

        self.ax.plot(self.sgn[:, 0], self.sgn[:, 1], '-')
        self.ax.relim()
        self.ax.autoscale_view()

        self.line, = self.ax.plot(self.sgn[:, 0], self.sgn[:, 1], '-')
        self.line.set_data([], [])
        self.fg.canvas.draw()

    def alertempty(self):
        dialog = Gtk.MessageDialog(self, 0, Gtk.MessageType.INFO,
                                   Gtk.ButtonsType.OK, "Empy filepath")
        dialog.format_secondary_text(
            "Please select a file to analyse")
        dialog.run()

        dialog.destroy()

    def alertconc(self):
        dialog = Gtk.MessageDialog(self, 0, Gtk.MessageType.INFO,
                                   Gtk.ButtonsType.OK,
                                   "Unable to import file")
        dialog.format_secondary_text(
            "Please check if the concentration file has columns: (sample, concentration) and absorbption file (sample, A532nm)")
        dialog.run()

        dialog.destroy()

    def Salva(self, event):

        self.filename = string.split(self.filepath.get_text(), '/')[-1]

        dialog = Gtk.FileChooserDialog(
            "Save file", None, Gtk.FileChooserAction.SAVE, (
                Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
                Gtk.STOCK_SAVE, Gtk.ResponseType.OK))

        dialog.set_transient_for(self)
        dialog.set_current_name(self.filename)
        dialog.set_do_overwrite_confirmation(True)

        response = dialog.run()

        if response == Gtk.ResponseType.OK:
            self.path = dialog.get_filename()
            print('Saving file: ' + self.path)
            np.savetxt(self.path, self.sgn, delimiter='\t')
            print('Done')
        elif response == Gtk.ResponseType.CANCEL:
            print("Cancel clicked")

        dialog.destroy()

    def Parabola(self, x, a, b):
        return a*x**2 + b

    def Baseline(self, x, a):
        return a*x/x

win = MyWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()


code:
#/usr/bin/env python
# -*- coding: utf-8 -*-
"""
@author: Eduardo
22 de Maio de 2017
HyperRayleigh Scattering Analysis
"""

import matplotlib.pyplot as plt
from matplotlib.backends.backend_gtk3agg import FigureCanvasGTK3Agg as FigureCanvas
# from matplotlib.backends.backend_gtk3cairo import FigureCanvasGTK3Cairo as FigureCanvas
from matplotlib.widgets import SpanSelector, Cursor
from matplotlib.lines import Line2D
import numpy as np
import sys
import os
from scipy.optimize import curve_fit
import string
# import subprocess

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk

class MyWindow(Gtk.Window):

    def __init__(self):
        Gtk.Window.__init__(self)

        # self.hb = Gtk.HeaderBar()
        # self.hb.set_show_close_button(True)
        # self.hb.props.title = "HRS Analysis"
        # self.set_titlebar(self.hb)

        self.set_title("HRS Analysis")
        self.set_wmclass("HRS Analysis", "HRS Analysis")

        self.set_border_width(10)
        self.set_default_size(2000, 1000)
        self.set_position(Gtk.WindowPosition.CENTER)

        self.lbEsc = Gtk.Label(label="Select file:")

        self.filepath = Gtk.Entry()

        self.btBrowse = Gtk.Button(label="Browse")
        self.btBrowse.connect("clicked", self.EscolheAqv)

        self.btFile = Gtk.Button(label="Analyse Files")
        self.btFile.set_sensitive(False)
        self.btFile.connect("clicked", self.seleciona)

        self.buttonOK = Gtk.Button(label="     Next    ")
        self.buttonOK.connect("clicked", self.proximo)

        self.buttonQuit = Gtk.Button(label="Remove Last")
        self.buttonQuit.connect("clicked", self.removelast)

        self.btConcentra = Gtk.Button(label="Select Concentration/Absorption File")
        self.btConcentra.connect("clicked", self.EscolheConc)

        self.btSalva = Gtk.Button(label="Save")
        self.btSalva.connect("clicked", self.Salva)

        self.liststore = Gtk.ListStore(str, str, float, float)
        self.treeview = Gtk.TreeView(model=self.liststore)

        # self.sel = self.treeview.get_selection()
        # self.sel.set_mode(Gtk.SelectionMode.NONE)

        self.amostra_text = Gtk.CellRendererText()
        self.column_amostra = Gtk.TreeViewColumn("Sample",
                                                 self.amostra_text, text=0)
        self.treeview.append_column(self.column_amostra)

        self.concentra_text = Gtk.CellRendererText()
        self.column_concentra = Gtk.TreeViewColumn("Concentration",
                                                   self.concentra_text, text=1)
        self.treeview.append_column(self.column_concentra)

        self.coef_text = Gtk.CellRendererText()
        self.column_coef = Gtk.TreeViewColumn("Quadratic Coef.",
                                              self.coef_text, text=2)
        self.treeview.append_column(self.column_coef)

        self.abs_text = Gtk.CellRendererText()
        self.column_abs = Gtk.TreeViewColumn("A (532)",
                                             self.abs_text, text=3)
        self.treeview.append_column(self.column_abs)

        self.bxchose = Gtk.HBox(spacing=6)
        self.boxgraph = Gtk.HBox(spacing=6)
        self.boxsubgraph = Gtk.VBox(spacing=6)
        self.boxV = Gtk.VBox(spacing=6)
        self.bxbutton = Gtk.HBox(spacing=6)
        self.bxTodos = Gtk.HBox(spacing=6)
        self.bxlist = Gtk.VBox(spacing=6)

        self.fg = plt.figure()
        self.ax = self.fg.add_subplot(111)

        self.ax.set_title('HRS Signal')
        self.ax.set_xlabel('$I(\omega)$')
        self.ax.set_ylabel('$I(2\omega)$')

        self.ax.ticklabel_format(style='sci', scilimits=(-2, 2), axis='both')

        self.cv1 = FigureCanvas(self.fg)
        # self.cursor = Cursor(self.ax, useblit=True, horizOn=True,
        #                      color='#ff9896', lw=1.5, alpha=0.9)

        self.fg2 = plt.figure()
        self.ax2 = self.fg2.add_subplot(111)
        self.ax2.set_title('HRS Signal Todas')
        self.ax2.set_xlabel('$I(\omega)$')
        self.ax2.set_ylabel('$I(2\omega)$')
        self.line2, = self.ax2.plot([], [], 'o')
        self.ax2.ticklabel_format(style='sci', scilimits=(-2, 2), axis='both')

        self.cv2 = FigureCanvas(self.fg2)

        self.fg4 = plt.figure()
        self.ax4 = self.fg4.add_subplot(111)
        self.ax4.set_title('Coef. Quadratico vs. Concentracao')
        self.line4, = self.ax4.plot([], [], 'ok')
        self.l4 = Line2D([], [], color='red', linewidth=1.5)
        self.ax4.add_line(self.l4)

        self.cv4 = FigureCanvas(self.fg4)

        self.bxbutton.pack_end(self.buttonOK, True, True, 0)
        self.bxbutton.pack_end(self.buttonQuit, True, True, 0)

        self.bxchose.pack_start(self.lbEsc, False, True, 0)
        self.bxchose.pack_start(self.filepath, True, True, 0)
        self.bxchose.pack_start(self.btBrowse, False, True, 0)
        self.bxchose.pack_start(self.btFile, False, True, 0)

        self.boxsubgraph.pack_start(self.cv2, True, True, 0)
        self.boxsubgraph.pack_start(self.cv4, True, True, 0)

        self.boxgraph.pack_start(self.cv1, True, True, 0)
        self.boxgraph.pack_start(self.boxsubgraph, True, True, 0)

        self.boxV.pack_start(self.bxchose, False, True, 0)
        self.boxV.pack_start(self.boxgraph, True, True, 0)

        self.bxlist.pack_start(self.btConcentra, False, True, 0)
        self.bxlist.pack_start(self.treeview, True, True, 0)
        self.bxlist.pack_start(self.bxbutton, False, False, 0)
        self.bxlist.pack_end(self.btSalva, False, True, 0)

        self.bxTodos.pack_start(self.boxV, True, True, 0)
        self.bxTodos.pack_start(self.bxlist, False, True, 5)
        self.add(self.bxTodos)

    def Parabola(self, x, a, b):
        return a*x**2 + b

    def Afin(self, x, a, b):
        return a*x + b

    def Slope(self, x, a):
        return a*x

    def proximo(self, event):
        self.ax2.errorbar(self.ref[:self.IM], self.sgn[:self.IM, 0],
                          yerr=self.sgn[:self.IM, 1], fmt='o')
        self.ax2.plot(self.x, self.y, 'r-', lw=2)
        self.fg2.canvas.draw()

        self.filepath.set_sensitive(True)
        self.lbEsc.set_sensitive(True)
        self.btBrowse.set_sensitive(True)
        self.btFile.set_sensitive(True)

        self.liststore[self.listline][2] = self.p[0]
        self.quad.append((
            float(self.liststore[self.listline][1]),
            self.liststore[self.listline][2],
            np.sqrt(self.pcov[0, 0])))

        self.listline += 1
        # self.treeview.set_cursor(self.listline)

    def quit(self, event):
        print('Exit')
        sys.exit()

    def removelast(self, event):
        self.quad.pop()
        self.listline -= 1
        self.liststore[self.listline][2] = 0.0

        self.filepath.set_sensitive(True)
        self.lbEsc.set_sensitive(True)
        self.btBrowse.set_sensitive(True)
        self.btFile.set_sensitive(True)

    def seleciona(self, event):
        if self.filepath.get_text() == "":
            self.alertempty()
        else:
            self.set_title(self.filepath.get_text())
            self.filepath.set_sensitive(False)
            self.lbEsc.set_sensitive(False)
            self.btBrowse.set_sensitive(False)
            self.btFile.set_sensitive(False)
            self.direc = self.filepath.get_text()
            self.ax.cla()
            self.plota()

    def EscolheAqv(self, event):
        dialog = Gtk.FileChooserDialog(
            "Selecione o arquivo", None, Gtk.FileChooserAction.OPEN, (
                Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
                Gtk.STOCK_OPEN, Gtk.ResponseType.OK))
        dialog.set_transient_for(self)

        filter_any = Gtk.FileFilter()
        filter_any.set_name("Signal files")
        filter_any.add_pattern("*s.dat")
        dialog.add_filter(filter_any)

        response = dialog.run()
        if response == Gtk.ResponseType.OK:
            self.filepath.set_text(dialog.get_filename())
        elif response == Gtk.ResponseType.CANCEL:
            print("Cancel clicked")

        dialog.destroy()

    def EscolheConc(self, event):
        dialog = Gtk.FileChooserDialog(
            "Select Concentration File", None, Gtk.FileChooserAction.OPEN, (
                Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
                Gtk.STOCK_OPEN, Gtk.ResponseType.OK))

        dialog.set_transient_for(self)
        response = dialog.run()

        if response == Gtk.ResponseType.OK:
            self.liststore.clear()
            self.btFile.set_sensitive(True)
            self.quad = []
            self.listline = 0

            self.conc = np.genfromtxt(dialog.get_filename(), dtype=None)
            # self.conc = self.conc[::-1]

        elif response == Gtk.ResponseType.CANCEL:
            print("Cancel clicked")

        # self.treeview.set_cursor(self.listline)
        self.concpath = dialog.get_current_folder()

        dialog.destroy()

        dialog2 = Gtk.FileChooserDialog(
            "Select Absorption File", None, Gtk.FileChooserAction.OPEN, (
                Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
                Gtk.STOCK_OPEN, Gtk.ResponseType.OK))

        dialog2.set_transient_for(self)
        dialog2.set_current_folder(self.concpath)
        response2 = dialog2.run()

        if response2 == Gtk.ResponseType.OK:
            self.Abs = np.genfromtxt(dialog2.get_filename(), dtype=float)
            # self.Abs = self.Abs[::-1]

        elif response2 == Gtk.ResponseType.CANCEL:
            print("Cancel clicked")

        dialog2.destroy()

        if len(self.conc) == len(self.Abs):
            for i in range(0, len(self.conc)):
                (self.smp, self.phi) = self.conc[i]
                self.A532 = self.Abs[i][1]

                self.liststore.append([str(self.smp),
                                       str(self.phi),
                                       0.0,
                                       self.A532])

        else:
            self.alertconcabs()

    def onselect(self, xmin, xmax):
        self.imin = np.searchsorted(self.ref[:self.IM], xmin)
        self.imax = np.searchsorted(self.ref[:self.IM], xmax)

        self.tempdata = []

        # try:
        self.p, self.pcov = curve_fit(
            self.Parabola,
            self.ref[self.imin:self.imax],
            self.sgn[self.imin:self.imax, 0])# ,
            # sigma=self.sgn[self.imin:self.imax, 1],
            # absolute_sigma=True)

        self.x = np.arange(0, 1.05*max(self.ref), max(self.ref)/11.0)
        self.y = self.Parabola(self.x, *self.p)

        self.line.set_data(self.x, self.y)
        self.fg.canvas.draw()

        self.line4.set_data([], [])
        self.l4.set_data([], [])

        self.fg4.canvas.draw()

        for linha in self.quad:
            self.tempdata.append(linha)

        self.tempdata.append((
            float(self.liststore[self.listline][1]),
            self.p[0],
            np.sqrt(self.pcov[0, 0])))
        self.tempdata = np.array(self.tempdata)

        print(self.tempdata)

        self.lim4 = max(self.tempdata[:, 0])*1.1
        self.x4 = np.arange(0, self.lim4, self.lim4/15)
        self.p4, self.pcov4 = curve_fit(
            self.Slope,
            self.tempdata[:, 0],
            self.tempdata[:, 1])

        self.y4 = self.Slope(self.x4, *self.p4)

        self.l4.set_data(self.x4, self.y4)
        self.line4.set_data(self.tempdata[:, 0], self.tempdata[:, 1])

        self.ax4.relim()  # recompute the ax.dataLim
        self.ax4.autoscale_view()  # update ax4 lim

        self.fg4.canvas.draw()

        # except:
        #     print('intervalo')

    def CalculaMediaMaximo(self, signal):

        sinal = np.zeros(30)

        for array in signal.T:
            Idx = np.where(array == max(array))[0]
            Idx = Idx[int(len(Idx)/2.)]# + 1

            sobe = array[:Idx][::-1]
            sinal = np.column_stack((sinal, sobe[:30]))
            # plt.plot(sinal)

        sinal = sinal[:, 1:]
        sinal = np.column_stack((
            np.average(sinal, axis = 1),
            np.std(sinal, axis = 1)/np.sqrt(10)))

        return sinal[::-1]

    def plota(self):
        print('Analising sample: %s' % self.filepath.get_text())

        self.ax.cla()
        self.ax.set_title('HRS Signal')
        self.ax.set_xlabel('$I(\omega)$')
        self.ax.set_ylabel('$I(2\omega)$')

        self.ax.ticklabel_format(style='sci', scilimits=(-2, 2), axis='both')

        self.span = SpanSelector(self.ax, self.onselect, 'horizontal',
                                 useblit=False, rectprops=dict(
                                     alpha=0.7, facecolor='#aec7e8'))

        self.Imps = np.genfromtxt(self.filepath.get_text(), skip_footer=21)
        self.Impr = np.genfromtxt(self.filepath.get_text()[:-5] + 'r.dat',
                                  skip_footer=22)

        self.ref_temp = np.average(self.Impr, axis=1)
        self.sgn_temp = np.column_stack((
            np.average(self.Imps, axis=1),
            np.std(self.Imps, axis=1, ddof=1)))

        self.medref = np.average(self.ref_temp[2:8])
        self.medsgn = np.average(self.sgn_temp[2:8, 0])

        self.IM = np.where(self.ref_temp == max(self.ref_temp))[0][0]

        # self.sgn = self.sgn_temp[:self.IM, :] - self.medsgn
        # self.ref = self.ref_temp[:self.IM] - self.medref
        self.sgn = self.sgn_temp[self.IM:, :][::-1] - self.medsgn
        self.ref = self.ref_temp[self.IM:][::-1] - self.medref

        self.sgn[:, 0] = (2*self.sgn[:, 0])/(10**(-self.A532*0.5) + 10**(-self.A532*1.5))

        # self.sgn = self.CalculaMediaMaximo(self.Imps)
        # self.referencia = self.CalculaMediaMaximo(self.Impr)
        # self.ref = self.referencia[:, 0]
        self.IM = -1

        self.ax.errorbar(self.ref[:self.IM], self.sgn[:self.IM, 0],
                         yerr=self.sgn[:self.IM, 1], fmt='ok-')

        self.line, = self.ax.plot(self.ref[:self.IM],
                                  self.sgn[:self.IM, 0], 'r-', lw=2,
                                  zorder=9)
        self.line.set_data([], [])

        self.fg.canvas.draw()

    def plotavarios(self):
        self.files = [file for file in sorted(os.listdir(
            self.filepath.get_text())) if file.endswith('s.dat')]

        for aqv in self.files:
            print(aqv)
            dados = np.genfromtxt(self.filepath.get_text() +
                                  '/' + aqv)

            self.line, = self.ax.plot(dados)
            self.ax.draw()
            # print(self.files)

    def alertempty(self):
        dialog = Gtk.MessageDialog(self, 0, Gtk.MessageType.INFO,
                                   Gtk.ButtonsType.OK, "Empy filepath")
        dialog.format_secondary_text(
            "Please select a file to analyse")
        dialog.run()

        dialog.destroy()

    def alertconc(self):
        dialog = Gtk.MessageDialog(self, 0, Gtk.MessageType.INFO,
                                   Gtk.ButtonsType.OK,
                                   "Unable to import file")
        dialog.format_secondary_text(
            "Please check if the concentration file has columns: (sample, concentration) and absorbption file (sample, A532nm)")
        dialog.run()

        dialog.destroy()

    def alertconcabs(self):
        dialog = Gtk.MessageDialog(self, 0, Gtk.MessageType.INFO,
                                   Gtk.ButtonsType.OK,
                                   "Unable to import files")
        dialog.format_secondary_text(
            "Please check if concentration and absorption files have the same number of rows")
        dialog.run()

        dialog.destroy()

    def Salva(self, event):

        self.filename = string.split(self.filepath.get_text(), '/')[-1]
        self.samplename = string.split(self.filename, '_')[0]

        dialog = Gtk.FileChooserDialog(
            "Save file", None, Gtk.FileChooserAction.SAVE, (
                Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
                Gtk.STOCK_SAVE, Gtk.ResponseType.OK))

        dialog.set_transient_for(self)
        dialog.set_current_name(self.samplename + '.HRS')
        dialog.set_do_overwrite_confirmation(True)

        response = dialog.run()
        if response == Gtk.ResponseType.OK:
            self.path = dialog.get_filename()
            print('Saving file: ' + self.path)
            self.salva = np.array(self.quad)
            np.savetxt(self.path, self.salva, delimiter='\t')
            print('Done')
        elif response == Gtk.ResponseType.CANCEL:
            print("Cancel clicked")

        dialog.destroy()

win = MyWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()


code:
**Play Minetest Server's Repository** This is the repository for the [Play Minetest](https://playminetest.com) server.

In order to contribute ideas or requests for changes, please create a [New Issue](https://notabug.org/PlayMinetest/PlayMinetestServer/issues/new) in the [issue tracker](https://notabug.org/PlayMinetest/PlayMinetestServer/issues). If you can make changes directly, please feel free to fork this repo, commit your improvements with comments, and submit a detailed Pull Request **that was ALREADY tested on a local multiplayer server**. For the additions or changes you would like to propose to us. This is ensure we are able to push your changes as quickly as possible.

**This was created** in order to share the contents, allow people to recommend additions/make changes to the server in order for better game play/functioning.

repo_name: Desour/PlayMinetestServer


code:
# Minetest Game

The default game bundled in the Minetest engine.

For further information, check
[this forum topic](https://forum.minetest.net/viewtopic.php?f=15&t=9724).
Also see the [Minetest Wiki](https://wiki.minetest.net/Subgames/Minetest_Game)
for more information.

## Installation

- Unzip the archive, rename the folder to minetest_game and
place it in .. minetest/games/

- GNU/Linux: If you use a system-wide installation place
    it in ~/.minetest/games/.

The Minetest engine can be found at [GitHub](https://github.com/minetest/minetest).

For further information or help, see:
https://wiki.minetest.net/Installing_Mods

## Compatibility

The Minetest Game GitHub master HEAD is generally compatible with the GitHub
master HEAD of the Minetest engine.
Additionally, when the Minetest engine is tagged to be a certain version (e.g.
0.4.10), Minetest Game is tagged with the version too.

When stable releases are made, Minetest Game and the Minetest engine is packaged
and made available at [www.minetest.net](https://www.minetest.net/downloads/).

## Licensing

See `LICENSE.txt`