Mock-Code in dieses Repo übernommen.
authorWintermute <wintermute@hannover.ccc.de>
Sun, 13 Oct 2013 18:20:04 +0000 (20:20 +0200)
committerWintermute <wintermute@hannover.ccc.de>
Sun, 13 Oct 2013 18:20:04 +0000 (20:20 +0200)
14 files changed:
badge/ui/event.h
mock/Makefile [new file with mode: 0644]
mock/badge_main_loop.c [new file with mode: 0644]
mock/badge_main_loop.h [new file with mode: 0644]
mock/mock-main.cc [new file with mode: 0644]
mock/mock/badge_worker.cc [new file with mode: 0644]
mock/mock/badge_worker.hh [new file with mode: 0644]
mock/mock/display.cc [new file with mode: 0644]
mock/mock/event.cc [new file with mode: 0644]
mock/mock/event.h [new file with mode: 0644]
mock/mock/lcd-display.glade [new file with mode: 0644]
mock/mock/lcd-window.cc [new file with mode: 0644]
mock/mock/lcd-window.hh [new file with mode: 0644]
mock/tools/level-converter.cc [new file with mode: 0644]

index 920df40..24fd501 100644 (file)
@@ -1,5 +1,5 @@
-#ifndef INCLUDED_BADGE2013_MOCKUP_EVENT_H
-#define INCLUDED_BADGE2013_MOCKUP_EVENT_H
+#ifndef INCLUDED_BADGE2013_BADGE_UI_EVENT_H
+#define INCLUDED_BADGE2013_BADGE_UI_EVENT_H
 
 #include <stdint.h>
 
