code:
/* MegaZeux
 *
 * Copyright (C) 1996 Greg Janson
 * Copyright (C) 1999 Charles Goetzman
 *
 * 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 __COUNTER_H
#define __COUNTER_H

#include "compat.h"

__M_BEGIN_DECLS

#include <stdio.h>

#include "world_struct.h"
#include "counter_struct.h"

CORE_LIBSPEC int match_function_counter(const char *dest, const char *src);
CORE_LIBSPEC void set_counter(struct world *mzx_world, const char *name,
 int value, int id);
CORE_LIBSPEC void set_string(struct world *mzx_world, const char *name,
 struct string *src, int id);
CORE_LIBSPEC void counter_fsg(void);

void initialize_gateway_functions(struct world *mzx_world);
int get_counter(struct world *mzx_world, const char *name, int id);
void inc_counter(struct world *mzx_world, const char *name, int value, int id);
void dec_counter(struct world *mzx_world, const char *name, int value, int id);
void mul_counter(struct world *mzx_world, const char *name, int value, int id);
void div_counter(struct world *mzx_world, const char *name, int value, int id);
void mod_counter(struct world *mzx_world, const char *name, int value, int id);

int get_string(struct world *mzx_world, const char *name, struct string *dest,
 int id);
void inc_string(struct world *mzx_world, const char *name, struct string *src,
 int id);
void dec_string_int(struct world *mzx_world, const char *name, int value,
 int id);
int compare_strings(struct string *dest, struct string *src);

void load_string_board(struct world *mzx_world, const char *expression,
 int w, int h, char l, char *src, int width);
int set_counter_special(struct world *mzx_world, char *char_value,
 int value, int id);
bool is_string(char *buffer);

struct counter *load_counter(FILE *fp);
struct string *load_string(FILE *fp);
void save_counter(FILE *fp, struct counter *src_counter);
void save_string(FILE *fp, struct string *src_string);

// Even old games tended to use at least this many.
#define MIN_COUNTER_ALLOCATE 32

// These take up more room...
#define MIN_STRING_ALLOCATE 4

// Strings cannot be longer than 1M
#define MAX_STRING_LEN (1 << 20)

// Maximum space board can consume
#define MAX_BOARD_SIZE 16 * 1024 * 1024

__M_END_DECLS

#endif // __COUNTER_H

repo_name: pgimeno/megazeux

license: mit


code:
/* MegaZeux
 *
 * Copyright (C) 1996 Greg Janson
 * Copyright (C) 1999 Charles Goetzman
 *
 * 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 __COUNTER_STRUCT_H
#define __COUNTER_STRUCT_H

#include "compat.h"

__M_BEGIN_DECLS

struct world;
struct counter;

typedef int (*gateway_write_function)(struct world *mzx_world,
 struct counter *counter, const char *name, int value, int id);

typedef int (*gateway_dec_function)(struct world *mzx_world,
 struct counter *counter, const char *name, int value, int id);

struct counter
{
  int value;
  gateway_write_function gateway_write;
  gateway_dec_function gateway_dec;
  char name[1];
};

// TODO - Give strings a dynamic length. It would expand
// set ends up being larger than the current size.

// "storage_space" is just there for show.. the truth is,
// name and storage share space. It's messy, but fast and
// space efficient.

// storage_space doesn't actually have to have anything,
// however (in fact, neither does name). Strings can
// be used as pointers to hold intermediate or immediate
// values. For instance, string literals and spliced
// strings. Anyone who uses strings in this way has a few
// responsibilities, however:
// The string must be properly initialized so length and
// value are set (allocated_length need not be set)
// The actual string list must not contain any of these
// kinds of temporary strings.
// Any deallocation (of value?) must be done by the
// initializer.
// get_string returns temporary strings like this (for
// speed and memory efficiency reasons), and the string
// mutating functions work on strings of this format as
// the second operand.

// In a normal (persistent string, initialized by
// add_string) string the struct will be over-initialized
// to contain room for both the name and the value; value
// will then point into the storage space somewhere. The
// name comes first and is a fixed size. The value comes
// after it and is of a dynamic length (allocated_length).
// Allocated_length will typically end up larger than
// length if the string's size is changed.

struct string
{
  size_t length;
  size_t allocated_length;
  char *value;

  char name[1];
  char storage_space[1];
};

// Special counter returns for opening files

enum special_counter_return
{
  FOPEN_NONE = 0,
  FOPEN_FREAD,
  FOPEN_FWRITE,
  FOPEN_FAPPEND,
  FOPEN_FMODIFY,
  FOPEN_SMZX_PALETTE,
  FOPEN_LOAD_GAME,
  FOPEN_SAVE_GAME,
  FOPEN_SAVE_WORLD,
  FOPEN_LOAD_ROBOT,
  FOPEN_LOAD_BC,
#ifndef CONFIG_DEBYTECODE
  FOPEN_SAVE_ROBOT,
  FOPEN_SAVE_BC
#endif
};

__M_END_DECLS

#endif // __COUNTER_STRUCT_H


code:
/* MegaZeux
 *
 * Copyright (C) 1996 Greg Janson
 * Copyright (C) 2004 B.D.A
 * 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
 */

// Translation of data.asm to C

#include "data.h"
#include "const.h"

// Some globals that still lurk.. should be moved to other places.

// Current MZX file information
char curr_file[MAX_PATH] = "CAVERNS.MZX";
char curr_sav[MAX_PATH] = "SAVED.SAV";
char current_dir[MAX_PATH];
char config_dir[MAX_PATH];

// Some global world values that haven't been removed yet.

unsigned char scroll_color = 15;

// Array of flags for things
const unsigned int flags[] =
{
  A_UNDER,                                                    // 0x00 Space
  0,                                                          // 0x01 Normal
  0,                                                          // 0x02 Solid
  0,                                                          // 0x03 Tree
  0,                                                          // 0x04 Line
  0,                                                          // 0x05 Customblock
  A_SHOOTABLE | A_BLOW_UP,                                    // 0x06 Breakaway
  A_SHOOTABLE | A_BLOW_UP,                                    // 0x07 Customblock
  A_PUSHABLE | A_BLOW_UP,                                     // 0x08 Boulder
  A_PUSHABLE | A_BLOW_UP,                                     // 0x09 Crate
  A_PUSHABLE | A_BLOW_UP,                                     // 0x0A Custompush
  A_PUSHABLE,                                                 // 0x0B Box
  A_PUSHABLE,                                                 // 0x0C Customsolidpush
  A_UNDER,                                                    // 0x0D Fake
  A_UNDER,                                                    // 0x0E Carpet
  A_UNDER,                                                    // 0x0F Floor
  A_UNDER,                                                    // 0x10 Tiles
  A_UNDER,                                                    // 0x11 Customfloor
  A_UNDER | A_BLOW_UP,                                        // 0x12 Web
  A_UNDER | A_BLOW_UP,                                        // 0x13 Thickweb
  A_UNDER,                                                    // 0x14 Stillwater
  A_UNDER | A_AFFECT_IF_STOOD,                                // 0x15 NWater
  A_UNDER | A_AFFECT_IF_STOOD,                                // 0x16 SWater
  A_UNDER | A_AFFECT_IF_STOOD,                                // 0x17 EWater
  A_UNDER | A_AFFECT_IF_STOOD,                                // 0x18 WWater
  A_UNDER | A_AFFECT_IF_STOOD | A_UPDATE,                     // 0x19 Ice
  A_UNDER | A_AFFECT_IF_STOOD | A_UPDATE,                     // 0x1A Lava
  A_ITEM | A_BLOW_UP,                                         // 0x1B Chest
  A_ITEM | A_PUSHABLE | A_BLOW_UP | A_SHOOTABLE,              // 0x1C Gem
  A_ITEM | A_PUSHABLE | A_BLOW_UP | A_SHOOTABLE,              // 0x1D Magicgem
  A_ITEM | A_PUSHABLE,                                        // 0x1E Health
  A_ITEM | A_PUSHABLE,                                        // 0x1F Ring
  A_ITEM | A_PUSHABLE,                                        // 0x20 Potion
  A_ITEM | A_PUSHABLE | A_UPDATE,                             // 0x21 Energizer
  A_UNDER | A_ITEM,                                           // 0x22 Goop
  A_ITEM | A_PUSHABLE,                                        // 0x23 Ammo
  A_ITEM | A_PUSHABLE | A_EXPLODE,                            // 0x24 Bomb
  A_PUSHABLE | A_EXPLODE | A_UPDATE,                          // 0x25 LitBomb
  A_HURTS | A_UPDATE,                                         // 0x26 Explosion
  A_ITEM | A_PUSHABLE,                                        // 0x27 Key
  A_ITEM,                                                     // 0x28 Lock
  A_ITEM,                                                     // 0x29 Door
  A_UPDATE,                                                   // 0x2A Opening/closing door
  A_ENTRANCE | A_UNDER,                                       // 0x2B Stairs
  A_ENTRANCE | A_UNDER,                                       // 0x2C Cave
  A_UPDATE,                                                   // 0x2D CW
  A_UPDATE,                                                   // 0x2E CCW
  A_ITEM,                                                     // 0x2F Gate
  A_UPDATE | A_UNDER,                                         // 0x30 OpenGate
  A_SPEC_PUSH | A_ITEM | A_UPDATE,                            // 0x31 Transport
  A_ITEM | A_PUSHABLE,                                        // 0x32 Coin
  A_UPDATE,                                                   // 0x33 MovingWall N
  A_UPDATE,                                                   // 0x34 MovingWall S
  A_UPDATE,                                                   // 0x35 MovingWall E
  A_UPDATE,                                                   // 0x36 MovingWall W
  A_ITEM | A_PUSHABLE | A_BLOW_UP,                            // 0x37 Pouch
  A_UPDATE,                                                   // 0x38 Pusher
  A_PUSHNS,                                                   // 0x39 SliderNS
  A_PUSHEW,                                                   // 0x3A SliderEW
  A_UPDATE | A_HURTS,                                         // 0x3B Lazer
  A_UPDATE,                                                   // 0x3C LazerWallShooter
  A_UPDATE | A_BLOW_UP | A_SHOOTABLE | A_ITEM |  A_ENEMY,     // 0x3D Bullet
  A_UPDATE | A_HURTS | A_EXPLODE,                             // 0x3E Missile
  A_UPDATE | A_UNDER | A_AFFECT_IF_STOOD,                     // 0x3F Fire
  0,                                                          // 0x40
  A_ITEM,                                                     // 0x41 Forest
  A_PUSHABLE | A_ITEM | A_UPDATE,                             // 0x42 Life
  A_UPDATE | A_UNDER | A_ENTRANCE,                            // 0x43 Whirlpool 1
  A_UPDATE | A_UNDER | A_ENTRANCE,                            // 0x44 Whirlpool 2
  A_UPDATE | A_UNDER | A_ENTRANCE,                            // 0x45 Whirlpool 3
  A_UPDATE | A_UNDER | A_ENTRANCE,                            // 0x46 Whirlpool 4
  A_ITEM,                                                     // 0x47 Invisible
  A_SPEC_SHOT,                                                // 0x48 RicochetPanel
  A_SPEC_SHOT,                                                // 0x49 Ricochet
  A_ITEM | A_SPEC_SHOT | A_SPEC_BOMB | A_UPDATE,              // 0x4A Mine
  A_HURTS,                                                    // 0x4B Spike
  A_HURTS,                                                    // 0x4C Customhurt
  0,                                                          // 0x4D Text
  A_UPDATE | A_ENEMY | A_BLOW_UP,                             // 0x4E ShootingFire
  A_UPDATE | A_ENEMY | A_BLOW_UP | A_PUSHABLE,                // 0x4F Seeker
  A_UPDATE | A_PUSHABLE | A_ENEMY | A_SHOOTABLE | A_BLOW_UP,  // 0x50 Snake
  A_UPDATE | A_EXPLODE | A_ITEM | A_SPEC_SHOT | A_PUSHABLE,   // 0x51 Eye
  A_UPDATE | A_BLOW_UP | A_PUSHABLE | A_ITEM | A_SHOOTABLE,   // 0x52 Thief
  A_UPDATE | A_ITEM | A_SPEC_BOMB | A_SPEC_SHOT,              // 0x53 SlimeBlob
  A_UPDATE | A_ENEMY | A_BLOW_UP | A_PUSHABLE | A_SPEC_SHOT,  // 0x54 Runner
  A_UPDATE | A_ITEM | A_PUSHABLE | A_SPEC_BOMB | A_SPEC_SHOT, // 0x55 Ghost
  A_UPDATE | A_SPEC_SHOT | A_SPEC_BOMB | A_ITEM,              // 0x56 Dragon
  A_UPDATE | A_ITEM | A_BLOW_UP | A_SPEC_SHOT | A_PUSHABLE,   // 0x57 Fish
  A_UPDATE | A_BLOW_UP | A_SHOOTABLE | A_ENEMY,               // 0x58 Shark
  A_UPDATE | A_ENEMY | A_BLOW_UP | A_SPEC_SHOT | A_PUSHABLE,  // 0x59 Spider
  A_UPDATE | A_ENEMY | A_SHOOTABLE | A_PUSHABLE | A_BLOW_UP,  // 0x5A Goblin (90)
  A_UPDATE | A_PUSHABLE | A_SHOOTABLE | A_ENEMY | A_BLOW_UP,  // 0x5B Tiger
  A_UPDATE,                                                   // 0x5C BulletGun
  A_UPDATE,                                                   // 0x5D SpinningGun
  A_UPDATE | A_ENEMY | A_SPEC_SHOT | A_PUSHABLE | A_BLOW_UP,  // 0x5E Bear
  A_UPDATE | A_BLOW_UP | A_ENEMY | A_SHOOTABLE | A_PUSHABLE,  // 0x5F BearCub
  0,                                                          // 0x60 '?'
  A_UPDATE,                                                   // 0x61 MissileGun
  0,                                                          // 0x62 98
  0,                                                          // 0x63 99
  0,                                                          // 0x64 100
  0,                                                          // 0x65 101
  0,                                                          // 0x66 102
  0,                                                          // 0x67 103
  0,                                                          // 0x68 104
  0,                                                          // 0x69 105
  0,                                                          // 0x6A 106
  0,                                                          // 0x6B 107
  0,                                                          // 0x6C 108
  0,                                                          // 0x6D 109
  0,                                                          // 0x6E 110
  0,                                                          // 0x6F 111
  0,                                                          // 0x70 112
  0,                                                          // 0x71 113
  0,                                                          // 0x72 114
  0,                                                          // 0x73 115
  0,                                                          // 0x74 116
  0,                                                          // 0x75 117
  0,                                                          // 0x76 118
  0,                                                          // 0x77 119
  0,                                                          // 0x78 120
  0,                                                          // 0x79 x0C 121
  A_SPEC_STOOD | A_SPEC_PUSH,                                 // 0x7A x0D Sensor
  A_ITEM | A_UPDATE | A_SPEC_SHOT | A_SPEC_BOMB | A_SPEC_PUSH,// 0x7B x0E Robot (pushable)
  A_ITEM | A_UPDATE | A_SPEC_SHOT | A_SPEC_BOMB,              // 0x7C x0F Robot
  A_ITEM,                                                     // 0x7D x00 Sign
  A_ITEM | A_PUSHABLE,                                        // 0x7E x01 Scroll
  A_SPEC_SHOT | A_SPEC_PUSH | A_SPEC_BOMB                     // 0x7F x02 Player
};

//Names for all things
const char *const thing_names[128] =
{
  "Space",
  "Normal",
  "Solid",
  "Tree",
  "Line",
  "CustomBlock",
  "Breakaway",
  "CustomBreak",
  "Boulder",
  "Crate",
  "CustomPush",
  "Box",
  "CustomBox",
  "Fake",
  "Carpet",
  "Floor",
  "Tiles",
  "CustomFloor",
  "Web",
  "ThickWeb",
  "StillWater",
  "NWater",
  "SWater",
  "EWater",
  "WWater",
  "Ice",
  "Lava",
  "Chest",
  "Gem",
  "MagicGem",
  "Health",
  "Ring",
  "Potion",
  "Energizer",
  "Goop",
  "Ammo",
  "Bomb",
  "LitBomb",
  "Explosion",
  "Key",
  "Lock",
  "Door",
  "OpenDoor",
  "Stairs",
  "Cave",
  "CWRotate",
  "CCWRotate",
  "Gate",
  "OpenGate",
  "Transport",
  "Coin",
  "NMovingWall",
  "SMovingWall",
  "EMovingWall",
  "WMovingWall",
  "Pouch",
  "Pusher",
  "SliderNS",
  "SliderEW",
  "Lazer",
  "LazerGun",
  "Bullet",
  "Missile",
  "Fire",
  "[unknown]",
  "Forest",
  "Life",
  "Whirlpool",
  "Whirlpool2",
  "Whirlpool3",
  "Whirlpool4",
  "InvisWall",
  "RicochetPanel",
  "Ricochet",
  "Mine",
  "Spike",
  "CustomHurt",
  "Text",
  "ShootingFire",
  "Seeker",
  "Snake",
  "Eye",
  "Thief",
  "Slimeblob",
  "Runner",
  "Ghost",
  "Dragon",
  "Fish",
  "Shark",
  "Spider",
  "Goblin",
  "SpittingTiger",
  "BulletGun",
  "SpinningGun",
  "Bear",
  "BearCub",
  "[unknown]",
  "MissileGun",
  "Sprite",
  "Sprite_colliding",
  "Image_file",
  "__unused",
  "__unused",
  "__unused",
  "__unused",
  "__unused",
  "__unused",
  "__unused",
  "__unused",
  "__unused",
  "__unused",
  "__unused",
  "__unused",
  "__unused",
  "__unused",
  "__unused",
  "__unused",
  "__unused",
  "__unused",
  "__unused",
  "__unused",
  "__unused",
  "Sensor",
  "PushableRobot",
  "Robot",
  "Sign",
  "Scroll",
  "Player"
};