diff --git a/mock/Makefile b/mock/Makefile
new file mode 100644 (file)
index 0000000..5b9f293
--- /dev/null
@@ -0,0 +1,77 @@
+#!/usr/bin/make -f
+
+CPPFLAGS      = $$(pkg-config --cflags gtkmm-3.0) -I. -I ../badge
+CFLAGS        = -Wall -Wextra -pedantic -std=c99   -Werror -O0 -g
+CXXFLAGS      = -Wall -Wextra -pedantic -std=c++11 -Werror -O0 -g
+
+BADGE         = badge
+CONVERTER     = level-converter
+
+GLADEFILES    = lcd-display.glade
+
+VPATH         = ../badge
+
+BADGE_CXXSRCS = mock-main.cc \
+                mock/badge_worker.cc \
+                mock/display.cc \
+                mock/event.cc \
+                mock/lcd-window.cc
+BADGE_CSRCS   = badge_main_loop.c \
+                ui/sprite.c \
+                jumpnrun/collision.c \
+                jumpnrun/enemies.c \
+                jumpnrun/items.c \
+                jumpnrun/jumpnrun.c \
+                jumpnrun/tiles.c \
+                jumpnrun/level_load.c
+
+BADGE_CXXOBJS = $(BADGE_CXXSRCS:%.cc=%.o)
+BADGE_COBJS   = $(BADGE_CSRCS:%.c=%.o)
+BADGE_OBJS    = $(BADGE_CXXOBJS) $(BADGE_COBJS)
+
+CONVERTER_SRCS = tools/level-converter.cc
+CONVERTER_OBJS = $(CONVERTER_SRCS:%.cc=%.o)
+
+CDEPS      = $(BADGE_CSRCS:%.c=%.dep)
+CXXDEPS    = $(BADGE_CXXSRCS:%.cc=%.dep) $(CONVERTER_SRCS:%.cc=%.dep)
+DEPS       = $(CDEPS) $(CXXDEPS)
+
+LDLIBS     = $$(pkg-config --libs gtkmm-3.0)
+RM         = rm -f
+
+.PHONY: all dep clean distclean play
+
+all: dep $(BADGE) $(CONVERTER)
+
+
+$(BADGE_COBJS) : %.o : %.c
+       $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -c -o $(@:../badge/%=%) $< $(LDLIBS)
+
+$(BADGE_CXXOBJS) : %.o : %.cc
+       $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) -c -o $@ $< $(LDLIBS)
+
+$(BADGE): $(BADGE_OBJS)
+       $(CXX) $(CXXFLAGS) $(LDFLAGS) $(LDLIBS) -o $@ $(+:../badge/%=%)
+
+dep: $(DEPS)
+
+$(CDEPS): %.dep : %.c
+       $(CC) $(CPPFLAGS) $(CFLAGS) -MM $< -MT $(<:%.c=%.o) -MF $@
+
+$(CXXDEPS): %.dep : %.cc
+       $(CXX) $(CPPFLAGS) $(CXXFLAGS) -MM $< -MT $(<:%.cc=%.o) -MF $@
+
+sinclude $(DEPS)
+
+clean:
+       $(RM) $(BADGE_OBJS) $(CONVERTER_OBJS) $(BADGE) $(CONVERTER)
+
+distclean: clean
+       $(RM) $(DEPS) $(wildcard *~)
+
+$(CONVERTER): $(CONVERTER_OBJS)
+       $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(LDFLAGS) $(LDLIBS) -o $@ $+
+
+play: all
+       ./$(CONVERTER)
+       ./$(BADGE)
diff --git a/mock/badge_main_loop.c b/mock/badge_main_loop.c
new file mode 100644 (file)
index 0000000..9c7a59d
--- /dev/null
@@ -0,0 +1,29 @@
+#include "badge_main_loop.h"
+
+#include "jumpnrun/jumpnrun.h"
+#include "ui/display.h"
+#include "ui/event.h"
+#include "ui/sprite.h"
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+void badge_main_loop(void) {
+
+  for(;;) {
+    FILE *fd = fopen("jumpnrun/levels.txt", "r");
+    char buf[12];
+
+    while(fgets(buf, sizeof(buf), fd)) {
+      buf[strlen(buf) - 1] = '\0';
+      char lvname[30];
+      sprintf(lvname, "jumpnrun/%s.lvl", buf);
+      while(jumpnrun_play(lvname) != JUMPNRUN_WON)
+        ;
+    }
+
+    fclose(fd);
+  }
+}
diff --git a/mock/badge_main_loop.h b/mock/badge_main_loop.h
new file mode 100644 (file)
index 0000000..cad43f8
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef INCLUDED_BADGE_MAIN_LOOP_H
+#define INCLUDED_BADGE_MAIN_LOOP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+  void badge_main_loop(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/mock/mock-main.cc b/mock/mock-main.cc
new file mode 100644 (file)
index 0000000..1bbd827
--- /dev/null
@@ -0,0 +1,23 @@
+#include "mock/lcd-window.hh"
+
+#include <glibmm/thread.h>
+#include <gtkmm/main.h>
+
+#include <memory>
+
+int main(int argc, char *argv[]) {
+  Glib::thread_init();
+
+  Gtk::Main kit(argc, argv);
+  Glib::RefPtr<Gtk::Builder> glade = Gtk::Builder::create();
+  badge2013::lcd_window *win_naked = nullptr;
+
+  glade->add_from_file("mock/lcd-display.glade");
+  glade->get_widget_derived("mainwindow", win_naked);
+
+  std::unique_ptr<badge2013::lcd_window> win(win_naked);
+
+  if(win) {
+    kit.run(*win);
+  }
+}
diff --git a/mock/mock/badge_worker.cc b/mock/mock/badge_worker.cc
new file mode 100644 (file)
index 0000000..75d2bca
--- /dev/null
@@ -0,0 +1,15 @@
+#include "badge_worker.hh"
+#include "badge_main_loop.h"
+#include "lcd-window.hh"
+
+namespace badge2013 {
+  void badge_framebuffer_set_backend(lcd_window *win);
+
+  badge_worker::badge_worker(lcd_window *win) : win_(win) { }
+
+  void badge_worker::run() {
+    badge_framebuffer_set_backend(win_);
+    badge_main_loop();
+    win_->request_close();
+  }
+}
diff --git a/mock/mock/badge_worker.hh b/mock/mock/badge_worker.hh
new file mode 100644 (file)
index 0000000..df871e7
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef INCLUDED_BADGE2013_MOCKUP_BADGE_WORKER_HH
+#define INCLUDED_BADGE2013_MOCKUP_BADGE_WORKER_HH
+
+namespace badge2013 {
+  class lcd_window;
+
+  class badge_worker {
+  public:
+    badge_worker(lcd_window *win);
+
+    void run();
+
+  private:
+    lcd_window *win_;
+  };
+}
+
+#endif
diff --git a/mock/mock/display.cc b/mock/mock/display.cc
new file mode 100644 (file)
index 0000000..a9b5479
--- /dev/null
@@ -0,0 +1,16 @@
+#include <ui/display.h>
+#include "lcd-window.hh"
+
+namespace badge2013 {
+  namespace {
+    lcd_window *window;
+  }
+
+  void badge_framebuffer_set_backend(lcd_window *win) {
+    window = win;
+  }
+}
+
+void badge_framebuffer_flush(badge_framebuffer const *fb) {
+  badge2013::window->push_framebuffer(*fb);
+}
diff --git a/mock/mock/event.cc b/mock/mock/event.cc
new file mode 100644 (file)
index 0000000..076867c
--- /dev/null
@@ -0,0 +1,41 @@
+#include "event.h"
+
+#include <glibmm/threads.h>
+#include <queue>
+
+namespace {
+  Glib::Threads::Mutex      badge_event_mutex;
+  Glib::Threads::Cond       badge_event_condition;
+  std::queue<badge_event_t> badge_event_queue;
+  uint8_t          volatile badge_event_input_state = 0;
+}
+
+uint8_t badge_event_current_input_state(void) {
+  Glib::Threads::Mutex::Lock lock(badge_event_mutex);
+  return badge_event_input_state;
+}
+
+void          badge_event_push(badge_event_t e) {
+  Glib::Threads::Mutex::Lock lock(badge_event_mutex);
+
+  badge_event_queue.push(e);
+
+  if(badge_event_type(e) == BADGE_EVENT_USER_INPUT) {
+    badge_event_input_state = badge_event_new_input_state(e);
+  }
+
+  badge_event_condition.signal();
+}
+
+badge_event_t badge_event_wait(void) {
+  Glib::Threads::Mutex::Lock lock(badge_event_mutex);
+
+  while(badge_event_queue.empty()) {
+    badge_event_condition.wait(badge_event_mutex);
+  }
+
+  badge_event_t result = badge_event_queue.front();
+  badge_event_queue.pop();
+
+  return result;
+}
diff --git a/mock/mock/event.h b/mock/mock/event.h
new file mode 100644 (file)
index 0000000..8818842
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef INCLUDED_BADGE2013_MOCKUP_EVENT_H
+#define INCLUDED_BADGE2013_MOCKUP_EVENT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <ui/event.h>
+
+  void          badge_event_push(badge_event_t);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/mock/mock/lcd-display.glade b/mock/mock/lcd-display.glade
new file mode 100644 (file)
index 0000000..1864b0a
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <!-- interface-requires gtk+ 3.0 -->
+  <object class="GtkWindow" id="mainwindow">
+    <property name="can_focus">False</property>
+    <property name="title" translatable="yes">LCD</property>
+    <property name="default_width">144</property>
+    <property name="default_height">98</property>
+    <property name="has_resize_grip">False</property>
+    <child>
+      <object class="GtkDrawingArea" id="canvas">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+      </object>
+    </child>
+  </object>
+</interface>
diff --git a/mock/mock/lcd-window.cc b/mock/mock/lcd-window.cc
new file mode 100644 (file)
index 0000000..8b1de24
--- /dev/null
@@ -0,0 +1,131 @@
+#include "lcd-window.hh"
+#include "badge_worker.hh"
+#include "mock/event.h"
+
+#include <gtkmm/main.h>
+
+namespace badge2013 {
+  lcd_drawingarea::lcd_drawingarea(BaseObjectType *cobject,
+                                  Glib::RefPtr<Gtk::Builder> const &)
+    : Gtk::DrawingArea(cobject)
+  {
+    sig_redraw_.connect(sigc::mem_fun(*this, &lcd_drawingarea::force_redraw));
+    badge_framebuffer_clear(&framebuffer_);
+  }
+
+  lcd_drawingarea::~lcd_drawingarea() { }
+
+  void lcd_drawingarea::push_framebuffer(badge_framebuffer const &fb) {
+    framebuffer_ = fb;
+    sig_redraw_();
+  }
+
+  void lcd_drawingarea::force_redraw() {
+    Glib::RefPtr<Gdk::Window> win = get_window();
+    if(win) {
+      win->invalidate(true);
+    }
+  }
+
+  bool lcd_drawingarea::on_draw(Cairo::RefPtr<Cairo::Context> const &cr) {
+    Gtk::Allocation alloc = get_allocation();
+    double w_width  = alloc.get_width ();
+    double w_height = alloc.get_height();
+
+    double c_width  = w_width  / BADGE_DISPLAY_WIDTH;
+    double c_height = w_height / BADGE_DISPLAY_HEIGHT;
+
+    cr->save();
+  
+    for(int i = 0; i < BADGE_DISPLAY_WIDTH; ++i) {
+      for(int j = 0; j < BADGE_DISPLAY_HEIGHT; ++j) {
+       if(badge_framebuffer_pixel(&framebuffer_, i, j)) {
+         cr->rectangle(c_width * i, c_height * j,
+                       c_width    , c_height);
+       }
+      }
+    }
+
+    cr->fill();
+    cr->restore();
+
+    return true;
+  }
+
+  ///////////////////////////////////////////////////////
+  ///////////////////////////////////////////////////////
+  ///////////////////////////////////////////////////////
+
+  lcd_window::lcd_window(BaseObjectType *cobject, Glib::RefPtr<Gtk::Builder> const &glade)
+    : Gtk::Window(cobject),
+      worker_(this)
+  {
+    glade->get_widget_derived("canvas", canvas_);
+
+    Glib::signal_timeout().connect(sigc::mem_fun(*this, &lcd_window::on_game_tick ), 11);
+    sig_close_.connect(sigc::mem_fun(*this, &lcd_window::hide));
+  }
+
+  lcd_window::~lcd_window() { }
+
+  void lcd_window::push_framebuffer(badge_framebuffer const &fb) {
+    canvas_->push_framebuffer(fb);
+  }
+
+  void lcd_window::request_close() {
+    sig_close_();
+  }
+
+  bool lcd_window::on_key_press_event  (GdkEventKey* event) {
+    uint8_t new_state = key_state_;
+
+    switch(event->keyval) {
+    case GDK_KEY_e: new_state |= BADGE_EVENT_KEY_UP;     break;
+    case GDK_KEY_s: new_state |= BADGE_EVENT_KEY_LEFT;   break;
+    case GDK_KEY_d: new_state |= BADGE_EVENT_KEY_DOWN;   break;
+    case GDK_KEY_f: new_state |= BADGE_EVENT_KEY_RIGHT;  break;
+    case GDK_KEY_a: new_state |= BADGE_EVENT_KEY_CENTER; break;
+    case GDK_KEY_j: new_state |= BADGE_EVENT_KEY_BTN_A;  break;
+    case GDK_KEY_k: new_state |= BADGE_EVENT_KEY_BTN_B;  break;
+    }
+
+    badge_event_push(badge_event_new(BADGE_EVENT_USER_INPUT, key_state_, new_state));
+    key_state_ = new_state;
+
+    return true;
+  }
+
+  bool lcd_window::on_key_release_event(GdkEventKey* event) {
+    uint8_t new_state = key_state_;
+
+    switch(event->keyval) {
+    case GDK_KEY_e: new_state &= ~BADGE_EVENT_KEY_UP;     break;
+    case GDK_KEY_s: new_state &= ~BADGE_EVENT_KEY_LEFT;   break;
+    case GDK_KEY_d: new_state &= ~BADGE_EVENT_KEY_DOWN;   break;
+    case GDK_KEY_f: new_state &= ~BADGE_EVENT_KEY_RIGHT;  break;
+    case GDK_KEY_a: new_state &= ~BADGE_EVENT_KEY_CENTER; break;
+    case GDK_KEY_j: new_state &= ~BADGE_EVENT_KEY_BTN_A;  break;
+    case GDK_KEY_k: new_state &= ~BADGE_EVENT_KEY_BTN_B;  break;
+    }
+
+    badge_event_push(badge_event_new(BADGE_EVENT_USER_INPUT, key_state_, new_state));
+    key_state_ = new_state;
+
+    return true;  
+  }
+
+  bool lcd_window::on_game_tick() {
+    badge_event_push(badge_event_new(BADGE_EVENT_GAME_TICK, key_state_, key_state_));
+
+    return true;
+  }
+
+  void lcd_window::on_show() {
+    Gtk::Window::on_show();
+
+    if(!running_) {
+      running_ = true;
+      Glib::Thread::create(sigc::mem_fun(worker_, &badge_worker::run));
+    }
+  }
+}
diff --git a/mock/mock/lcd-window.hh b/mock/mock/lcd-window.hh
new file mode 100644 (file)
index 0000000..dc31b99
--- /dev/null
@@ -0,0 +1,63 @@
+#ifndef INCLUDED_BADGE2013_MOCKUP_LCD_WINDOW_HH
+#define INCLUDED_BADGE2013_MOCKUP_LCD_WINDOW_HH
+
+#include "badge_worker.hh"
+#include <ui/display.h>
+
+#include <glibmm/dispatcher.h>
+#include <glibmm/thread.h>
+
+#include <gtkmm/builder.h>
+#include <gtkmm/dialog.h>
+#include <gtkmm/drawingarea.h>
+#include <gtkmm/window.h>
+
+#include <cstdint>
+#include <memory>
+
+namespace badge2013 {
+  class lcd_drawingarea : public Gtk::DrawingArea {
+  public:
+    lcd_drawingarea(BaseObjectType *cobject,
+                   Glib::RefPtr<Gtk::Builder> const &glade);
+    virtual ~lcd_drawingarea();
+
+    void push_framebuffer(badge_framebuffer const &fb);
+
+  protected:
+    virtual bool on_draw(Cairo::RefPtr<Cairo::Context> const &cr);
+
+  private:
+    void force_redraw();
+
+    Glib::Dispatcher  sig_redraw_;
+    badge_framebuffer framebuffer_;  
+  };
+
+
+  class lcd_window : public Gtk::Window {
+  public:
+    lcd_window(BaseObjectType *cobject, Glib::RefPtr<Gtk::Builder> const &glade);
+    virtual ~lcd_window();
+
+    void push_framebuffer(badge_framebuffer const &fb);
+    void request_close();
+
+  protected:
+    virtual void on_show();
+    virtual bool on_key_press_event  (GdkEventKey* event);
+    virtual bool on_key_release_event(GdkEventKey* event);
+
+  private:
+    bool on_game_tick();
+
+    bool             running_ = false;
+    Glib::Dispatcher sig_close_;
+    badge_worker     worker_;
+    lcd_drawingarea *canvas_    = 0;
+    std::uint8_t     key_state_ = 0;
+    std::uint8_t     ticks_ = 0;
+  };
+}
+
+#endif
diff --git a/mock/tools/level-converter.cc b/mock/tools/level-converter.cc
new file mode 100644 (file)
index 0000000..d99928c
--- /dev/null
@@ -0,0 +1,254 @@
+extern "C" {
+#include <jumpnrun/levels.h>
+#include <jumpnrun/items.h>
+#include <jumpnrun/tiles.h>
+#include <jumpnrun/enemies.h>
+}
+
+#include <boost/spirit/include/qi_symbols.hpp>
+
+#include <algorithm>
+#include <fstream>
+#include <iostream>
+#include <map>
+#include <numeric>
+#include <sstream>
+#include <stdexcept>
+#include <string>
+#include <vector>
+
+enum {
+  LEVEL_LINE_COUNT = 13
+};
+
+namespace jnrcpp {
+  struct descriptors {
+    descriptors() {
+      tiles.add
+        ("tube_top_left" , JUMPNRUN_TILE_TYPE_TUBE_TOP_LEFT )
+        ("tube_top_right", JUMPNRUN_TILE_TYPE_TUBE_TOP_RIGHT)
+        ("tube_left"     , JUMPNRUN_TILE_TYPE_TUBE_LEFT     )
+        ("tube_right"    , JUMPNRUN_TILE_TYPE_TUBE_RIGHT    )
+        ("brick"         , JUMPNRUN_TILE_TYPE_BRICK         )
+        ("square"        , JUMPNRUN_TILE_TYPE_SQUARE        )
+        ;
+
+      items.add
+        ("doc", JUMPNRUN_ITEM_TYPE_DOCUMENT)
+        ;
+
+      enemies.add
+        ("cat"      , JUMPNRUN_ENEMY_TYPE_CAT      )
+        ("mushroom" , JUMPNRUN_ENEMY_TYPE_MUSHROOM )
+       ("kaninchen", JUMPNRUN_ENEMY_TYPE_KANINCHEN)
+        ;
+    }
+
+    boost::spirit::qi::symbols<char, unsigned> tiles;
+    boost::spirit::qi::symbols<char, unsigned> items;
+    boost::spirit::qi::symbols<char, unsigned> enemies;
+  } const desc;
+
+  struct level_name_map {
+    level_name_map() {
+      std::ifstream in("jumpnrun/levels.txt");
+
+      if(!in) {
+        throw std::logic_error("jumpnrun/levels.txt konnte nicht geöffnet werden.");
+      }
+
+      std::string name;
+      while(std::getline(in, name)) {
+        if(name != "") {
+          names.push_back(name);
+        }
+      }
+    }
+
+    std::vector<std::string> names;
+  } const level_names;
+
+  class level {
+  public:
+    level(std::string const &name)
+      : name(name),
+        level_lines(LEVEL_LINE_COUNT)
+    {
+      std::ifstream in(("jumpnrun/" + name + ".lv").c_str());
+
+      if(!in) {
+        throw std::invalid_argument("Could not open file: " + name + ".lv");
+      }
+
+      for(std::size_t i = 0; i < level_lines.size(); ++i) {
+        std::getline(in, level_lines[i]);
+      }
+
+      std::string line;
+      std::string type_prefix;
+      std::map<char, std::string> *objmap = 0;
+
+      while(std::getline(in, line)) {
+        if(line[0] == '[') {
+          if(line == "[tiles]") {
+            objmap = &tile_types;
+          } else if(line == "[items]") {
+            objmap = &item_types;
+          } else if(line == "[enemies]") {
+            objmap = &enemy_types;
+          } else {
+            throw std::invalid_argument("Unkown type: " + line);
+          }
+        } else if(line != "") {
+          char c;
+          std::string tok;
+          std::istringstream parser(line);
+
+          if(parser >> c >> tok) {
+            if(objmap) {
+              (*objmap)[c] = tok;
+            }
+          } else {
+            throw std::invalid_argument("Line not parseable: " + line);
+          }
+        }
+      }
+    }
+
+    std::size_t length() const {
+      std::size_t level_length = 0;
+
+      for(std::size_t i = 0; i < level_lines.size(); ++i) {
+        level_length = std::max(level_length, level_lines[i].size());
+      }
+
+      return level_length;
+    }
+
+    unsigned find_type(boost::spirit::qi::symbols<char, unsigned> const &types, std::string const &type, std::string const &error) const {
+      unsigned const *p = types.find(type);
+      if(!p) throw std::invalid_argument(error + type);
+      return *p;
+    }
+
+    std::size_t count_things(std::map<char, std::string> const &objmap) const {
+      std::size_t len = length();
+      std::size_t i = 0;
+
+      for(std::size_t x = 0; x < len; ++x) {
+        for(std::size_t y = 0; y < level_lines.size(); ++y) {
+          if(x < level_lines[y].size()) {
+            auto iter = objmap.find(level_lines[y][x]);
+
+            if(iter != objmap.end()) {
+              ++i;
+            }
+          }
+        }
+      }
+
+      return i;
+    }
+
+    std::size_t count_tiles  () const { return count_things(tile_types ); }
+    std::size_t count_items  () const { return count_things(item_types ); }
+    std::size_t count_enemies() const { return count_things(enemy_types); }
+
+    void dump_things(std::ostream &dest, std::map<char, std::string> const &objmap, boost::spirit::qi::symbols<char, unsigned> const &types, std::string const &error) const {
+      std::size_t len = length();
+
+      for(std::size_t x = 0; x < len; ++x) {
+        for(std::size_t y = 0; y < level_lines.size(); ++y) {
+          if(level_lines[y].size() < x) continue;
+
+          auto iter = objmap.find(level_lines[y][x]);
+
+          if(iter != objmap.end()) {
+            unsigned char buf[3];
+            buf[0] = static_cast<uint8_t>(y) << 4 | static_cast<uint8_t>(x >> 8);
+            buf[1] = static_cast<uint8_t>(x);
+            buf[2] = static_cast<uint8_t>(find_type(types, iter->second, error));
+
+            dest.write(static_cast<char const*>(static_cast<void*>(&buf[0])), sizeof(buf));
+          }
+        }
+      }
+    }
+
+    void dump_tiles  (std::ostream &dest) const { dump_things(dest,  tile_types, desc.tiles  , "Unbekannter Tile-Typ: "); }
+    void dump_items  (std::ostream &dest) const { dump_things(dest,  item_types, desc.items  , "Unbekannter Item-Typ: "); }
+    void dump_enemies(std::ostream &dest) const { dump_things(dest, enemy_types, desc.enemies, "Unbekannter Enemy-Typ: "); }
+
+    std::pair<std::size_t, std::size_t> starting_position() const {
+      std::pair<std::size_t, std::size_t> player_pos(0, 0);
+
+      for(std::size_t y = 0; y < level_lines.size(); ++y) {
+        std::size_t x = level_lines[y].find('P');
+
+        if(x != std::string::npos) {
+          player_pos.first = x;
+          player_pos.second = y;
+          break;
+        }
+      }
+
+      return player_pos;
+    }
+
+    void generate_header(jumpnrun_level *dest) const {
+      dest->header.tile_count  = count_tiles  ();
+      dest->header.item_count  = count_items  ();
+      dest->header.enemy_count = count_enemies();
+    }
+
+    void dump(std::ostream &dest) const {
+      jumpnrun_level dummy;
+
+      generate_header(&dummy);
+      uint16_t head[3] = {
+        static_cast<uint16_t>(dummy.header. tile_count),
+        static_cast<uint16_t>(dummy.header. item_count),
+        static_cast<uint16_t>(dummy.header.enemy_count)
+      };
+
+      std::pair<std::size_t, std::size_t> player_pos = starting_position();
+
+      uint16_t spos[2] = {
+        static_cast<uint16_t>(player_pos.first),
+        static_cast<uint16_t>(player_pos.second)
+      };
+
+      dest.write(static_cast<char const *>(static_cast<void const *>(head)), sizeof(head));
+      dest.write(static_cast<char const *>(static_cast<void const *>(spos)), sizeof(spos));
+
+      dump_tiles(dest);
+      dump_items(dest);
+      dump_enemies(dest);
+    }
+
+  private:
+    std::string name;
+    std::vector<std::string> level_lines;
+    std::map<char, std::string> tile_types;
+    std::map<char, std::string> item_types;
+    std::map<char, std::string> enemy_types;
+  };
+}
+
+void jumpnrun_level_dump(size_t level) {
+  std::string name = jnrcpp::level_names.names[level];
+  jnrcpp::level lv(name);
+  std::ofstream out(("jumpnrun/" + name + ".lvl").c_str());
+
+  lv.dump(out);
+}
+
+void jumpnrun_levels_dump(void) {
+  for(size_t i = 0; i < jnrcpp::level_names.names.size(); ++i) {
+    jumpnrun_level_dump(i);
+  }
+}
+
+int main() {
+  jumpnrun_levels_dump();
+}
This page took 0.044944 seconds and 4 git commands to generate.