code:
/* MegaZeux
 *
 * Copyright (C) 1996 Greg Janson
 *
 * 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 __DATA_H
#define __DATA_H

#include "compat.h"

__M_BEGIN_DECLS

#include "const.h"
#include <stdio.h>
#include <stdlib.h>

CORE_LIBSPEC extern char curr_file[MAX_PATH];
CORE_LIBSPEC extern char curr_sav[MAX_PATH];
CORE_LIBSPEC extern char current_dir[MAX_PATH];
CORE_LIBSPEC extern char config_dir[MAX_PATH];

CORE_LIBSPEC extern unsigned char scroll_color;
CORE_LIBSPEC extern const char *const thing_names[128];
CORE_LIBSPEC extern const unsigned int flags[128];

enum thing
{
  SPACE           = 0,
  NORMAL          = 1,
  SOLID           = 2,
  TREE            = 3,
  LINE            = 4,
  CUSTOM_BLOCK    = 5,
  BREAKAWAY       = 6,
  CUSTOM_BREAK    = 7,
  BOULDER         = 8,
  CRATE           = 9,
  CUSTOM_PUSH     = 10,
  BOX             = 11,
  CUSTOM_BOX      = 12,
  FAKE            = 13,
  CARPET          = 14,
  FLOOR           = 15,
  TILES           = 16,
  CUSTOM_FLOOR    = 17,
  WEB             = 18,
  THICK_WEB       = 19,
  STILL_WATER     = 20,
  N_WATER         = 21,
  S_WATER         = 22,
  E_WATER         = 23,
  W_WATER         = 24,
  ICE             = 25,
  LAVA            = 26,
  CHEST           = 27,
  GEM             = 28,
  MAGIC_GEM       = 29,
  HEALTH          = 30,
  RING            = 31,
  POTION          = 32,
  ENERGIZER       = 33,
  GOOP            = 34,
  AMMO            = 35,
  BOMB            = 36,
  LIT_BOMB        = 37,
  EXPLOSION       = 38,
  KEY             = 39,
  LOCK            = 40,
  DOOR            = 41,
  OPEN_DOOR       = 42,
  STAIRS          = 43,
  CAVE            = 44,
  CW_ROTATE       = 45,
  CCW_ROTATE      = 46,
  GATE            = 47,
  OPEN_GATE       = 48,
  TRANSPORT       = 49,
  COIN            = 50,
  N_MOVING_WALL   = 51,
  S_MOVING_WALL   = 52,
  E_MOVING_WALL   = 53,
  W_MOVING_WALL   = 54,
  POUCH           = 55,
  PUSHER          = 56,
  SLIDER_NS       = 57,
  SLIDER_EW       = 58,
  LAZER           = 59,
  LAZER_GUN       = 60,
  BULLET          = 61,
  MISSILE         = 62,
  FIRE            = 63,
  FOREST          = 65,
  LIFE            = 66,
  WHIRLPOOL_1     = 67,
  WHIRLPOOL_2     = 68,
  WHIRLPOOL_3     = 69,
  WHIRLPOOL_4     = 70,
  INVIS_WALL      = 71,
  RICOCHET_PANEL  = 72,
  RICOCHET        = 73,
  MINE            = 74,
  SPIKE           = 75,
  CUSTOM_HURT     = 76,
  __TEXT          = 77,
  SHOOTING_FIRE   = 78,
  SEEKER          = 79,
  SNAKE           = 80,
  EYE             = 81,
  THIEF           = 82,
  SLIMEBLOB       = 83,
  RUNNER          = 84,
  GHOST           = 85,
  DRAGON          = 86,
  FISH            = 87,
  SHARK           = 88,
  SPIDER          = 89,
  GOBLIN          = 90,
  SPITTING_TIGER  = 91,
  BULLET_GUN      = 92,
  SPINNING_GUN    = 93,
  BEAR            = 94,
  BEAR_CUB        = 95,
  MISSILE_GUN     = 97,
  SPRITE          = 98,
  SPR_COLLISION   = 99,
  IMAGE_FILE      = 100,
  SENSOR          = 122,
  ROBOT_PUSHABLE  = 123,
  ROBOT           = 124,
  SIGN            = 125,
  SCROLL          = 126,
  PLAYER          = 127,
  NO_ID           = 255
};

static inline bool is_fake(enum thing id)
{
  return (id == SPACE) || ((id >= FAKE) && (id <= THICK_WEB));
}

static inline bool is_robot(enum thing id)
{
  return (id == ROBOT) || (id == ROBOT_PUSHABLE);
}

static inline bool is_signscroll(enum thing id)
{
  return (id == SIGN) || (id == SCROLL);
}

static inline bool is_water(enum thing id)
{
  return (id >= STILL_WATER) && (id <= W_WATER);
}

static inline bool is_whirlpool(enum thing id)
{
  return (id >= WHIRLPOOL_1) && (id <= WHIRLPOOL_4);
}

static inline bool is_enemy(enum thing id)
{
  return (id >= SNAKE) && (id <= BEAR_CUB) &&
   (id != BULLET_GUN) && (id != SPINNING_GUN);
}

static inline bool is_storageless(enum thing id)
{
  return id < SENSOR;
}

enum dir
{
  IDLE    = 0,
  NORTH   = 1,
  SOUTH   = 2,
  EAST    = 3,
  WEST    = 4,
  RANDNS  = 5,
  RANDEW  = 6,
  RANDNE  = 7,
  RANDNB  = 8,
  SEEK    = 9,
  RANDANY = 10,
  BENEATH = 11,
  ANYDIR  = 12,
  FLOW    = 13,
  NODIR   = 14,
  RANDB   = 15,
  RANDP   = 16,
  CW      = 32,
  OPP     = 64,
  RANDNOT = 128
};

static inline bool is_cardinal_dir(enum dir d)
{
  return (d >= NORTH) && (d <= WEST);
}

static inline int dir_to_int(enum dir d)
{
  return (int)d - 1;
}

static inline enum dir int_to_dir(int d)
{
  return (enum dir)(d + 1);
}

#define CAN_PUSH      (1 << 0)
#define CAN_TRANSPORT (1 << 1)
#define CAN_LAVAWALK  (1 << 2)
#define CAN_FIREWALK  (1 << 3)
#define CAN_WATERWALK (1 << 4)
#define MUST_WEB      (1 << 5)
#define MUST_THICKWEB (1 << 6)
#define REACT_PLAYER  (1 << 7)
#define MUST_WATER    (1 << 8)
#define MUST_LAVAGOOP (1 << 9)
#define CAN_GOOPWALK  (1 << 10)
#define SPITFIRE      (1 << 11)

enum move_status
{
  NO_HIT      = 0,
  HIT         = 1,
  HIT_PLAYER  = 2,
  HIT_EDGE    = 3
};

enum equality
{
  EQUAL                 = 0,
  LESS_THAN             = 1,
  GREATER_THAN          = 2,
  GREATER_THAN_OR_EQUAL = 3,
  LESS_THAN_OR_EQUAL    = 4,
  NOT_EQUAL             = 5
};

enum condition
{
  WALKING               = 0,
  SWIMMING              = 1,
  FIRE_WALKING          = 2,
  TOUCHING              = 3,
  BLOCKED               = 4,
  ALIGNED               = 5,
  ALIGNED_NS            = 6,
  ALIGNED_EW            = 7,
  LASTSHOT              = 8,
  LASTTOUCH             = 9,
  RIGHTPRESSED          = 10,
  LEFTPRESSED           = 11,
  UPPRESSED             = 12,
  DOWNPRESSED           = 13,
  SPACEPRESSED          = 14,
  DELPRESSED            = 15,
  MUSICON               = 16,
  SOUNDON               = 17
};

enum chest_contents
{
  ITEM_KEY              = 1,
  ITEM_COINS            = 2,
  ITEM_LIFE             = 3,
  ITEM_AMMO             = 4,
  ITEM_GEMS             = 5,
  ITEM_HEALTH           = 6,
  ITEM_POTION           = 7,
  ITEM_RING             = 8,
  ITEM_LOBOMBS          = 9,
  ITEM_HIBOMBS          = 10
};

enum give_item
{
  GIVE_GEMS             = 0,
  GIVE_AMMO             = 1,
  GIVE_TIME             = 2,
  GIVE_SCORE            = 3,
  GIVE_HEALTH           = 4,
  GIVE_LIVES            = 5,
  GIVE_LOBOMBS          = 6,
  GIVE_HIBOMBS          = 7,
  GIVE_COINS            = 8
};

enum potion
{
  POTION_DUD            = 0,
  POTION_INVINCO        = 1,
  POTION_BLAST          = 2,
  POTION_SMALL_HEALTH   = 3,
  POTION_BIG_HEALTH     = 4,
  POTION_POISON         = 5,
  POTION_BLIND          = 6,
  POTION_KILL           = 7,
  POTION_FIREWALK       = 8,
  POTION_DETONATE       = 9,
  POTION_BANISH         = 10,
  POTION_SUMMON         = 11,
  POTION_AVALANCHE      = 12,
  POTION_FREEZE         = 13,
  POTION_WIND           = 14,
  POTION_SLOW           = 15
};

enum board_target
{
  TARGET_NONE           = 0,
  TARGET_POSITION       = 1,
  TARGET_ENTRANCE       = 2,
  TARGET_TELEPORT       = 3
};

enum robot_command_name
{
  ROBOTIC_CMD_END                                       = 0,
  ROBOTIC_CMD_DIE                                       = 1,
  ROBOTIC_CMD_WAIT                                      = 2,
  ROBOTIC_CMD_CYCLE                                     = 3,
  ROBOTIC_CMD_GO                                        = 4,
  ROBOTIC_CMD_WALK                                      = 5,
  ROBOTIC_CMD_BECOME                                    = 6,
  ROBOTIC_CMD_CHAR                                      = 7,
  ROBOTIC_CMD_COLOR                                     = 8,
  ROBOTIC_CMD_GOTOXY                                    = 9,
  ROBOTIC_CMD_SET                                       = 10,
  ROBOTIC_CMD_INC                                       = 11,
  ROBOTIC_CMD_DEC                                       = 12,
  ROBOTIC_CMD_UNUSED_13                                 = 13,
  ROBOTIC_CMD_UNUSED_14                                 = 14,
  ROBOTIC_CMD_UNUSED_15                                 = 15,
  ROBOTIC_CMD_IF                                        = 16,
  ROBOTIC_CMD_UNUSED_17                                 = 17,
  ROBOTIC_CMD_IF_CONDITION                              = 18,
  ROBOTIC_CMD_IF_NOT_CONDITION                          = 19,
  ROBOTIC_CMD_IF_ANY                                    = 20,
  ROBOTIC_CMD_IF_NO                                     = 21,
  ROBOTIC_CMD_IF_THING_DIR                              = 22,
  ROBOTIC_CMD_IF_NOT_THING_DIR                          = 23,
  ROBOTIC_CMD_IF_THING_XY                               = 24,
  ROBOTIC_CMD_IF_AT                                     = 25,
  ROBOTIC_CMD_IF_DIR_OF_PLAYER                          = 26,
  ROBOTIC_CMD_DOUBLE                                    = 27,
  ROBOTIC_CMD_HALF                                      = 28,
  ROBOTIC_CMD_GOTO                                      = 29,
  ROBOTIC_CMD_SEND                                      = 30,
  ROBOTIC_CMD_EXPLODE                                   = 31,
  ROBOTIC_CMD_PUT_DIR                                   = 32,
  ROBOTIC_CMD_GIVE                                      = 33,
  ROBOTIC_CMD_TAKE                                      = 34,
  ROBOTIC_CMD_TAKE_OR                                   = 35,
  ROBOTIC_CMD_ENDGAME                                   = 36,
  ROBOTIC_CMD_ENDLIFE                                   = 37,
  ROBOTIC_CMD_MOD                                       = 38,
  ROBOTIC_CMD_SAM                                       = 39,
  ROBOTIC_CMD_VOLUME                                    = 40,
  ROBOTIC_CMD_END_MOD                                   = 41,
  ROBOTIC_CMD_END_SAM                                   = 42,
  ROBOTIC_CMD_PLAY                                      = 43,
  ROBOTIC_CMD_END_PLAY                                  = 44,
  ROBOTIC_CMD_WAIT_THEN_PLAY                            = 45,
  ROBOTIC_CMD_WAIT_PLAY                                 = 46,
  ROBOTIC_CMD_BLANK_LINE                                = 47,
  ROBOTIC_CMD_SFX                                       = 48,
  ROBOTIC_CMD_PLAY_IF_SILENT                            = 49,
  ROBOTIC_CMD_OPEN                                      = 50,
  ROBOTIC_CMD_LOCKSELF                                  = 51,
  ROBOTIC_CMD_UNLOCKSELF                                = 52,
  ROBOTIC_CMD_SEND_DIR                                  = 53,
  ROBOTIC_CMD_ZAP                                       = 54,
  ROBOTIC_CMD_RESTORE                                   = 55,
  ROBOTIC_CMD_LOCKPLAYER                                = 56,
  ROBOTIC_CMD_UNLOCKPLAYER                              = 57,
  ROBOTIC_CMD_LOCKPLAYER_NS                             = 58,
  ROBOTIC_CMD_LOCKPLAYER_EW                             = 59,
  ROBOTIC_CMD_LOCKPLAYER_ATTACK                         = 60,
  ROBOTIC_CMD_MOVE_PLAYER_DIR                           = 61,
  ROBOTIC_CMD_MOVE_PLAYER_DIR_OR                        = 62,
  ROBOTIC_CMD_PUT_PLAYER_XY                             = 63,
  ROBOTIC_CMD_OBSOLETE_IF_PLAYER_DIR                    = 64,
  ROBOTIC_CMD_OBSOLETE_IF_NOT_PLAYER_DIR                = 65,
  ROBOTIC_CMD_IF_PLAYER_XY                              = 66,
  ROBOTIC_CMD_PUT_PLAYER_DIR                            = 67,
  ROBOTIC_CMD_TRY_DIR                                   = 68,
  ROBOTIC_CMD_ROTATECW                                  = 69,
  ROBOTIC_CMD_ROTATECCW                                 = 70,
  ROBOTIC_CMD_SWITCH                                    = 71,
  ROBOTIC_CMD_SHOOT                                     = 72,
  ROBOTIC_CMD_LAYBOMB                                   = 73,
  ROBOTIC_CMD_LAYBOMB_HIGH                              = 74,
  ROBOTIC_CMD_SHOOTMISSILE                              = 75,
  ROBOTIC_CMD_SHOOTSEEKER                               = 76,
  ROBOTIC_CMD_SPITFIRE                                  = 77,
  ROBOTIC_CMD_LAZERWALL                                 = 78,
  ROBOTIC_CMD_PUT_XY                                    = 79,
  ROBOTIC_CMD_DIE_ITEM                                  = 80,
  ROBOTIC_CMD_SEND_XY                                   = 81,
  ROBOTIC_CMD_COPYROBOT_NAMED                           = 82,
  ROBOTIC_CMD_COPYROBOT_XY                              = 83,
  ROBOTIC_CMD_COPYROBOT_DIR                             = 84,
  ROBOTIC_CMD_DUPLICATE_SELF_DIR                        = 85,
  ROBOTIC_CMD_DUPLICATE_SELF_XY                         = 86,
  ROBOTIC_CMD_BULLETN                                   = 87,
  ROBOTIC_CMD_BULLETS                                   = 88,
  ROBOTIC_CMD_BULLETE                                   = 89,
  ROBOTIC_CMD_BULLETW                                   = 90,
  ROBOTIC_CMD_GIVEKEY                                   = 91,
  ROBOTIC_CMD_GIVEKEY_OR                                = 92,
  ROBOTIC_CMD_TAKEKEY                                   = 93,
  ROBOTIC_CMD_TAKEKEY_OR                                = 94,
  ROBOTIC_CMD_INC_RANDOM                                = 95,
  ROBOTIC_CMD_DEC_RANDOM                                = 96,
  ROBOTIC_CMD_SET_RANDOM                                = 97,
  ROBOTIC_CMD_TRADE                                     = 98,
  ROBOTIC_CMD_SEND_DIR_PLAYER                           = 99,
  ROBOTIC_CMD_PUT_DIR_PLAYER                            = 100,
  ROBOTIC_CMD_SLASH                                     = 101,
  ROBOTIC_CMD_MESSAGE_LINE                              = 102,
  ROBOTIC_CMD_MESSAGE_BOX_LINE                          = 103,
  ROBOTIC_CMD_MESSAGE_BOX_OPTION                        = 104,
  ROBOTIC_CMD_MESSAGE_BOX_MAYBE_OPTION                  = 105,
  ROBOTIC_CMD_LABEL                                     = 106,
  ROBOTIC_CMD_COMMENT                                   = 107,
  ROBOTIC_CMD_ZAPPED_LABEL                              = 108,
  ROBOTIC_CMD_TELEPORT                                  = 109,
  ROBOTIC_CMD_SCROLLVIEW                                = 110,
  ROBOTIC_CMD_INPUT                                     = 111,
  ROBOTIC_CMD_IF_INPUT                                  = 112,
  ROBOTIC_CMD_IF_INPUT_NOT                              = 113,
  ROBOTIC_CMD_IF_INPUT_MATCHES                          = 114,
  ROBOTIC_CMD_PLAYER_CHAR                               = 115,
  ROBOTIC_CMD_MESSAGE_BOX_COLOR_LINE                    = 116,
  ROBOTIC_CMD_MESSAGE_BOX_CENTER_LINE                   = 117,
  ROBOTIC_CMD_MOVE_ALL                                  = 118,
  ROBOTIC_CMD_COPY                                      = 119,
  ROBOTIC_CMD_SET_EDGE_COLOR                            = 120,
  ROBOTIC_CMD_BOARD                                     = 121,
  ROBOTIC_CMD_BOARD_IS_NONE                             = 122,
  ROBOTIC_CMD_CHAR_EDIT                                 = 123,
  ROBOTIC_CMD_BECOME_PUSHABLE                           = 124,
  ROBOTIC_CMD_BECOME_NONPUSHABLE                        = 125,
  ROBOTIC_CMD_BLIND                                     = 126,
  ROBOTIC_CMD_FIREWALKER                                = 127,
  ROBOTIC_CMD_FREEZETIME                                = 128,
  ROBOTIC_CMD_SLOWTIME                                  = 129,
  ROBOTIC_CMD_WIND                                      = 130,
  ROBOTIC_CMD_AVALANCHE                                 = 131,
  ROBOTIC_CMD_COPY_DIR                                  = 132,
  ROBOTIC_CMD_BECOME_LAVAWALKER                         = 133,
  ROBOTIC_CMD_BECOME_NONLAVAWALKER                      = 134,
  ROBOTIC_CMD_CHANGE                                    = 135,
  ROBOTIC_CMD_PLAYERCOLOR                               = 136,
  ROBOTIC_CMD_BULLETCOLOR                               = 137,
  ROBOTIC_CMD_MISSILECOLOR                              = 138,
  ROBOTIC_CMD_MESSAGE_ROW                               = 139,
  ROBOTIC_CMD_REL_SELF                                  = 140,
  ROBOTIC_CMD_REL_PLAYER                                = 141,
  ROBOTIC_CMD_REL_COUNTERS                              = 142,
  ROBOTIC_CMD_SET_ID_CHAR                               = 143,
  ROBOTIC_CMD_JUMP_MOD_ORDER                            = 144,
  ROBOTIC_CMD_ASK                                       = 145,
  ROBOTIC_CMD_FILLHEALTH                                = 146,
  ROBOTIC_CMD_THICK_ARROW                               = 147,
  ROBOTIC_CMD_THIN_ARROW                                = 148,
  ROBOTIC_CMD_SET_MAX_HEALTH                            = 149,
  ROBOTIC_CMD_SAVE_PLAYER_POSITION                      = 150,
  ROBOTIC_CMD_RESTORE_PLAYER_POSITION                   = 151,
  ROBOTIC_CMD_EXCHANGE_PLAYER_POSITION                  = 152,
  ROBOTIC_CMD_MESSAGE_COLUMN                            = 153,
  ROBOTIC_CMD_CENTER_MESSAGE                            = 154,
  ROBOTIC_CMD_CLEAR_MESSAGE                             = 155,
  ROBOTIC_CMD_RESETVIEW                                 = 156,
  ROBOTIC_CMD_MOD_SAM                                   = 157,
  ROBOTIC_CMD_VOLUME2                                   = 158,
  ROBOTIC_CMD_SCROLLBASE                                = 159,
  ROBOTIC_CMD_SCROLLCORNER                              = 160,
  ROBOTIC_CMD_SCROLLTITLE                               = 161,
  ROBOTIC_CMD_SCROLLPOINTER                             = 162,
  ROBOTIC_CMD_SCROLLARROW                               = 163,
  ROBOTIC_CMD_VIEWPORT                                  = 164,
  ROBOTIC_CMD_VIEWPORT_WIDTH                            = 165,
  ROBOTIC_CMD_UNUSED_166                                = 166,
  ROBOTIC_CMD_UNUSED_167                                = 167,
  ROBOTIC_CMD_SAVE_PLAYER_POSITION_N                    = 168,
  ROBOTIC_CMD_RESTORE_PLAYER_POSITION_N                 = 169,
  ROBOTIC_CMD_EXCHANGE_PLAYER_POSITION_N                = 170,
  ROBOTIC_CMD_RESTORE_PLAYER_POSITION_N_DUPLICATE_SELF  = 171,
  ROBOTIC_CMD_EXCHANGE_PLAYER_POSITION_N_DUPLICATE_SELF = 172,
  ROBOTIC_CMD_PLAYER_BULLETN                            = 173,
  ROBOTIC_CMD_PLAYER_BULLETS                            = 174,
  ROBOTIC_CMD_PLAYER_BULLETE                            = 175,
  ROBOTIC_CMD_PLAYER_BULLETW                            = 176,
  ROBOTIC_CMD_NEUTRAL_BULLETN                           = 177,
  ROBOTIC_CMD_NEUTRAL_BULLETS                           = 178,
  ROBOTIC_CMD_NEUTRAL_BULLETE                           = 179,
  ROBOTIC_CMD_NEUTRAL_BULLETW                           = 180,
  ROBOTIC_CMD_ENEMY_BULLETN                             = 181,
  ROBOTIC_CMD_ENEMY_BULLETS                             = 182,
  ROBOTIC_CMD_ENEMY_BULLETE                             = 183,
  ROBOTIC_CMD_ENEMY_BULLETW                             = 184,
  ROBOTIC_CMD_PLAYER_BULLET_COLOR                       = 185,
  ROBOTIC_CMD_NEUTRAL_BULLET_COLOR                      = 186,
  ROBOTIC_CMD_ENEMY_BULLET_COLOR                        = 187,
  ROBOTIC_CMD_UNUSED_188                                = 188,
  ROBOTIC_CMD_UNUSED_189                                = 189,
  ROBOTIC_CMD_UNUSED_190                                = 190,
  ROBOTIC_CMD_UNUSED_191                                = 191,
  ROBOTIC_CMD_UNUSED_192                                = 192,
  ROBOTIC_CMD_REL_SELF_FIRST                            = 193,
  ROBOTIC_CMD_REL_SELF_LAST                             = 194,
  ROBOTIC_CMD_REL_PLAYER_FIRST                          = 195,
  ROBOTIC_CMD_REL_PLAYER_LAST                           = 196,
  ROBOTIC_CMD_REL_COUNTERS_FIRST                        = 197,
  ROBOTIC_CMD_REL_COUNTERS_LAST                         = 198,
  ROBOTIC_CMD_MOD_FADE_OUT                              = 199,
  ROBOTIC_CMD_MOD_FADE_IN                               = 200,
  ROBOTIC_CMD_COPY_BLOCK                                = 201,
  ROBOTIC_CMD_CLIP_INPUT                                = 202,
  ROBOTIC_CMD_PUSH                                      = 203,
  ROBOTIC_CMD_SCROLL_CHAR                               = 204,
  ROBOTIC_CMD_FLIP_CHAR                                 = 205,
  ROBOTIC_CMD_COPY_CHAR                                 = 206,
  ROBOTIC_CMD_UNUSED_207                                = 207,
  ROBOTIC_CMD_UNUSED_208                                = 208,
  ROBOTIC_CMD_UNUSED_209                                = 209,
  ROBOTIC_CMD_CHANGE_SFX                                = 210,
  ROBOTIC_CMD_COLOR_INTENSITY_ALL                       = 211,
  ROBOTIC_CMD_COLOR_INTENSITY_N                         = 212,
  ROBOTIC_CMD_COLOR_FADE_OUT                            = 213,
  ROBOTIC_CMD_COLOR_FADE_IN                             = 214,
  ROBOTIC_CMD_SET_COLOR                                 = 215,
  ROBOTIC_CMD_LOAD_CHAR_SET                             = 216,
  ROBOTIC_CMD_MULTIPLY                                  = 217,
  ROBOTIC_CMD_DIVIDE                                    = 218,
  ROBOTIC_CMD_MODULO                                    = 219,
  ROBOTIC_CMD_PLAYER_CHAR_DIR                           = 220,
  ROBOTIC_CMD_UNUSED_221                                = 221,
  ROBOTIC_CMD_LOAD_PALETTE                              = 222,
  ROBOTIC_CMD_UNUSED_223                                = 223,
  ROBOTIC_CMD_MOD_FADE_TO                               = 224,
  ROBOTIC_CMD_SCROLLVIEW_XY                             = 225,
  ROBOTIC_CMD_SWAP_WORLD                                = 226,
  ROBOTIC_CMD_IF_ALIGNEDROBOT                           = 227,
  ROBOTIC_CMD_UNUSED_228                                = 228,
  ROBOTIC_CMD_LOCKSCROLL                                = 229,
  ROBOTIC_CMD_UNLOCKSCROLL                              = 230,
  ROBOTIC_CMD_IF_FIRST_INPUT                            = 231,
  ROBOTIC_CMD_PERSISTENT_GO                             = 232,
  ROBOTIC_CMD_WAIT_MOD_FADE                             = 233,
  ROBOTIC_CMD_UNUSED_234                                = 234,
  ROBOTIC_CMD_ENABLE_SAVING                             = 235,
  ROBOTIC_CMD_DISABLE_SAVING                            = 236,
  ROBOTIC_CMD_ENABLE_SENSORONLY_SAVING                  = 237,
  ROBOTIC_CMD_STATUS_COUNTER                            = 238,
  ROBOTIC_CMD_OVERLAY_ON                                = 239,
  ROBOTIC_CMD_OVERLAY_STATIC                            = 240,
  ROBOTIC_CMD_OVERLAY_TRANSPARENT                       = 241,
  ROBOTIC_CMD_OVERLAY_PUT_OVERLAY                       = 242,
  ROBOTIC_CMD_COPY_OVERLAY_BLOCK                        = 243,
  ROBOTIC_CMD_UNUSED_244                                = 244,
  ROBOTIC_CMD_CHANGE_OVERLAY                            = 245,
  ROBOTIC_CMD_CHANGE_OVERLAY_COLOR                      = 246,
  ROBOTIC_CMD_WRITE_OVERLAY                             = 247,
  ROBOTIC_CMD_UNUSED_248                                = 248,
  ROBOTIC_CMD_UNUSED_249                                = 249,
  ROBOTIC_CMD_UNUSED_250                                = 250,
  ROBOTIC_CMD_LOOP_START                                = 251,
  ROBOTIC_CMD_LOOP_FOR                                  = 252,
  ROBOTIC_CMD_ABORT_LOOP                                = 253,
  ROBOTIC_CMD_DISABLE_MESG_EDGE                         = 254,
  ROBOTIC_CMD_ENABLE_MESG_EDGE                          = 255
};

__M_END_DECLS

#endif // __DATA_H


code:
##
# MegaZeux Editor Makefile fragment
##

.PHONY: editor_clean editor_target_clean

editor_src = src/editor
editor_obj = src/editor/.build

editor_flags := ${core_flags}

ifeq (${PLATFORM},mingw)
editor_spec := -DEDITOR_LIBSPEC="__declspec(dllexport)"
endif

ifeq (${PLATFORM},darwin)
editor_ldflags += -framework Cocoa
endif

ifneq (${X11DIR},)
editor_flags   += -I${X11DIR}/../include
editor_ldflags += -L${X11DIR}/../${RAWLIBDIR} -lX11 ${SDL_LDFLAGS}
endif

${editor_obj}/%.o: ${editor_src}/%.c
	$(if ${V},,@echo "  CC      " $<)
	${CC} -MD ${core_cflags} ${editor_flags} ${editor_spec} -c $< -o $@

editor_objs := \
  ${editor_obj}/board.o ${editor_obj}/block.o ${editor_obj}/configure.o  \
  ${editor_obj}/char_ed.o ${editor_obj}/debug.o ${editor_obj}/edit.o     \
  ${editor_obj}/edit_di.o ${editor_obj}/fill.o ${editor_obj}/graphics.o  \
  ${editor_obj}/macro.o ${editor_obj}/pal_ed.o ${editor_obj}/param.o     \
  ${editor_obj}/robo_ed.o ${editor_obj}/robot.o ${editor_obj}/sfx_edit.o \
  ${editor_obj}/window.o ${editor_obj}/world.o

-include ${editor_objs:.o=.d}

${editor_objs}: $(filter-out $(wildcard ${editor_obj}), ${editor_obj})

ifeq (${BUILD_MODULAR},1)

editor_target := ${DSOPRE}editor${DSOPOST}

${editor_target}: ${editor_objs} ${core_target}
	$(if ${V},,@echo "  LINK    " $@)
	${CC} ${DSOLDFLAGS} -o $@ ${editor_objs} ${editor_ldflags} \
	  ${LDFLAGS} ${DSOSONAME}$@ ${DSORPATH} -L. -lcore

editor_target_clean:
	$(if ${V},,@echo "  RM      " ${editor_target} ${editor_target}.debug)
	${RM} ${editor_target} ${editor_target}.debug

else

editor_target := ${editor_objs}

editor_target_clean:

endif

editor_clean: editor_target_clean
	$(if ${V},,@echo "  RM      " ${editor_obj})
	${RM} -r ${editor_obj}


code:
/* MegaZeux
 *
 * Copyright (C) 1996 Greg Janson
 *
 * 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
 */

/* Block functions and dialogs */

#include "block.h"

#include "../helpsys.h"
#include "../idput.h"
#include "../error.h"
#include "../window.h"
#include "../data.h"
#include "../idarray.h"
#include "../world_struct.h"

#include <stdio.h>

//--------------------------
//
// ( ) Copy block
// ( ) Move block
// ( ) Clear block
// ( ) Flip block
// ( ) Mirror block
// ( ) Paint block
// ( ) Copy to/from overlay
// ( ) Save as ANSi
// ( ) Save as MZM
//
//    _OK_      _Cancel_
//
//--------------------------
int block_cmd(struct world *mzx_world)
{
  int dialog_result;
  struct element *elements[3];
  struct dialog di;
  int block_operation = 0;
  const char *radio_button_strings[] =
  {
    "Copy block",
    "Copy block (repeated)",
    "Move block",
    "Clear block",
    "Flip block",
    "Mirror block",
    "Paint block",
    "Copy to/from overlay",
    "Save as MZM"
  };

  set_context(73);
  elements[0] = construct_radio_button(2, 2, radio_button_strings,
   9, 21, &block_operation);
  elements[1] = construct_button(5, 12, "OK", 0);
  elements[2] = construct_button(15, 12, "Cancel", -1);

  construct_dialog(&di, "Choose block command", 26, 3, 29, 15,
   elements, 3, 0);

  dialog_result = run_dialog(mzx_world, &di);
  pop_context();

  destruct_dialog(&di);

  if(dialog_result)
    return -1;

  return block_operation;
}

int rtoo_obj_type(struct world *mzx_world)
{
  int dialog_result;
  struct element *elements[3];
  struct dialog di;
  int object_type = 0;
  const char *radio_button_strings[] =
  {
    "Custom Block",
    "Custom Floor",
    "Text"
  };

  set_context(74);
  elements[0] = construct_radio_button(6, 4, radio_button_strings,
   3, 12, &object_type);
  elements[1] = construct_button(5, 11, "OK", 0);
  elements[2] = construct_button(15, 11, "Cancel", -1);

  construct_dialog(&di, "Object type", 26, 4, 28, 14,
   elements, 3, 0);

  dialog_result = run_dialog(mzx_world, &di);

  destruct_dialog(&di);
  pop_context();

  if(dialog_result)
    return -1;

  return object_type;
}

int choose_char_set(struct world *mzx_world)
{
  int dialog_result;
  struct element *elements[3];
  struct dialog di;
  int charset_type = 0;
  const char *radio_button_strings[] =
  {
    "MegaZeux default",
    "ASCII set",
    "SMZX set",
    "Blank set"
  };

  set_context(75);
  elements[0] = construct_radio_button(4, 4, radio_button_strings,
   4, 16, &charset_type);
  elements[1] = construct_button(5, 11, "OK", 0);
  elements[2] = construct_button(15, 11, "Cancel", -1);

  construct_dialog(&di, "Object type", 26, 4, 28, 14,
   elements, 3, 0);

  dialog_result = run_dialog(mzx_world, &di);

  destruct_dialog(&di);
  pop_context();

  if(dialog_result)
    return -1;

  return charset_type;
}

int export_type(struct world *mzx_world)
{
  int export_choice = 0;
  int dialog_result;
  struct element *elements[3];
  struct dialog di;
  const char *radio_strings[] =
  {
    "Board file (MZB)", "Character set (CHR)",
    "Palette (PAL)", "Sound effects (SFX)"
  };

  set_context(77);

  elements[0] = construct_radio_button(2, 3, radio_strings,
   4, 19, &export_choice);
  elements[1] = construct_button(5, 8, "OK", 0);
  elements[2] = construct_button(15, 8, "Cancel", -1);

  construct_dialog(&di, "Export as:", 26, 5, 28, 11,
   elements, 3, 0);

  dialog_result = run_dialog(mzx_world, &di);
  destruct_dialog(&di);
  pop_context();

  if(dialog_result)
    return -1;

  return export_choice;
}

int import_type(struct world *mzx_world)
{
  int import_choice = 0;
  int dialog_result;
  struct element *elements[3];
  struct dialog di;
  const char *radio_strings[] =
  {
    "Board file (MZB)", "Character set (CHR)",
    "World file (MZX)", "Palette (PAL)",
    "Sound effects (SFX)", "MZM (choose pos.)"
  };

  set_context(77);

  elements[0] = construct_radio_button(2, 3, radio_strings,
   6, 19, &import_choice);
  elements[1] = construct_button(5, 10, "OK", 0);
  elements[2] = construct_button(15, 10, "Cancel", -1);

  construct_dialog(&di, "Import:", 26, 4, 28, 13,
   elements, 3, 0);

  dialog_result = run_dialog(mzx_world, &di);
  destruct_dialog(&di);
  pop_context();

  if(dialog_result)
    return -1;

  return import_choice;
}


code:
/* MegaZeux
 *
 * Copyright (C) 1996 Greg Janson
 *
 * 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
 */

/* Declarations */

#ifndef __EDITOR_BLOCK_H
#define __EDITOR_BLOCK_H

#include "../compat.h"

__M_BEGIN_DECLS

#include "../world_struct.h"

int block_cmd(struct world *mzx_world);
int rtoo_obj_type(struct world *mzx_world);
int choose_char_set(struct world *mzx_world);
int export_type(struct world *mzx_world);
int import_type(struct world *mzx_world);

__M_END_DECLS

#endif  // __EDITOR_BLOCK_H


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
 */

#include "board.h"

#include "../board.h"
#include "../extmem.h"
#include "../world.h"

#include "world.h"

#include <string.h>

static int board_magic(const char magic_string[4])
{
  if(magic_string[0] == 0xFF)
  {
    if(magic_string[1] == 'M')
    {
      // MZX versions >= 2.00 && <= 2.51S1
      if(magic_string[2] == 'B' && magic_string[3] == '2')
        return 0x0200;

      // MZX versions >= 2.51S2 && <= 9.xx
      if((magic_string[2] > 1) && (magic_string[2] < 10))
        return ((int)magic_string[2] << 8) + (int)magic_string[3];
    }
  }

  // Not a recognized board magic
  return 0;
}

static struct board *load_board_allocate_direct(FILE *fp, int version)
{
  struct board *cur_board = cmalloc(sizeof(struct board));
  int board_start, board_end;

  board_start = ftell(fp);
  fseek(fp, 0, SEEK_END);
  board_end = ftell(fp);
  fseek(fp, board_start, SEEK_SET);

  load_board_direct(cur_board, fp, (board_end - board_start), 0, version);
  fread(cur_board->board_name, 25, 1, fp);
  return cur_board;
}

void replace_current_board(struct world *mzx_world, char *name)
{
  int version, current_board_id = mzx_world->current_board_id;
  struct board *src_board = mzx_world->current_board;
  FILE *input_mzb = fopen_unsafe(name, "rb");
  char version_string[4];

  fread(version_string, 4, 1, input_mzb);
  version = board_magic(version_string);

  if(version > 0 && version <= WORLD_VERSION)
  {
    clear_board(src_board);
    src_board = load_board_allocate_direct(input_mzb, version);
    optimize_null_objects(src_board);

    set_update_done_current(mzx_world);

    if(src_board->robot_list)
      src_board->robot_list[0] = &mzx_world->global_robot;

    set_current_board(mzx_world, src_board);
    mzx_world->board_list[current_board_id] = src_board;
  }

  fclose(input_mzb);
}

struct board *create_blank_board(void)
{
  struct board *cur_board = cmalloc(sizeof(struct board));
  int i;

  cur_board->size = 0;
  cur_board->board_name[0] = 0;
  cur_board->board_width = 100;
  cur_board->board_height = 100;
  cur_board->overlay_mode = 1;
  cur_board->level_id = cmalloc(100 * 100);
  cur_board->level_param = cmalloc(100 * 100);
  cur_board->level_color = cmalloc(100 * 100);
  cur_board->level_under_id = cmalloc(100 * 100);
  cur_board->level_under_param = cmalloc(100 * 100);
  cur_board->level_under_color = cmalloc(100 * 100);
  cur_board->overlay = cmalloc(100 * 100);
  cur_board->overlay_color = cmalloc(100 * 100);
  cur_board->mod_playing[0] = 0;
  cur_board->viewport_x = 0;
  cur_board->viewport_y = 0;
  cur_board->viewport_width = 80;
  cur_board->viewport_height = 25;
  cur_board->can_shoot = 1;
  cur_board->can_bomb = 1;
  cur_board->fire_burn_brown = 0;
  cur_board->fire_burn_space = 1;
  cur_board->fire_burn_fakes = 1;
  cur_board->fire_burn_trees = 1;
  cur_board->explosions_leave = EXPL_LEAVE_ASH;
  cur_board->save_mode = CAN_SAVE;
  cur_board->forest_becomes = FOREST_TO_FLOOR;
  cur_board->collect_bombs = 1;
  cur_board->fire_burns = FIRE_BURNS_FOREVER;

  for(i = 0; i < 4; i++)
  {
    cur_board->board_dir[i] = NO_BOARD;
  }

  cur_board->restart_if_zapped = 0;
  cur_board->time_limit = 0;
  cur_board->last_key = '?';
  cur_board->num_input = 0;
  cur_board->input_size = 0;
  cur_board->input_string[0] = 0;
  cur_board->player_last_dir = 0x10;
  cur_board->bottom_mesg[0] = 0;
  cur_board->b_mesg_timer = 0;
  cur_board->lazwall_start = 7;
  cur_board->b_mesg_row = 24;
  cur_board->b_mesg_col = -1;
  cur_board->scroll_x = 0;
  cur_board->scroll_y = 0;
  cur_board->locked_x = -1;
  cur_board->locked_y = -1;
  cur_board->player_ns_locked = 0;
  cur_board->player_ew_locked = 0;
  cur_board->player_attack_locked = 0;
  cur_board->volume = 255;
  cur_board->volume_inc = 0;
  cur_board->volume_target = 255;

  cur_board->num_robots = 0;
  cur_board->num_robots_active = 0;
  cur_board->num_robots_allocated = 0;
  cur_board->robot_list = cmalloc(sizeof(struct robot *));
  cur_board->robot_list_name_sorted = NULL;
  cur_board->num_scrolls = 0;
  cur_board->num_scrolls_allocated = 0;
  cur_board->scroll_list = cmalloc(sizeof(struct scroll *));
  cur_board->num_sensors = 0;
  cur_board->num_sensors_allocated = 0;
  cur_board->sensor_list = cmalloc(sizeof(struct sensor *));

  memset(cur_board->level_id, 0, 100 * 100);
  memset(cur_board->level_color, 7, 100 * 100);
  memset(cur_board->level_param, 0, 100 * 100);
  memset(cur_board->level_under_id, 0, 100 * 100);
  memset(cur_board->level_under_color, 7, 100 * 100);
  memset(cur_board->level_under_param, 0, 100 * 100);
  memset(cur_board->overlay, 32, 100 * 100);
  memset(cur_board->overlay_color, 7, 100 * 100);

  cur_board->level_id[0] = 127;

  return cur_board;
}

void save_board_file(struct board *cur_board, char *name)
{
  FILE *board_file = fopen_unsafe(name, "wb");

  if(board_file)
  {
    fputc(0xff, board_file);

    fputc('M', board_file);
    fputc((WORLD_VERSION >> 8) & 0xff, board_file);
    fputc(WORLD_VERSION & 0xff, board_file);

    optimize_null_objects(cur_board);
    save_board(cur_board, board_file, 0, WORLD_VERSION);
    // Write name
    fwrite(cur_board->board_name, 25, 1, board_file);
    fclose(board_file);
  }
}

void change_board_size(struct board *src_board, int new_width, int new_height)
{
  int board_width = src_board->board_width;
  int board_height = src_board->board_height;

  if(new_width == 0)
    new_width = 1;

  if(new_height == 0)
    new_height = 1;

  if((board_width != new_width) || (board_height != new_height))
  {
    char *level_id = src_board->level_id;
    char *level_color = src_board->level_color;
    char *level_param = src_board->level_param;
    char *level_under_id = src_board->level_under_id;
    char *level_under_color = src_board->level_under_color;
    char *level_under_param = src_board->level_under_param;
    char *overlay = src_board->overlay;
    char *overlay_color = src_board->overlay_color;
    int overlay_mode = src_board->overlay_mode;
    int board_size = board_width * board_height;
    int new_size = new_width * new_height;
    int i;

    // Shrinking height? Remove any robots/scrolls/sensors from excess lines
    if(new_height < board_height)
    {
      int offset;
      int check_id;

      for(offset = new_height * board_width; offset < board_size;
       offset++)
      {
        check_id = level_id[offset];

        if(check_id == 122)
          clear_sensor_id(src_board, level_param[offset]);
        else

        if((check_id == 126) || (check_id == 125))
          clear_scroll_id(src_board, level_param[offset]);
        else

        if((check_id == 123) || (check_id == 124))
          clear_robot_id(src_board, level_param[offset]);
      }
    }

    if(new_width < board_width)
    {
      // Take out pieces from each width, then reallocate.
      // Only do this for the current height or the new height, whichever is
      // less.

      int src_offset, dest_offset;
      int max_height = new_height;
      int check_id, offset;

      if(new_height > board_height)
        max_height = board_height;

      for(i = 0, src_offset = 0, dest_offset = 0; i < max_height;
       i++, src_offset += board_width, dest_offset += new_width)
      {
        // First, remove any robots/scrolls/sensors from excess chunks
        for(offset = src_offset + new_width; offset < src_offset + board_width;
          offset++)
        {
          check_id = level_id[offset];

          if(check_id == 122)
            clear_sensor_id(src_board, level_param[offset]);
          else

          if((check_id == 126) || (check_id == 125))
            clear_scroll_id(src_board, level_param[offset]);
          else

          if((check_id == 123) || (check_id == 124))
            clear_robot_id(src_board, level_param[offset]);
        }

        memmove(level_id + dest_offset, level_id + src_offset, new_width);
        memmove(level_param + dest_offset, level_param + src_offset, new_width);
        memmove(level_color + dest_offset, level_color + src_offset, new_width);
        memmove(level_under_id + dest_offset,
         level_under_id + src_offset, new_width);
        memmove(level_under_param + dest_offset,
         level_under_param + src_offset, new_width);
        memmove(level_under_color + dest_offset,
         level_under_color + src_offset, new_width);
      }

      // Resize layers
      src_board->level_id = crealloc(level_id, new_size);
      src_board->level_color = crealloc(level_color, new_size);
      src_board->level_param = crealloc(level_param, new_size);
      src_board->level_under_id = crealloc(level_under_id, new_size);
      src_board->level_under_color = crealloc(level_under_color, new_size);
      src_board->level_under_param = crealloc(level_under_param, new_size);

      level_id = src_board->level_id;
      level_color = src_board->level_color;
      level_param = src_board->level_param;
      level_under_id = src_board->level_under_id;
      level_under_color = src_board->level_under_color;
      level_under_param = src_board->level_under_param;

      // Do the overlay too, if it exists
      if(overlay_mode)
      {
        for(i = 0, src_offset = 0, dest_offset = 0; i < max_height;
         i++, src_offset += board_width, dest_offset += new_width)
        {
          memmove(overlay + dest_offset, overlay + src_offset, new_width);
          memmove(overlay_color + dest_offset, overlay_color + src_offset, new_width);
        }

        src_board->overlay = crealloc(overlay, new_size);
        src_board->overlay_color = crealloc(overlay_color, new_size);

        overlay = src_board->overlay;
        overlay_color = src_board->overlay_color;
      }
    }
    else

    if(new_width > board_width)
    {
      // Reallocate first, then copy over pieces, padding in widths
      // Only do this for the current height or the new height, whichever is
      // less.
      int src_offset, dest_offset;
      int max_height = new_height;
      int width_difference = new_width - board_width;

      if(new_height > board_height)
        max_height = board_height;

      // Resize first this time.
      src_board->level_id = crealloc(level_id, new_size);
      src_board->level_color = crealloc(level_color, new_size);
      src_board->level_param = crealloc(level_param, new_size);
      src_board->level_under_id = crealloc(level_under_id, new_size);
      src_board->level_under_color = crealloc(level_under_color, new_size);
      src_board->level_under_param = crealloc(level_under_param, new_size);

      // Resize the overlay too, if it exists
      if(overlay_mode)
      {
        src_board->overlay = crealloc(overlay, new_size);
        src_board->overlay_color = crealloc(overlay_color, new_size);
        overlay = src_board->overlay;
        overlay_color = src_board->overlay_color;
      }

      level_id = src_board->level_id;
      level_color = src_board->level_color;
      level_param = src_board->level_param;
      level_under_id = src_board->level_under_id;
      level_under_color = src_board->level_under_color;
      level_under_param = src_board->level_under_param;

      // And start at the end instead of the beginning
      src_offset = board_width * (max_height - 1);
      dest_offset = new_width * (max_height - 1);

      for(i = 0; i < max_height; i++, src_offset -= board_width, dest_offset -= new_width)
      {
        memmove(level_id + dest_offset, level_id + src_offset, board_width);
        memmove(level_param + dest_offset, level_param + src_offset, board_width);
        memmove(level_color + dest_offset, level_color + src_offset, board_width);
        memmove(level_under_id + dest_offset,
         level_under_id + src_offset, board_width);
        memmove(level_under_param + dest_offset,
         level_under_param + src_offset, board_width);
        memmove(level_under_color + dest_offset,
         level_under_color + src_offset, board_width);
        // And fill in the remainder with blanks
        memset(level_id + dest_offset + board_width, 0, width_difference);
        memset(level_param + dest_offset + board_width, 0, width_difference);
        memset(level_color + dest_offset + board_width, 7, width_difference);
        memset(level_under_id + dest_offset + board_width, 0, width_difference);
        memset(level_under_param + dest_offset + board_width, 0, width_difference);
        memset(level_under_color + dest_offset + board_width, 7, width_difference);
      }

      src_offset = board_width * (max_height - 1);
      dest_offset = new_width * (max_height - 1);

      // Do the overlay too, if it exists
      if(overlay_mode)
      {
        for(i = 0; i < max_height; i++, src_offset -= board_width, dest_offset -= new_width)
        {
          memmove(overlay + dest_offset, overlay + src_offset, board_width);
          memmove(overlay_color + dest_offset, overlay_color + src_offset, board_width);
          // And fill in the remainder with blanks
          memset(overlay + dest_offset + board_width, 32, width_difference);
          memset(overlay_color + dest_offset + board_width, 7, width_difference);
        }
      }
    }
    else
    {
      // Width remains the same, just a straight resize

      src_board->level_id = crealloc(level_id, new_size);
      src_board->level_color = crealloc(level_color, new_size);
      src_board->level_param = crealloc(level_param, new_size);
      src_board->level_under_id = crealloc(level_under_id, new_size);
      src_board->level_under_color = crealloc(level_under_color, new_size);
      src_board->level_under_param = crealloc(level_under_param, new_size);

      // Resize the overlay too, if it exists
      if(overlay_mode)
      {
        src_board->overlay = crealloc(overlay, new_size);
        src_board->overlay_color = crealloc(overlay_color, new_size);
      }

      level_id = src_board->level_id;
      level_color = src_board->level_color;
      level_param = src_board->level_param;
      level_under_id = src_board->level_under_id;
      level_under_color = src_board->level_under_color;
      level_under_param = src_board->level_under_param;
      overlay = src_board->overlay;
      overlay_color = src_board->overlay_color;
    }

    // Fill in any blanks
    if(new_height > board_height)
    {
      int offset = new_width * board_height;
      int size_difference = new_size - offset;

      memset(level_id + offset, 0, size_difference);
      memset(level_param + offset, 0, size_difference);
      memset(level_color + offset, 7, size_difference);
      memset(level_under_id + offset, 0, size_difference);
      memset(level_under_param + offset, 0, size_difference);
      memset(level_under_color + offset, 7, size_difference);

      if(overlay_mode)
      {
        memset(overlay + offset, 32, size_difference);
        memset(overlay_color + offset, 7, size_difference);
      }
    }

    // Set the new sizes
    src_board->board_width = new_width;
    src_board->board_height = new_height;
  }
}


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 __EDITOR_BOARD_H
#define __EDITOR_BOARD_H

#include "../compat.h"

__M_BEGIN_DECLS

#include "../board_struct.h"
#include "../world_struct.h"

void replace_current_board(struct world *mzx_world, char *name);
struct board *create_blank_board(void);
void save_board_file(struct board *cur_board, char *name);
void change_board_size(struct board *src_board, int new_width, int new_height);

__M_END_DECLS

#endif // __EDITOR_BOARD_H